@bugspotter/sdk 0.1.0-alpha.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.
Files changed (67) hide show
  1. package/CHANGELOG.md +69 -0
  2. package/LICENSE +21 -0
  3. package/README.md +639 -0
  4. package/dist/bugspotter.min.js +2 -0
  5. package/dist/bugspotter.min.js.LICENSE.txt +14 -0
  6. package/dist/capture/base-capture.d.ts +34 -0
  7. package/dist/capture/base-capture.js +23 -0
  8. package/dist/capture/capture-lifecycle.d.ts +24 -0
  9. package/dist/capture/capture-lifecycle.js +2 -0
  10. package/dist/capture/console.d.ts +29 -0
  11. package/dist/capture/console.js +107 -0
  12. package/dist/capture/metadata.d.ts +21 -0
  13. package/dist/capture/metadata.js +76 -0
  14. package/dist/capture/network.d.ts +32 -0
  15. package/dist/capture/network.js +135 -0
  16. package/dist/capture/screenshot.d.ts +19 -0
  17. package/dist/capture/screenshot.js +52 -0
  18. package/dist/collectors/dom.d.ts +67 -0
  19. package/dist/collectors/dom.js +164 -0
  20. package/dist/collectors/index.d.ts +2 -0
  21. package/dist/collectors/index.js +5 -0
  22. package/dist/core/buffer.d.ts +50 -0
  23. package/dist/core/buffer.js +88 -0
  24. package/dist/core/circular-buffer.d.ts +42 -0
  25. package/dist/core/circular-buffer.js +77 -0
  26. package/dist/core/compress.d.ts +49 -0
  27. package/dist/core/compress.js +245 -0
  28. package/dist/core/offline-queue.d.ts +76 -0
  29. package/dist/core/offline-queue.js +301 -0
  30. package/dist/core/transport.d.ts +73 -0
  31. package/dist/core/transport.js +352 -0
  32. package/dist/core/upload-helpers.d.ts +32 -0
  33. package/dist/core/upload-helpers.js +79 -0
  34. package/dist/core/uploader.d.ts +70 -0
  35. package/dist/core/uploader.js +185 -0
  36. package/dist/index.d.ts +140 -0
  37. package/dist/index.esm.js +205 -0
  38. package/dist/index.js +244 -0
  39. package/dist/utils/logger.d.ts +28 -0
  40. package/dist/utils/logger.js +84 -0
  41. package/dist/utils/sanitize-patterns.d.ts +103 -0
  42. package/dist/utils/sanitize-patterns.js +282 -0
  43. package/dist/utils/sanitize.d.ts +73 -0
  44. package/dist/utils/sanitize.js +254 -0
  45. package/dist/widget/button.d.ts +33 -0
  46. package/dist/widget/button.js +143 -0
  47. package/dist/widget/components/dom-element-cache.d.ts +62 -0
  48. package/dist/widget/components/dom-element-cache.js +105 -0
  49. package/dist/widget/components/form-validator.d.ts +66 -0
  50. package/dist/widget/components/form-validator.js +115 -0
  51. package/dist/widget/components/pii-detection-display.d.ts +64 -0
  52. package/dist/widget/components/pii-detection-display.js +142 -0
  53. package/dist/widget/components/redaction-canvas.d.ts +95 -0
  54. package/dist/widget/components/redaction-canvas.js +230 -0
  55. package/dist/widget/components/screenshot-processor.d.ts +44 -0
  56. package/dist/widget/components/screenshot-processor.js +191 -0
  57. package/dist/widget/components/style-manager.d.ts +37 -0
  58. package/dist/widget/components/style-manager.js +296 -0
  59. package/dist/widget/components/template-manager.d.ts +66 -0
  60. package/dist/widget/components/template-manager.js +198 -0
  61. package/dist/widget/modal.d.ts +62 -0
  62. package/dist/widget/modal.js +299 -0
  63. package/docs/CDN.md +213 -0
  64. package/docs/FRAMEWORK_INTEGRATION.md +1104 -0
  65. package/docs/PUBLISHING.md +550 -0
  66. package/docs/SESSION_REPLAY.md +381 -0
  67. package/package.json +90 -0
