@bbearai/core 0.2.12 → 0.2.14
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/README.md +95 -8
- package/dist/index.d.mts +20 -1
- package/dist/index.d.ts +20 -1
- package/dist/index.js +25 -3
- package/dist/index.mjs +25 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Core client and utilities for BugBear QA platform.
|
|
4
4
|
|
|
5
|
-
> **Note:** Most users should install `@bbearai/react` instead, which
|
|
5
|
+
> **Note:** Most users should install `@bbearai/react` or `@bbearai/react-native` instead, which include this package automatically.
|
|
6
6
|
|
|
7
7
|
## Installation
|
|
8
8
|
|
|
@@ -20,6 +20,7 @@ const bugbear = createBugBear({
|
|
|
20
20
|
getCurrentUser: async () => ({
|
|
21
21
|
id: 'user-123',
|
|
22
22
|
email: 'user@example.com',
|
|
23
|
+
name: 'Jane Doe', // Optional, used for reporter identity
|
|
23
24
|
}),
|
|
24
25
|
});
|
|
25
26
|
|
|
@@ -28,6 +29,7 @@ await bugbear.submitReport({
|
|
|
28
29
|
type: 'bug',
|
|
29
30
|
description: 'Button does not work',
|
|
30
31
|
severity: 'high',
|
|
32
|
+
appContext: { currentRoute: '/dashboard' },
|
|
31
33
|
});
|
|
32
34
|
|
|
33
35
|
// Check if user is a tester
|
|
@@ -37,13 +39,84 @@ const isTester = await bugbear.isTester();
|
|
|
37
39
|
const assignments = await bugbear.getAssignedTests();
|
|
38
40
|
```
|
|
39
41
|
|
|
40
|
-
##
|
|
42
|
+
## Configuration
|
|
41
43
|
|
|
42
|
-
|
|
44
|
+
```typescript
|
|
45
|
+
interface BugBearConfig {
|
|
46
|
+
// Required
|
|
47
|
+
projectId: string;
|
|
48
|
+
getCurrentUser: () => Promise<{ id: string; email: string; name?: string } | null>;
|
|
49
|
+
|
|
50
|
+
// Optional — context
|
|
51
|
+
getAppContext?: () => AppContext; // Rich app context (userRole, etc.)
|
|
52
|
+
getNavigationHistory?: () => string[]; // Custom navigation tracking
|
|
53
|
+
|
|
54
|
+
// Optional — callbacks
|
|
55
|
+
onReportSubmitted?: (report: BugBearReport) => void;
|
|
56
|
+
onNavigate?: (route: string) => void; // Deep linking from test cases
|
|
57
|
+
|
|
58
|
+
// Optional — self-hosted
|
|
59
|
+
supabaseUrl?: string;
|
|
60
|
+
supabaseAnonKey?: string;
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### AppContext
|
|
65
|
+
|
|
66
|
+
Provide `getAppContext` to attach rich context to every bug report. This helps the developer fixing the bug understand the user's state:
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
const bugbear = createBugBear({
|
|
70
|
+
projectId: 'your-project-id',
|
|
71
|
+
getCurrentUser: async () => ({ id: user.id, email: user.email }),
|
|
72
|
+
getAppContext: () => ({
|
|
73
|
+
currentRoute: window.location.pathname,
|
|
74
|
+
userRole: currentUser?.role, // e.g. 'owner', 'manager', 'guest'
|
|
75
|
+
propertyId: currentProperty?.id, // App-specific context
|
|
76
|
+
custom: { // Any additional context
|
|
77
|
+
theme: 'dark',
|
|
78
|
+
locale: 'en-US',
|
|
79
|
+
},
|
|
80
|
+
}),
|
|
81
|
+
});
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Automatic Context Capture
|
|
85
|
+
|
|
86
|
+
BugBear automatically captures debugging context when initialized via `BugBearProvider` (React or React Native). No manual setup required.
|
|
43
87
|
|
|
44
|
-
|
|
88
|
+
**What's captured automatically:**
|
|
45
89
|
|
|
46
|
-
|
|
90
|
+
| Data | Details |
|
|
91
|
+
|------|---------|
|
|
92
|
+
| **Console logs** | Last 50 `console.log/warn/error/info` calls |
|
|
93
|
+
| **Network requests** | Last 20 `fetch()` calls with method, URL, status, duration |
|
|
94
|
+
| **Failed response bodies** | First 500 chars of response body for 4xx/5xx errors |
|
|
95
|
+
| **Navigation history** | Last 20 route changes (via `pushState`/`replaceState`/`popstate`) |
|
|
96
|
+
| **Performance metrics** | Page load time, memory usage (Chrome) |
|
|
97
|
+
| **Environment** | Language, timezone, online status, cookies, localStorage |
|
|
98
|
+
|
|
99
|
+
This data is attached to every bug report as `enhanced_context` and is available to the MCP server's `get_report_context` tool.
|
|
100
|
+
|
|
101
|
+
### Manual Capture (framework authors)
|
|
102
|
+
|
|
103
|
+
If you're not using `BugBearProvider`, start capture manually:
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
import { contextCapture } from '@bbearai/core';
|
|
107
|
+
|
|
108
|
+
// Start capturing (call once at app init)
|
|
109
|
+
contextCapture.startCapture();
|
|
110
|
+
|
|
111
|
+
// For React Native: manually track screen changes
|
|
112
|
+
contextCapture.trackNavigation('/home');
|
|
113
|
+
contextCapture.trackNavigation('/settings');
|
|
114
|
+
|
|
115
|
+
// Get captured data (automatically included in submitReport)
|
|
116
|
+
const context = contextCapture.getEnhancedContext();
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Client Methods
|
|
47
120
|
|
|
48
121
|
| Method | Description |
|
|
49
122
|
|--------|-------------|
|
|
@@ -53,7 +126,9 @@ Creates a BugBear client instance.
|
|
|
53
126
|
| `shouldShowWidget()` | Check if widget should be visible (QA enabled + is tester) |
|
|
54
127
|
| `getTesterInfo()` | Get current tester's info |
|
|
55
128
|
| `getAssignedTests()` | Get test cases assigned to current tester |
|
|
56
|
-
| `
|
|
129
|
+
| `getAppContext()` | Get current app context (uses config callback or auto-captured) |
|
|
130
|
+
| `getNavigationHistory()` | Get navigation history (config callback > manual > auto-captured) |
|
|
131
|
+
| `trackNavigation(route)` | Manually track a route change |
|
|
57
132
|
| `uploadScreenshot(file)` | Upload a screenshot |
|
|
58
133
|
|
|
59
134
|
## Types
|
|
@@ -66,7 +141,15 @@ interface BugBearReport {
|
|
|
66
141
|
severity?: 'critical' | 'high' | 'medium' | 'low';
|
|
67
142
|
screenshots?: string[];
|
|
68
143
|
appContext?: AppContext;
|
|
69
|
-
|
|
144
|
+
enhancedContext?: EnhancedBugContext;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
interface AppContext {
|
|
148
|
+
currentRoute: string;
|
|
149
|
+
screenName?: string;
|
|
150
|
+
userRole?: string;
|
|
151
|
+
propertyId?: string;
|
|
152
|
+
custom?: Record<string, unknown>;
|
|
70
153
|
}
|
|
71
154
|
|
|
72
155
|
interface TesterInfo {
|
|
@@ -96,7 +179,11 @@ interface TestAssignment {
|
|
|
96
179
|
If you're building a BugBear integration for a different framework (Vue, Svelte, etc.), use this package as the foundation:
|
|
97
180
|
|
|
98
181
|
```typescript
|
|
99
|
-
import { BugBearClient, createBugBear, BugBearConfig } from '@bbearai/core';
|
|
182
|
+
import { BugBearClient, createBugBear, contextCapture, BugBearConfig } from '@bbearai/core';
|
|
183
|
+
|
|
184
|
+
// Start context capture at app init
|
|
185
|
+
contextCapture.startCapture();
|
|
100
186
|
|
|
101
187
|
// Create your framework-specific wrapper around the client
|
|
188
|
+
const client = createBugBear(config);
|
|
102
189
|
```
|
package/dist/index.d.mts
CHANGED
|
@@ -662,11 +662,30 @@ declare class BugBearClient {
|
|
|
662
662
|
error?: string;
|
|
663
663
|
durationSeconds?: number;
|
|
664
664
|
}>;
|
|
665
|
+
/**
|
|
666
|
+
* Pass a test assignment — convenience wrapper around updateAssignmentStatus
|
|
667
|
+
*/
|
|
668
|
+
passAssignment(assignmentId: string): Promise<{
|
|
669
|
+
success: boolean;
|
|
670
|
+
error?: string;
|
|
671
|
+
durationSeconds?: number;
|
|
672
|
+
}>;
|
|
673
|
+
/**
|
|
674
|
+
* Fail a test assignment — convenience wrapper around updateAssignmentStatus
|
|
675
|
+
*/
|
|
676
|
+
failAssignment(assignmentId: string): Promise<{
|
|
677
|
+
success: boolean;
|
|
678
|
+
error?: string;
|
|
679
|
+
durationSeconds?: number;
|
|
680
|
+
}>;
|
|
665
681
|
/**
|
|
666
682
|
* Skip a test assignment with a required reason
|
|
667
683
|
* Marks the assignment as 'skipped' and records why it was skipped
|
|
668
684
|
*/
|
|
669
|
-
skipAssignment(assignmentId: string, reason: SkipReason
|
|
685
|
+
skipAssignment(assignmentId: string, reason: SkipReason | {
|
|
686
|
+
reason: SkipReason;
|
|
687
|
+
notes?: string;
|
|
688
|
+
}, notes?: string): Promise<{
|
|
670
689
|
success: boolean;
|
|
671
690
|
error?: string;
|
|
672
691
|
}>;
|
package/dist/index.d.ts
CHANGED
|
@@ -662,11 +662,30 @@ declare class BugBearClient {
|
|
|
662
662
|
error?: string;
|
|
663
663
|
durationSeconds?: number;
|
|
664
664
|
}>;
|
|
665
|
+
/**
|
|
666
|
+
* Pass a test assignment — convenience wrapper around updateAssignmentStatus
|
|
667
|
+
*/
|
|
668
|
+
passAssignment(assignmentId: string): Promise<{
|
|
669
|
+
success: boolean;
|
|
670
|
+
error?: string;
|
|
671
|
+
durationSeconds?: number;
|
|
672
|
+
}>;
|
|
673
|
+
/**
|
|
674
|
+
* Fail a test assignment — convenience wrapper around updateAssignmentStatus
|
|
675
|
+
*/
|
|
676
|
+
failAssignment(assignmentId: string): Promise<{
|
|
677
|
+
success: boolean;
|
|
678
|
+
error?: string;
|
|
679
|
+
durationSeconds?: number;
|
|
680
|
+
}>;
|
|
665
681
|
/**
|
|
666
682
|
* Skip a test assignment with a required reason
|
|
667
683
|
* Marks the assignment as 'skipped' and records why it was skipped
|
|
668
684
|
*/
|
|
669
|
-
skipAssignment(assignmentId: string, reason: SkipReason
|
|
685
|
+
skipAssignment(assignmentId: string, reason: SkipReason | {
|
|
686
|
+
reason: SkipReason;
|
|
687
|
+
notes?: string;
|
|
688
|
+
}, notes?: string): Promise<{
|
|
670
689
|
success: boolean;
|
|
671
690
|
error?: string;
|
|
672
691
|
}>;
|
package/dist/index.js
CHANGED
|
@@ -630,19 +630,40 @@ var BugBearClient = class {
|
|
|
630
630
|
return { success: false, error: message };
|
|
631
631
|
}
|
|
632
632
|
}
|
|
633
|
+
/**
|
|
634
|
+
* Pass a test assignment — convenience wrapper around updateAssignmentStatus
|
|
635
|
+
*/
|
|
636
|
+
async passAssignment(assignmentId) {
|
|
637
|
+
return this.updateAssignmentStatus(assignmentId, "passed");
|
|
638
|
+
}
|
|
639
|
+
/**
|
|
640
|
+
* Fail a test assignment — convenience wrapper around updateAssignmentStatus
|
|
641
|
+
*/
|
|
642
|
+
async failAssignment(assignmentId) {
|
|
643
|
+
return this.updateAssignmentStatus(assignmentId, "failed");
|
|
644
|
+
}
|
|
633
645
|
/**
|
|
634
646
|
* Skip a test assignment with a required reason
|
|
635
647
|
* Marks the assignment as 'skipped' and records why it was skipped
|
|
636
648
|
*/
|
|
637
649
|
async skipAssignment(assignmentId, reason, notes) {
|
|
650
|
+
let actualReason;
|
|
651
|
+
let actualNotes;
|
|
652
|
+
if (typeof reason === "object") {
|
|
653
|
+
actualReason = reason.reason;
|
|
654
|
+
actualNotes = reason.notes;
|
|
655
|
+
} else {
|
|
656
|
+
actualReason = reason;
|
|
657
|
+
actualNotes = notes;
|
|
658
|
+
}
|
|
638
659
|
try {
|
|
639
660
|
const updateData = {
|
|
640
661
|
status: "skipped",
|
|
641
|
-
skip_reason:
|
|
662
|
+
skip_reason: actualReason,
|
|
642
663
|
completed_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
643
664
|
};
|
|
644
|
-
if (
|
|
645
|
-
updateData.notes =
|
|
665
|
+
if (actualNotes) {
|
|
666
|
+
updateData.notes = actualNotes;
|
|
646
667
|
}
|
|
647
668
|
const { error } = await this.supabase.from("test_assignments").update(updateData).eq("id", assignmentId);
|
|
648
669
|
if (error) {
|
|
@@ -1282,6 +1303,7 @@ var BugBearClient = class {
|
|
|
1282
1303
|
return false;
|
|
1283
1304
|
}
|
|
1284
1305
|
await this.supabase.from("discussion_threads").update({ last_message_at: (/* @__PURE__ */ new Date()).toISOString() }).eq("id", threadId);
|
|
1306
|
+
await this.markThreadAsRead(threadId);
|
|
1285
1307
|
return true;
|
|
1286
1308
|
} catch (err) {
|
|
1287
1309
|
console.error("BugBear: Error sending message", err);
|
package/dist/index.mjs
CHANGED
|
@@ -601,19 +601,40 @@ var BugBearClient = class {
|
|
|
601
601
|
return { success: false, error: message };
|
|
602
602
|
}
|
|
603
603
|
}
|
|
604
|
+
/**
|
|
605
|
+
* Pass a test assignment — convenience wrapper around updateAssignmentStatus
|
|
606
|
+
*/
|
|
607
|
+
async passAssignment(assignmentId) {
|
|
608
|
+
return this.updateAssignmentStatus(assignmentId, "passed");
|
|
609
|
+
}
|
|
610
|
+
/**
|
|
611
|
+
* Fail a test assignment — convenience wrapper around updateAssignmentStatus
|
|
612
|
+
*/
|
|
613
|
+
async failAssignment(assignmentId) {
|
|
614
|
+
return this.updateAssignmentStatus(assignmentId, "failed");
|
|
615
|
+
}
|
|
604
616
|
/**
|
|
605
617
|
* Skip a test assignment with a required reason
|
|
606
618
|
* Marks the assignment as 'skipped' and records why it was skipped
|
|
607
619
|
*/
|
|
608
620
|
async skipAssignment(assignmentId, reason, notes) {
|
|
621
|
+
let actualReason;
|
|
622
|
+
let actualNotes;
|
|
623
|
+
if (typeof reason === "object") {
|
|
624
|
+
actualReason = reason.reason;
|
|
625
|
+
actualNotes = reason.notes;
|
|
626
|
+
} else {
|
|
627
|
+
actualReason = reason;
|
|
628
|
+
actualNotes = notes;
|
|
629
|
+
}
|
|
609
630
|
try {
|
|
610
631
|
const updateData = {
|
|
611
632
|
status: "skipped",
|
|
612
|
-
skip_reason:
|
|
633
|
+
skip_reason: actualReason,
|
|
613
634
|
completed_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
614
635
|
};
|
|
615
|
-
if (
|
|
616
|
-
updateData.notes =
|
|
636
|
+
if (actualNotes) {
|
|
637
|
+
updateData.notes = actualNotes;
|
|
617
638
|
}
|
|
618
639
|
const { error } = await this.supabase.from("test_assignments").update(updateData).eq("id", assignmentId);
|
|
619
640
|
if (error) {
|
|
@@ -1253,6 +1274,7 @@ var BugBearClient = class {
|
|
|
1253
1274
|
return false;
|
|
1254
1275
|
}
|
|
1255
1276
|
await this.supabase.from("discussion_threads").update({ last_message_at: (/* @__PURE__ */ new Date()).toISOString() }).eq("id", threadId);
|
|
1277
|
+
await this.markThreadAsRead(threadId);
|
|
1256
1278
|
return true;
|
|
1257
1279
|
} catch (err) {
|
|
1258
1280
|
console.error("BugBear: Error sending message", err);
|