@arvoretech/bug-jar 0.2.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Árvore Educação
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,126 @@
1
+ # 🪲 Bug Jar
2
+
3
+ Capture everything for non-technical people to help debug. One script tag, zero config.
4
+
5
+ Bug Jar is a lightweight JavaScript library that silently records all browser activity (network requests, console logs, errors, user actions, performance metrics, and more) and lets anyone — even non-technical users — generate a complete debug report with a single click.
6
+
7
+ ## Why?
8
+
9
+ Because asking someone to "open DevTools and check the Network tab" doesn't scale. Bug Jar gives your support team, QA, and stakeholders a one-click way to capture everything developers need to reproduce and fix bugs.
10
+
11
+ ## What it captures
12
+
13
+ | Category | Details |
14
+ |----------|---------|
15
+ | **Network** | All fetch/XHR/beacon requests with headers, payload, response, status, timing |
16
+ | **Console** | log, warn, error, info, debug — with stack traces |
17
+ | **Errors** | Uncaught exceptions, unhandled promise rejections, resource load failures |
18
+ | **User Actions** | Clicks, inputs, navigation, scroll, resize, visibility changes |
19
+ | **Environment** | Browser, OS, viewport, DPR, timezone, language, connection type |
20
+ | **Performance** | Navigation timing, Web Vitals (LCP, FID, CLS), resource count |
21
+ | **Storage** | localStorage keys, sessionStorage keys, cookie names |
22
+ | **Screenshot** | Visual snapshot of the current page state |
23
+ | **HTML Snapshot** | Full DOM at the moment of report |
24
+ | **Feature Flags** | PostHog, LaunchDarkly, Statsig, Unleash (auto-detected) |
25
+ | **Memory** | JS heap usage (Chrome) |
26
+
27
+ ## Quick Start
28
+
29
+ ### Script tag (zero config)
30
+
31
+ ```html
32
+ <script src="https://unpkg.com/@arvoretech/bug-jar"></script>
33
+ <script>
34
+ BugJar.init();
35
+ </script>
36
+ ```
37
+
38
+ ### NPM
39
+
40
+ ```bash
41
+ npm install @arvoretech/bug-jar
42
+ ```
43
+
44
+ ```typescript
45
+ import { init } from '@arvoretech/bug-jar'
46
+
47
+ init({
48
+ endpoint: 'https://your-api.com/bug-reports',
49
+ uiPosition: 'bottom-right',
50
+ })
51
+ ```
52
+
53
+ ## Configuration
54
+
55
+ ```typescript
56
+ init({
57
+ // Buffer sizes
58
+ maxNetworkEntries: 100,
59
+ maxConsoleEntries: 200,
60
+ maxUserActions: 150,
61
+ maxErrors: 50,
62
+
63
+ // What to capture
64
+ captureScreenshot: true,
65
+ captureHtmlSnapshot: true,
66
+ captureCookies: true,
67
+ captureLocalStorage: true,
68
+ captureSessionStorage: true,
69
+ capturePerformance: true,
70
+ captureWebVitals: true,
71
+ captureMemory: true,
72
+ captureConnectivity: true,
73
+
74
+ // Privacy — fields containing these strings are redacted
75
+ sensitiveFields: ['password', 'token', 'secret', 'authorization', 'cookie', 'session', 'credit_card', 'cvv', 'ssn', 'cpf'],
76
+
77
+ // Where to send reports (if not set, downloads as JSON file)
78
+ endpoint: 'https://your-api.com/bug-reports',
79
+
80
+ // Callback when report is generated
81
+ onCapture: (report) => console.log(report),
82
+
83
+ // UI widget
84
+ ui: true,
85
+ uiPosition: 'bottom-right', // bottom-right | bottom-left | top-right | top-left
86
+ uiLabel: 'Reportar Bug',
87
+ })
88
+ ```
89
+
90
+ ## Programmatic Usage
91
+
92
+ ```typescript
93
+ import { BugJar } from '@arvoretech/bug-jar'
94
+
95
+ const jar = new BugJar({ ui: false })
96
+ jar.start()
97
+
98
+ // Later, capture a report programmatically
99
+ const report = await jar.capture('User clicked X but nothing happened')
100
+
101
+ // Send it wherever you want
102
+ await fetch('/api/bugs', {
103
+ method: 'POST',
104
+ body: JSON.stringify(report),
105
+ })
106
+ ```
107
+
108
+ ## Privacy & Security
109
+
110
+ - Sensitive fields are automatically redacted (passwords, tokens, secrets, etc.)
111
+ - Password inputs are never captured
112
+ - You control what gets captured via configuration
113
+ - No data leaves the browser unless you configure an endpoint
114
+ - All processing happens client-side
115
+
116
+ ## Browser Support
117
+
118
+ Works in all modern browsers (Chrome, Firefox, Safari, Edge). Some features (memory info, connection type) are Chrome-only but degrade gracefully.
119
+
120
+ ## Size
121
+
122
+ ~12kb gzipped, zero dependencies.
123
+
124
+ ## License
125
+
126
+ MIT
@@ -0,0 +1,162 @@
1
+ interface BugJarConfig {
2
+ maxNetworkEntries: number;
3
+ maxConsoleEntries: number;
4
+ maxUserActions: number;
5
+ maxErrors: number;
6
+ captureScreenshot: boolean;
7
+ captureHtmlSnapshot: boolean;
8
+ captureCookies: boolean;
9
+ captureLocalStorage: boolean;
10
+ captureSessionStorage: boolean;
11
+ capturePerformance: boolean;
12
+ captureWebVitals: boolean;
13
+ captureMemory: boolean;
14
+ captureConnectivity: boolean;
15
+ sensitiveFields: string[];
16
+ endpoint?: string;
17
+ onCapture?: (report: BugReport) => void;
18
+ ui: boolean;
19
+ uiPosition: "bottom-right" | "bottom-left" | "top-right" | "top-left";
20
+ uiLabel: string;
21
+ }
22
+ interface NetworkEntry {
23
+ id: string;
24
+ timestamp: number;
25
+ method: string;
26
+ url: string;
27
+ requestHeaders: Record<string, string>;
28
+ requestBody: unknown;
29
+ status: number | null;
30
+ statusText: string;
31
+ responseHeaders: Record<string, string>;
32
+ responseBody: unknown;
33
+ responseSize: number | null;
34
+ duration: number | null;
35
+ type: "fetch" | "xhr" | "beacon";
36
+ error: string | null;
37
+ initiator: string | null;
38
+ }
39
+ interface ConsoleEntry {
40
+ timestamp: number;
41
+ level: "log" | "warn" | "error" | "info" | "debug";
42
+ args: unknown[];
43
+ stack: string | null;
44
+ }
45
+ interface ErrorEntry {
46
+ timestamp: number;
47
+ message: string;
48
+ stack: string | null;
49
+ filename: string | null;
50
+ lineno: number | null;
51
+ colno: number | null;
52
+ type: "uncaught" | "unhandledrejection" | "resource";
53
+ context: string | null;
54
+ }
55
+ interface UserAction {
56
+ timestamp: number;
57
+ type: "click" | "input" | "navigation" | "scroll" | "resize" | "visibility" | "copy" | "paste";
58
+ target: string;
59
+ value?: string;
60
+ metadata?: Record<string, unknown>;
61
+ }
62
+ interface EnvironmentInfo {
63
+ userAgent: string;
64
+ platform: string;
65
+ language: string;
66
+ languages: string[];
67
+ timezone: string;
68
+ timezoneOffset: number;
69
+ screenWidth: number;
70
+ screenHeight: number;
71
+ viewportWidth: number;
72
+ viewportHeight: number;
73
+ devicePixelRatio: number;
74
+ colorDepth: number;
75
+ cookiesEnabled: boolean;
76
+ doNotTrack: string | null;
77
+ online: boolean;
78
+ hardwareConcurrency: number;
79
+ maxTouchPoints: number;
80
+ vendor: string;
81
+ connection: ConnectionInfo | null;
82
+ memory: MemoryInfo | null;
83
+ }
84
+ interface ConnectionInfo {
85
+ effectiveType: string;
86
+ downlink: number;
87
+ rtt: number;
88
+ saveData: boolean;
89
+ }
90
+ interface MemoryInfo {
91
+ jsHeapSizeLimit: number;
92
+ totalJSHeapSize: number;
93
+ usedJSHeapSize: number;
94
+ }
95
+ interface PerformanceData {
96
+ navigationTiming: Record<string, number>;
97
+ resourceCount: number;
98
+ totalTransferSize: number;
99
+ domContentLoaded: number | null;
100
+ loadComplete: number | null;
101
+ firstPaint: number | null;
102
+ firstContentfulPaint: number | null;
103
+ largestContentfulPaint: number | null;
104
+ firstInputDelay: number | null;
105
+ cumulativeLayoutShift: number | null;
106
+ timeToInteractive: number | null;
107
+ }
108
+ interface StorageSnapshot {
109
+ localStorage: Record<string, string>;
110
+ sessionStorage: Record<string, string>;
111
+ cookies: string[];
112
+ }
113
+ interface BugReport {
114
+ id: string;
115
+ timestamp: number;
116
+ url: string;
117
+ title: string;
118
+ userDescription: string;
119
+ environment: EnvironmentInfo;
120
+ network: NetworkEntry[];
121
+ console: ConsoleEntry[];
122
+ errors: ErrorEntry[];
123
+ userActions: UserAction[];
124
+ performance: PerformanceData | null;
125
+ storage: StorageSnapshot | null;
126
+ screenshot: string | null;
127
+ htmlSnapshot: string | null;
128
+ featureFlags: Record<string, unknown> | null;
129
+ metadata: Record<string, unknown>;
130
+ version: string;
131
+ }
132
+
133
+ declare function generateSummary(report: BugReport): string;
134
+
135
+ declare function exportAsZip(report: BugReport, videoBlob: Blob | null): Promise<Blob>;
136
+
137
+ declare class BugJar {
138
+ private config;
139
+ private network;
140
+ private console;
141
+ private errors;
142
+ private userActions;
143
+ private environment;
144
+ private performance;
145
+ private storage;
146
+ private screenshot;
147
+ private featureFlags;
148
+ private screenRecorder;
149
+ private ui;
150
+ private started;
151
+ constructor(config?: Partial<BugJarConfig>);
152
+ start(): void;
153
+ stop(): void;
154
+ startRecording(): Promise<void>;
155
+ get isRecording(): boolean;
156
+ capture(userDescription?: string): Promise<BugReport>;
157
+ captureAndExport(userDescription?: string): Promise<BugReport>;
158
+ getReport(): Promise<BugReport>;
159
+ }
160
+ declare function init(config?: Partial<BugJarConfig>): BugJar;
161
+
162
+ export { BugJar, type BugJarConfig, type BugReport, BugJar as default, exportAsZip, generateSummary, init };
@@ -0,0 +1,162 @@
1
+ interface BugJarConfig {
2
+ maxNetworkEntries: number;
3
+ maxConsoleEntries: number;
4
+ maxUserActions: number;
5
+ maxErrors: number;
6
+ captureScreenshot: boolean;
7
+ captureHtmlSnapshot: boolean;
8
+ captureCookies: boolean;
9
+ captureLocalStorage: boolean;
10
+ captureSessionStorage: boolean;
11
+ capturePerformance: boolean;
12
+ captureWebVitals: boolean;
13
+ captureMemory: boolean;
14
+ captureConnectivity: boolean;
15
+ sensitiveFields: string[];
16
+ endpoint?: string;
17
+ onCapture?: (report: BugReport) => void;
18
+ ui: boolean;
19
+ uiPosition: "bottom-right" | "bottom-left" | "top-right" | "top-left";
20
+ uiLabel: string;
21
+ }
22
+ interface NetworkEntry {
23
+ id: string;
24
+ timestamp: number;
25
+ method: string;
26
+ url: string;
27
+ requestHeaders: Record<string, string>;
28
+ requestBody: unknown;
29
+ status: number | null;
30
+ statusText: string;
31
+ responseHeaders: Record<string, string>;
32
+ responseBody: unknown;
33
+ responseSize: number | null;
34
+ duration: number | null;
35
+ type: "fetch" | "xhr" | "beacon";
36
+ error: string | null;
37
+ initiator: string | null;
38
+ }
39
+ interface ConsoleEntry {
40
+ timestamp: number;
41
+ level: "log" | "warn" | "error" | "info" | "debug";
42
+ args: unknown[];
43
+ stack: string | null;
44
+ }
45
+ interface ErrorEntry {
46
+ timestamp: number;
47
+ message: string;
48
+ stack: string | null;
49
+ filename: string | null;
50
+ lineno: number | null;
51
+ colno: number | null;
52
+ type: "uncaught" | "unhandledrejection" | "resource";
53
+ context: string | null;
54
+ }
55
+ interface UserAction {
56
+ timestamp: number;
57
+ type: "click" | "input" | "navigation" | "scroll" | "resize" | "visibility" | "copy" | "paste";
58
+ target: string;
59
+ value?: string;
60
+ metadata?: Record<string, unknown>;
61
+ }
62
+ interface EnvironmentInfo {
63
+ userAgent: string;
64
+ platform: string;
65
+ language: string;
66
+ languages: string[];
67
+ timezone: string;
68
+ timezoneOffset: number;
69
+ screenWidth: number;
70
+ screenHeight: number;
71
+ viewportWidth: number;
72
+ viewportHeight: number;
73
+ devicePixelRatio: number;
74
+ colorDepth: number;
75
+ cookiesEnabled: boolean;
76
+ doNotTrack: string | null;
77
+ online: boolean;
78
+ hardwareConcurrency: number;
79
+ maxTouchPoints: number;
80
+ vendor: string;
81
+ connection: ConnectionInfo | null;
82
+ memory: MemoryInfo | null;
83
+ }
84
+ interface ConnectionInfo {
85
+ effectiveType: string;
86
+ downlink: number;
87
+ rtt: number;
88
+ saveData: boolean;
89
+ }
90
+ interface MemoryInfo {
91
+ jsHeapSizeLimit: number;
92
+ totalJSHeapSize: number;
93
+ usedJSHeapSize: number;
94
+ }
95
+ interface PerformanceData {
96
+ navigationTiming: Record<string, number>;
97
+ resourceCount: number;
98
+ totalTransferSize: number;
99
+ domContentLoaded: number | null;
100
+ loadComplete: number | null;
101
+ firstPaint: number | null;
102
+ firstContentfulPaint: number | null;
103
+ largestContentfulPaint: number | null;
104
+ firstInputDelay: number | null;
105
+ cumulativeLayoutShift: number | null;
106
+ timeToInteractive: number | null;
107
+ }
108
+ interface StorageSnapshot {
109
+ localStorage: Record<string, string>;
110
+ sessionStorage: Record<string, string>;
111
+ cookies: string[];
112
+ }
113
+ interface BugReport {
114
+ id: string;
115
+ timestamp: number;
116
+ url: string;
117
+ title: string;
118
+ userDescription: string;
119
+ environment: EnvironmentInfo;
120
+ network: NetworkEntry[];
121
+ console: ConsoleEntry[];
122
+ errors: ErrorEntry[];
123
+ userActions: UserAction[];
124
+ performance: PerformanceData | null;
125
+ storage: StorageSnapshot | null;
126
+ screenshot: string | null;
127
+ htmlSnapshot: string | null;
128
+ featureFlags: Record<string, unknown> | null;
129
+ metadata: Record<string, unknown>;
130
+ version: string;
131
+ }
132
+
133
+ declare function generateSummary(report: BugReport): string;
134
+
135
+ declare function exportAsZip(report: BugReport, videoBlob: Blob | null): Promise<Blob>;
136
+
137
+ declare class BugJar {
138
+ private config;
139
+ private network;
140
+ private console;
141
+ private errors;
142
+ private userActions;
143
+ private environment;
144
+ private performance;
145
+ private storage;
146
+ private screenshot;
147
+ private featureFlags;
148
+ private screenRecorder;
149
+ private ui;
150
+ private started;
151
+ constructor(config?: Partial<BugJarConfig>);
152
+ start(): void;
153
+ stop(): void;
154
+ startRecording(): Promise<void>;
155
+ get isRecording(): boolean;
156
+ capture(userDescription?: string): Promise<BugReport>;
157
+ captureAndExport(userDescription?: string): Promise<BugReport>;
158
+ getReport(): Promise<BugReport>;
159
+ }
160
+ declare function init(config?: Partial<BugJarConfig>): BugJar;
161
+
162
+ export { BugJar, type BugJarConfig, type BugReport, BugJar as default, exportAsZip, generateSummary, init };