@@ -0,0 +1,296 @@
1
+ "use strict";
2
+ /**
3
+ * StyleManager
4
+ *
5
+ * Responsibility: Generate and manage CSS styles for the bug report modal
6
+ * Follows SRP: Only handles style generation and theming
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.StyleManager = void 0;
10
+ class StyleManager {
11
+ constructor(config = {}) {
12
+ this.config = {
13
+ primaryColor: config.primaryColor || '#007bff',
14
+ dangerColor: config.dangerColor || '#dc3545',
15
+ borderRadius: config.borderRadius || '4px',
16
+ fontFamily: config.fontFamily || '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
17
+ zIndex: config.zIndex || 999999,
18
+ };
19
+ }
20
+ /**
21
+ * Generate complete CSS stylesheet for the modal
22
+ */
23
+ generateStyles() {
24
+ return `
25
+ .overlay {
26
+ position: fixed;
27
+ top: 0;
28
+ left: 0;
29
+ width: 100%;
30
+ height: 100%;
31
+ background: rgba(0, 0, 0, 0.5);
32
+ display: flex;
33
+ align-items: center;
34
+ justify-content: center;
35
+ z-index: ${this.config.zIndex};
36
+ font-family: ${this.config.fontFamily};
37
+ }
38
+
39
+ .modal {
40
+ background: white;
41
+ border-radius: 8px;
42
+ width: 90%;
43
+ max-width: 600px;
44
+ max-height: 90vh;
45
+ overflow-y: auto;
46
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
47
+ }
48
+
49
+ .header {
50
+ padding: 20px;
51
+ border-bottom: 1px solid #e0e0e0;
52
+ display: flex;
53
+ justify-content: space-between;
54
+ align-items: center;
55
+ }
56
+
57
+ .header h2 {
58
+ margin: 0;
59
+ font-size: 20px;
60
+ font-weight: 600;
61
+ }
62
+
63
+ .close {
64
+ background: none;
65
+ border: none;
66
+ font-size: 24px;
67
+ cursor: pointer;
68
+ color: #666;
69
+ padding: 0;
70
+ width: 30px;
71
+ height: 30px;
72
+ display: flex;
73
+ align-items: center;
74
+ justify-content: center;
75
+ border-radius: ${this.config.borderRadius};
76
+ }
77
+
78
+ .close:hover {
79
+ background: #f0f0f0;
80
+ }
81
+
82
+ .body {
83
+ padding: 20px;
84
+ }
85
+
86
+ .form-group {
87
+ margin-bottom: 20px;
88
+ }
89
+
90
+ .label {
91
+ display: block;
92
+ margin-bottom: 8px;
93
+ font-weight: 500;
94
+ font-size: 14px;
95
+ }
96
+
97
+ .input,
98
+ .textarea {
99
+ width: 100%;
100
+ padding: 10px;
101
+ border: 1px solid #ddd;
102
+ border-radius: ${this.config.borderRadius};
103
+ font-size: 14px;
104
+ font-family: ${this.config.fontFamily};
105
+ box-sizing: border-box;
106
+ }
107
+
108
+ .input:focus,
109
+ .textarea:focus {
110
+ outline: none;
111
+ border-color: ${this.config.primaryColor};
112
+ }
113
+
114
+ .textarea {
115
+ min-height: 100px;
116
+ resize: vertical;
117
+ }
118
+
119
+ .screenshot-container {
120
+ margin-top: 10px;
121
+ position: relative;
122
+ }
123
+
124
+ .screenshot {
125
+ max-width: 100%;
126
+ border: 1px solid #ddd;
127
+ border-radius: ${this.config.borderRadius};
128
+ }
129
+
130
+ .redaction-canvas {
131
+ position: absolute;
132
+ top: 0;
133
+ left: 0;
134
+ cursor: crosshair;
135
+ border: 2px solid ${this.config.primaryColor};
136
+ border-radius: ${this.config.borderRadius};
137
+ }
138
+
139
+ .redaction-controls {
140
+ margin-top: 10px;
141
+ display: flex;
142
+ gap: 10px;
143
+ }
144
+
145
+ .btn-redact,
146
+ .btn-clear {
147
+ padding: 8px 16px;
148
+ border: 1px solid #ddd;
149
+ border-radius: ${this.config.borderRadius};
150
+ background: white;
151
+ cursor: pointer;
152
+ font-size: 14px;
153
+ }
154
+
155
+ .btn-redact:hover,
156
+ .btn-clear:hover {
157
+ background: #f5f5f5;
158
+ }
159
+
160
+ .btn-redact.active {
161
+ background: ${this.config.primaryColor};
162
+ color: white;
163
+ border-color: ${this.config.primaryColor};
164
+ }
165
+
166
+ .pii-section {
167
+ margin-top: 20px;
168
+ padding: 15px;
169
+ background: #fff3cd;
170
+ border: 1px solid #ffc107;
171
+ border-radius: ${this.config.borderRadius};
172
+ }
173
+
174
+ .pii-title {
175
+ margin: 0 0 10px 0;
176
+ font-size: 14px;
177
+ font-weight: 600;
178
+ color: #856404;
179
+ }
180
+
181
+ .pii-list {
182
+ margin: 0;
183
+ padding-left: 20px;
184
+ font-size: 13px;
185
+ color: #856404;
186
+ }
187
+
188
+ .pii-badge {
189
+ display: inline-block;
190
+ padding: 2px 8px;
191
+ margin: 2px;
192
+ background: #ffc107;
193
+ color: #856404;
194
+ border-radius: 12px;
195
+ font-size: 12px;
196
+ font-weight: 500;
197
+ }
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
+
250
+ .btn-secondary {
251
+ background: #6c757d;
252
+ color: white;
253
+ }
254
+
255
+ .btn-secondary:hover {
256
+ opacity: 0.9;
257
+ }
258
+
259
+ .error {
260
+ color: ${this.config.dangerColor};
261
+ font-size: 12px;
262
+ margin-top: 4px;
263
+ }
264
+ `;
265
+ }
266
+ /**
267
+ * Inject styles into document head
268
+ */
269
+ injectStyles() {
270
+ const styleElement = document.createElement('style');
271
+ styleElement.textContent = this.generateStyles();
272
+ document.head.appendChild(styleElement);
273
+ return styleElement;
274
+ }
275
+ /**
276
+ * Remove injected styles
277
+ */
278
+ removeStyles(styleElement) {
279
+ if (styleElement && styleElement.parentNode) {
280
+ styleElement.parentNode.removeChild(styleElement);
281
+ }
282
+ }
283
+ /**
284
+ * Update configuration and regenerate styles
285
+ */
286
+ updateConfig(config) {
287
+ this.config = Object.assign(Object.assign({}, this.config), config);
288
+ }
289
+ /**
290
+ * Get current configuration
291
+ */
292
+ getConfig() {
293
+ return Object.assign({}, this.config);
294
+ }
295
+ }
296
+ exports.StyleManager = StyleManager;
@@ -0,0 +1,66 @@
1
+ /**
2
+ * TemplateManager
3
+ *
4
+ * Responsibility: Generate HTML templates for modal components
5
+ * Follows SRP: Only handles HTML structure generation
6
+ */
7
+ export interface TemplateConfig {
8
+ title?: string;
9
+ titlePlaceholder?: string;
10
+ descriptionPlaceholder?: string;
11
+ submitButtonText?: string;
12
+ cancelButtonText?: string;
13
+ showScreenshot?: boolean;
14
+ }
15
+ export declare class TemplateManager {
16
+ private config;
17
+ constructor(config?: TemplateConfig);
18
+ /**
19
+ * Generate complete modal HTML structure
20
+ */
21
+ generateModalHTML(screenshotDataUrl?: string): string;
22
+ /**
23
+ * Generate modal header
24
+ */
25
+ private generateHeader;
26
+ /**
27
+ * Generate modal body with form
28
+ */
29
+ private generateBody;
30
+ /**
31
+ * Generate title input field
32
+ */
33
+ private generateTitleField;
34
+ /**
35
+ * Generate description textarea field
36
+ */
37
+ private generateDescriptionField;
38
+ /**
39
+ * Generate screenshot section with redaction controls
40
+ */
41
+ private generateScreenshotSection;
42
+ /**
43
+ * Generate PII detection section (initially hidden)
44
+ */
45
+ private generatePIISection;
46
+ /**
47
+ * Generate modal footer with action buttons
48
+ */
49
+ private generateFooter;
50
+ /**
51
+ * Generate PII badge HTML
52
+ */
53
+ generatePIIBadge(type: string, count: number): string;
54
+ /**
55
+ * Escape HTML to prevent XSS
56
+ */
57
+ private escapeHtml;
58
+ /**
59
+ * Update configuration
60
+ */
61
+ updateConfig(config: Partial<TemplateConfig>): void;
62
+ /**
63
+ * Get current configuration
64
+ */
65
+ getConfig(): Required<TemplateConfig>;
66
+ }
@@ -0,0 +1,198 @@
1
+ "use strict";
2
+ /**
3
+ * TemplateManager
4
+ *
5
+ * Responsibility: Generate HTML templates for modal components
6
+ * Follows SRP: Only handles HTML structure generation
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.TemplateManager = void 0;
10
+ class TemplateManager {
11
+ constructor(config = {}) {
12
+ this.config = {
13
+ title: config.title || 'Report a Bug',
14
+ titlePlaceholder: config.titlePlaceholder || 'Brief description of the issue',
15
+ descriptionPlaceholder: config.descriptionPlaceholder || 'Detailed description of what happened...',
16
+ submitButtonText: config.submitButtonText || 'Submit Bug Report',
17
+ cancelButtonText: config.cancelButtonText || 'Cancel',
18
+ showScreenshot: config.showScreenshot !== false,
19
+ };
20
+ }
21
+ /**
22
+ * Generate complete modal HTML structure
23
+ */
24
+ generateModalHTML(screenshotDataUrl) {
25
+ return `
26
+ <div class="overlay">
27
+ <div class="modal">
28
+ ${this.generateHeader()}
29
+ ${this.generateBody(screenshotDataUrl)}
30
+ ${this.generateFooter()}
31
+ </div>
32
+ </div>
33
+ `;
34
+ }
35
+ /**
36
+ * Generate modal header
37
+ */
38
+ generateHeader() {
39
+ return `
40
+ <div class="header">
41
+ <h2>${this.escapeHtml(this.config.title)}</h2>
42
+ <button class="close" aria-label="Close">&times;</button>
43
+ </div>
44
+ `;
45
+ }
46
+ /**
47
+ * Generate modal body with form
48
+ */
49
+ generateBody(screenshotDataUrl) {
50
+ return `
51
+ <div class="body">
52
+ <form class="form">
53
+ ${this.generateTitleField()}
54
+ ${this.generateDescriptionField()}
55
+ ${this.config.showScreenshot && screenshotDataUrl ? this.generateScreenshotSection(screenshotDataUrl) : ''}
56
+ ${this.generatePIISection()}
57
+ </form>
58
+ </div>
59
+ `;
60
+ }
61
+ /**
62
+ * Generate title input field
63
+ */
64
+ generateTitleField() {
65
+ return `
66
+ <div class="form-group">
67
+ <label class="label" for="title">Title *</label>
68
+ <input
69
+ type="text"
70
+ id="title"
71
+ class="input"
72
+ placeholder="${this.escapeHtml(this.config.titlePlaceholder)}"
73
+ required
74
+ />
75
+ <div class="error" id="title-error"></div>
76
+ </div>
77
+ `;
78
+ }
79
+ /**
80
+ * Generate description textarea field
81
+ */
82
+ generateDescriptionField() {
83
+ return `
84
+ <div class="form-group">
85
+ <label class="label" for="description">Description *</label>
86
+ <textarea
87
+ id="description"
88
+ class="textarea"
89
+ placeholder="${this.escapeHtml(this.config.descriptionPlaceholder)}"
90
+ required
91
+ ></textarea>
92
+ <div class="error" id="description-error"></div>
93
+ </div>
94
+ `;
95
+ }
96
+ /**
97
+ * Generate screenshot section with redaction controls
98
+ */
99
+ generateScreenshotSection(screenshotDataUrl) {
100
+ return `
101
+ <div class="form-group">
102
+ <label class="label">Screenshot</label>
103
+ <div class="screenshot-container">
104
+ <img
105
+ src="${screenshotDataUrl}"
106
+ alt="Bug screenshot"
107
+ class="screenshot"
108
+ id="screenshot"
109
+ />
110
+ <canvas
111
+ class="redaction-canvas"
112
+ id="redaction-canvas"
113
+ style="display: none;"
114
+ ></canvas>
115
+ </div>
116
+ <div class="redaction-controls">
117
+ <button
118
+ type="button"
119
+ class="btn-redact"
120
+ id="btn-redact"
121
+ >
122
+ ✏️ Redact Area
123
+ </button>
124
+ <button
125
+ type="button"
126
+ class="btn-clear"
127
+ id="btn-clear"
128
+ >
129
+ 🗑️ Clear Redactions
130
+ </button>
131
+ </div>
132
+ </div>
133
+ `;
134
+ }
135
+ /**
136
+ * Generate PII detection section (initially hidden)
137
+ */
138
+ generatePIISection() {
139
+ return `
140
+ <div class="pii-section" id="pii-section" style="display: none;">
141
+ <h3 class="pii-title">⚠️ Potential PII Detected</h3>
142
+ <div id="pii-content"></div>
143
+ <div class="checkbox-group">
144
+ <input
145
+ type="checkbox"
146
+ id="pii-confirm"
147
+ class="checkbox"
148
+ />
149
+ <label for="pii-confirm" class="checkbox-label">
150
+ I have reviewed and redacted sensitive information
151
+ </label>
152
+ </div>
153
+ </div>
154
+ `;
155
+ }
156
+ /**
157
+ * Generate modal footer with action buttons
158
+ */
159
+ generateFooter() {
160
+ return `
161
+ <div class="footer">
162
+ <button type="button" class="btn btn-secondary" id="btn-cancel">
163
+ ${this.escapeHtml(this.config.cancelButtonText)}
164
+ </button>
165
+ <button type="submit" class="btn btn-primary submit" id="btn-submit">
166
+ ${this.escapeHtml(this.config.submitButtonText)}
167
+ </button>
168
+ </div>
169
+ `;
170
+ }
171
+ /**
172
+ * Generate PII badge HTML
173
+ */
174
+ generatePIIBadge(type, count) {
175
+ return `<span class="bugspotter-pii-badge">${this.escapeHtml(type)}: ${count}</span>`;
176
+ }
177
+ /**
178
+ * Escape HTML to prevent XSS
179
+ */
180
+ escapeHtml(text) {
181
+ const div = document.createElement('div');
182
+ div.textContent = text;
183
+ return div.innerHTML;
184
+ }
185
+ /**
186
+ * Update configuration
187
+ */
188
+ updateConfig(config) {
189
+ this.config = Object.assign(Object.assign({}, this.config), config);
190
+ }
191
+ /**
192
+ * Get current configuration
193
+ */
194
+ getConfig() {
195
+ return Object.assign({}, this.config);
196
+ }
197
+ }
198
+ exports.TemplateManager = TemplateManager;
@@ -0,0 +1,62 @@
1
+ export interface BugReportData {
2
+ title: string;
3
+ description: string;
4
+ }
5
+ export interface PIIDetection {
6
+ type: string;
7
+ count: number;
8
+ }
9
+ export interface BugReportModalOptions {
10
+ onSubmit: (data: BugReportData) => void | Promise<void>;
11
+ onClose?: () => void;
12
+ }
13
+ /**
14
+ * BugReportModal
15
+ *
16
+ * Refactored to follow SOLID principles
17
+ * Acts as a lightweight coordinator for specialized components
18
+ */
19
+ export declare class BugReportModal {
20
+ private container;
21
+ private shadow;
22
+ private options;
23
+ private styleManager;
24
+ private templateManager;
25
+ private domCache;
26
+ private validator;
27
+ private piiDisplay;
28
+ private redactionCanvas;
29
+ private screenshotProcessor;
30
+ private originalScreenshot;
31
+ private piiDetections;
32
+ private handleEscapeKey;
33
+ constructor(options: BugReportModalOptions);
34
+ /**
35
+ * Show the modal with optional screenshot
36
+ */
37
+ show(screenshotDataUrl?: string): void;
38
+ /**
39
+ * Close and cleanup the modal
40
+ */
41
+ close(): void;
42
+ /**
43
+ * Destroy the modal (alias for close)
44
+ */
45
+ destroy(): void;
46
+ private setupRedactionCanvas;
47
+ private attachEventListeners;
48
+ private validateField;
49
+ private checkForPII;
50
+ private updateSubmitButton;
51
+ private toggleRedactionMode;
52
+ private clearRedactions;
53
+ private handleSubmit;
54
+ /**
55
+ * Get the final screenshot (with redactions applied)
56
+ */
57
+ getScreenshot(): string;
58
+ /**
59
+ * Handle Escape key press to close modal
60
+ */
61
+ private onEscapeKey;
62
+ }