@bbearai/core 0.9.6 → 0.9.8

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.d.mts CHANGED
@@ -413,6 +413,16 @@ interface TestAssignment {
413
413
  isVerification?: boolean;
414
414
  /** Original report ID if this is a verification assignment */
415
415
  originalReportId?: string;
416
+ /** Original bug report data (populated for verification assignments) */
417
+ originalReport?: {
418
+ id: string;
419
+ title: string;
420
+ description: string;
421
+ severity: Severity | null;
422
+ screenshotUrls: string[];
423
+ resolutionNotes?: string;
424
+ route?: string;
425
+ };
416
426
  }
417
427
  interface TestStep {
418
428
  stepNumber: number;
@@ -1280,6 +1290,30 @@ declare class BugBearClient {
1280
1290
  queued?: boolean;
1281
1291
  error?: string;
1282
1292
  }>;
1293
+ /**
1294
+ * Submit feedback about the BugBear widget itself.
1295
+ * Sends to BugBear's own internal project via a dedicated API endpoint.
1296
+ */
1297
+ submitWidgetFeedback(feedback: {
1298
+ description: string;
1299
+ type: 'bug' | 'feedback' | 'suggestion';
1300
+ severity?: Severity;
1301
+ title?: string;
1302
+ screenshots?: string[];
1303
+ }): Promise<{
1304
+ success: boolean;
1305
+ error?: string;
1306
+ }>;
1307
+ /**
1308
+ * Get a pre-authenticated dashboard URL for the given tester email.
1309
+ * Uses a server-generated magic link that bypasses the login page.
1310
+ * Falls back to raw dashboardUrl when no API key is configured.
1311
+ */
1312
+ getDashboardLoginUrl(email: string): Promise<{
1313
+ success: boolean;
1314
+ loginUrl?: string;
1315
+ error?: string;
1316
+ }>;
1283
1317
  /**
1284
1318
  * Capture an email for QA testing.
1285
1319
  * Called by the email interceptor — not typically called directly.
package/dist/index.d.ts CHANGED
@@ -413,6 +413,16 @@ interface TestAssignment {
413
413
  isVerification?: boolean;
414
414
  /** Original report ID if this is a verification assignment */
415
415
  originalReportId?: string;
416
+ /** Original bug report data (populated for verification assignments) */
417
+ originalReport?: {
418
+ id: string;
419
+ title: string;
420
+ description: string;
421
+ severity: Severity | null;
422
+ screenshotUrls: string[];
423
+ resolutionNotes?: string;
424
+ route?: string;
425
+ };
416
426
  }
417
427
  interface TestStep {
418
428
  stepNumber: number;
@@ -1280,6 +1290,30 @@ declare class BugBearClient {
1280
1290
  queued?: boolean;
1281
1291
  error?: string;
1282
1292
  }>;
1293
+ /**
1294
+ * Submit feedback about the BugBear widget itself.
1295
+ * Sends to BugBear's own internal project via a dedicated API endpoint.
1296
+ */
1297
+ submitWidgetFeedback(feedback: {
1298
+ description: string;
1299
+ type: 'bug' | 'feedback' | 'suggestion';
1300
+ severity?: Severity;
1301
+ title?: string;
1302
+ screenshots?: string[];
1303
+ }): Promise<{
1304
+ success: boolean;
1305
+ error?: string;
1306
+ }>;
1307
+ /**
1308
+ * Get a pre-authenticated dashboard URL for the given tester email.
1309
+ * Uses a server-generated magic link that bypasses the login page.
1310
+ * Falls back to raw dashboardUrl when no API key is configured.
1311
+ */
1312
+ getDashboardLoginUrl(email: string): Promise<{
1313
+ success: boolean;
1314
+ loginUrl?: string;
1315
+ error?: string;
1316
+ }>;
1283
1317
  /**
1284
1318
  * Capture an email for QA testing.
1285
1319
  * Called by the email interceptor — not typically called directly.
package/dist/index.js CHANGED
@@ -1417,6 +1417,80 @@ var BugBearClient = class {
1417
1417
  this.reportSubmitInFlight = false;
1418
1418
  }
1419
1419
  }
1420
+ /**
1421
+ * Submit feedback about the BugBear widget itself.
1422
+ * Sends to BugBear's own internal project via a dedicated API endpoint.
1423
+ */
1424
+ async submitWidgetFeedback(feedback) {
1425
+ try {
1426
+ await this.ready();
1427
+ const baseUrl = (this.config.apiBaseUrl || DEFAULT_API_BASE_URL).replace(/\/$/, "");
1428
+ const testerInfo = await this.getTesterInfo();
1429
+ const response = await fetch(`${baseUrl}/api/v1/widget-feedback`, {
1430
+ method: "POST",
1431
+ headers: {
1432
+ "Content-Type": "application/json",
1433
+ ...this.config.apiKey ? { "Authorization": `Bearer ${this.config.apiKey}` } : {}
1434
+ },
1435
+ body: JSON.stringify({
1436
+ description: feedback.description,
1437
+ type: feedback.type,
1438
+ severity: feedback.severity,
1439
+ title: feedback.title,
1440
+ screenshots: feedback.screenshots,
1441
+ deviceInfo: this.getDeviceInfo(),
1442
+ appContext: this.getAppContext(),
1443
+ reporterName: testerInfo?.name || null,
1444
+ reporterEmail: testerInfo?.email || null
1445
+ })
1446
+ });
1447
+ if (!response.ok) {
1448
+ const body = await response.json().catch(() => ({}));
1449
+ return { success: false, error: body.error || `HTTP ${response.status}` };
1450
+ }
1451
+ return { success: true };
1452
+ } catch (err) {
1453
+ const message = err instanceof Error ? err.message : "Widget feedback submission failed";
1454
+ return { success: false, error: message };
1455
+ }
1456
+ }
1457
+ /**
1458
+ * Get a pre-authenticated dashboard URL for the given tester email.
1459
+ * Uses a server-generated magic link that bypasses the login page.
1460
+ * Falls back to raw dashboardUrl when no API key is configured.
1461
+ */
1462
+ async getDashboardLoginUrl(email) {
1463
+ try {
1464
+ if (!this.config.apiKey) {
1465
+ const fallback = this.config.dashboardUrl;
1466
+ if (fallback) return { success: true, loginUrl: fallback };
1467
+ return { success: false, error: "API key required for auto-login" };
1468
+ }
1469
+ await this.ready();
1470
+ const baseUrl = (this.config.apiBaseUrl || DEFAULT_API_BASE_URL).replace(/\/$/, "");
1471
+ const response = await fetch(`${baseUrl}/api/v1/auth/widget-login`, {
1472
+ method: "POST",
1473
+ headers: {
1474
+ "Content-Type": "application/json",
1475
+ "Authorization": `Bearer ${this.config.apiKey}`
1476
+ },
1477
+ body: JSON.stringify({ email })
1478
+ });
1479
+ if (!response.ok) {
1480
+ const body = await response.json().catch(() => ({}));
1481
+ return { success: false, error: body.error || `HTTP ${response.status}` };
1482
+ }
1483
+ const result = await response.json();
1484
+ const loginUrl = result?.data?.loginUrl;
1485
+ if (!loginUrl) {
1486
+ return { success: false, error: "No login URL in response" };
1487
+ }
1488
+ return { success: true, loginUrl };
1489
+ } catch (err) {
1490
+ const message = err instanceof Error ? err.message : "Failed to get dashboard login URL";
1491
+ return { success: false, error: message };
1492
+ }
1493
+ }
1420
1494
  /**
1421
1495
  * Capture an email for QA testing.
1422
1496
  * Called by the email interceptor — not typically called directly.
@@ -1475,6 +1549,15 @@ var BugBearClient = class {
1475
1549
  is_verification,
1476
1550
  original_report_id,
1477
1551
  notes,
1552
+ original_report:reports(
1553
+ id,
1554
+ title,
1555
+ description,
1556
+ severity,
1557
+ screenshot_urls,
1558
+ resolution_notes,
1559
+ app_context
1560
+ ),
1478
1561
  test_case:test_cases(
1479
1562
  id,
1480
1563
  title,
@@ -1524,6 +1607,16 @@ var BugBearClient = class {
1524
1607
  ];
1525
1608
  const mapItem = (item) => {
1526
1609
  const tc = item.test_case;
1610
+ const rpt = item.original_report;
1611
+ const originalReport = rpt ? {
1612
+ id: rpt.id,
1613
+ title: rpt.title,
1614
+ description: rpt.description,
1615
+ severity: rpt.severity,
1616
+ screenshotUrls: rpt.screenshot_urls || [],
1617
+ resolutionNotes: rpt.resolution_notes || void 0,
1618
+ route: rpt.app_context?.currentRoute || void 0
1619
+ } : void 0;
1527
1620
  return {
1528
1621
  id: item.id,
1529
1622
  status: item.status,
@@ -1531,6 +1624,7 @@ var BugBearClient = class {
1531
1624
  skipReason: item.skip_reason,
1532
1625
  isVerification: item.is_verification || false,
1533
1626
  originalReportId: item.original_report_id,
1627
+ originalReport,
1534
1628
  testCase: tc ? {
1535
1629
  id: tc.id,
1536
1630
  title: tc.title,
@@ -1565,15 +1659,15 @@ var BugBearClient = class {
1565
1659
  } : void 0,
1566
1660
  platforms: tc.platforms || void 0
1567
1661
  } : {
1568
- // Standalone verification assignment (bug reported without a test case)
1662
+ // Standalone verification use original report data when available
1569
1663
  id: item.original_report_id || item.id,
1570
- title: item.notes?.replace(/^Verification:\s*/i, "") || "Bug Verification",
1664
+ title: rpt?.title || (item.notes?.replace(/^Verification:\s*/i, "") || "Bug Verification"),
1571
1665
  testKey: "VERIFY",
1572
- description: "Verify that the reported bug has been fixed",
1666
+ description: rpt?.description || "Verify that the reported bug has been fixed",
1573
1667
  steps: [],
1574
1668
  expectedResult: "The bug should no longer be reproducible",
1575
1669
  priority: "P1",
1576
- targetRoute: void 0,
1670
+ targetRoute: rpt?.app_context?.currentRoute || void 0,
1577
1671
  track: void 0,
1578
1672
  group: void 0,
1579
1673
  role: void 0,
@@ -1609,6 +1703,18 @@ var BugBearClient = class {
1609
1703
  started_at,
1610
1704
  completed_at,
1611
1705
  duration_seconds,
1706
+ is_verification,
1707
+ original_report_id,
1708
+ notes,
1709
+ original_report:reports(
1710
+ id,
1711
+ title,
1712
+ description,
1713
+ severity,
1714
+ screenshot_urls,
1715
+ resolution_notes,
1716
+ app_context
1717
+ ),
1612
1718
  test_case:test_cases(
1613
1719
  id,
1614
1720
  title,
@@ -1631,17 +1737,30 @@ var BugBearClient = class {
1631
1737
  `).eq("id", assignmentId).single();
1632
1738
  if (error || !data) return null;
1633
1739
  const testCase = data.test_case;
1634
- if (!testCase) {
1740
+ const rpt = data.original_report;
1741
+ const originalReport = rpt ? {
1742
+ id: rpt.id,
1743
+ title: rpt.title,
1744
+ description: rpt.description,
1745
+ severity: rpt.severity,
1746
+ screenshotUrls: rpt.screenshot_urls || [],
1747
+ resolutionNotes: rpt.resolution_notes || void 0,
1748
+ route: rpt.app_context?.currentRoute || void 0
1749
+ } : void 0;
1750
+ if (!testCase && !data.is_verification) {
1635
1751
  console.error("BugBear: Assignment returned without test_case");
1636
1752
  return null;
1637
1753
  }
1638
- const track = testCase.track;
1754
+ const track = testCase?.track;
1639
1755
  return {
1640
1756
  id: data.id,
1641
1757
  status: data.status,
1642
1758
  startedAt: data.started_at,
1643
1759
  durationSeconds: data.duration_seconds,
1644
- testCase: {
1760
+ isVerification: data.is_verification || false,
1761
+ originalReportId: data.original_report_id,
1762
+ originalReport,
1763
+ testCase: testCase ? {
1645
1764
  id: testCase.id,
1646
1765
  title: testCase.title,
1647
1766
  testKey: testCase.test_key,
@@ -1659,6 +1778,16 @@ var BugBearClient = class {
1659
1778
  rubricMode: track.rubric_mode || "pass_fail",
1660
1779
  description: track.description
1661
1780
  } : void 0
1781
+ } : {
1782
+ id: data.original_report_id || data.id,
1783
+ title: rpt?.title || (data.notes?.replace(/^Verification:\s*/i, "") || "Bug Verification"),
1784
+ testKey: "VERIFY",
1785
+ description: rpt?.description || "Verify that the reported bug has been fixed",
1786
+ steps: [],
1787
+ expectedResult: "The bug should no longer be reproducible",
1788
+ priority: "P1",
1789
+ targetRoute: rpt?.app_context?.currentRoute || void 0,
1790
+ track: void 0
1662
1791
  }
1663
1792
  };
1664
1793
  } catch (err) {
package/dist/index.mjs CHANGED
@@ -1371,6 +1371,80 @@ var BugBearClient = class {
1371
1371
  this.reportSubmitInFlight = false;
1372
1372
  }
1373
1373
  }
1374
+ /**
1375
+ * Submit feedback about the BugBear widget itself.
1376
+ * Sends to BugBear's own internal project via a dedicated API endpoint.
1377
+ */
1378
+ async submitWidgetFeedback(feedback) {
1379
+ try {
1380
+ await this.ready();
1381
+ const baseUrl = (this.config.apiBaseUrl || DEFAULT_API_BASE_URL).replace(/\/$/, "");
1382
+ const testerInfo = await this.getTesterInfo();
1383
+ const response = await fetch(`${baseUrl}/api/v1/widget-feedback`, {
1384
+ method: "POST",
1385
+ headers: {
1386
+ "Content-Type": "application/json",
1387
+ ...this.config.apiKey ? { "Authorization": `Bearer ${this.config.apiKey}` } : {}
1388
+ },
1389
+ body: JSON.stringify({
1390
+ description: feedback.description,
1391
+ type: feedback.type,
1392
+ severity: feedback.severity,
1393
+ title: feedback.title,
1394
+ screenshots: feedback.screenshots,
1395
+ deviceInfo: this.getDeviceInfo(),
1396
+ appContext: this.getAppContext(),
1397
+ reporterName: testerInfo?.name || null,
1398
+ reporterEmail: testerInfo?.email || null
1399
+ })
1400
+ });
1401
+ if (!response.ok) {
1402
+ const body = await response.json().catch(() => ({}));
1403
+ return { success: false, error: body.error || `HTTP ${response.status}` };
1404
+ }
1405
+ return { success: true };
1406
+ } catch (err) {
1407
+ const message = err instanceof Error ? err.message : "Widget feedback submission failed";
1408
+ return { success: false, error: message };
1409
+ }
1410
+ }
1411
+ /**
1412
+ * Get a pre-authenticated dashboard URL for the given tester email.
1413
+ * Uses a server-generated magic link that bypasses the login page.
1414
+ * Falls back to raw dashboardUrl when no API key is configured.
1415
+ */
1416
+ async getDashboardLoginUrl(email) {
1417
+ try {
1418
+ if (!this.config.apiKey) {
1419
+ const fallback = this.config.dashboardUrl;
1420
+ if (fallback) return { success: true, loginUrl: fallback };
1421
+ return { success: false, error: "API key required for auto-login" };
1422
+ }
1423
+ await this.ready();
1424
+ const baseUrl = (this.config.apiBaseUrl || DEFAULT_API_BASE_URL).replace(/\/$/, "");
1425
+ const response = await fetch(`${baseUrl}/api/v1/auth/widget-login`, {
1426
+ method: "POST",
1427
+ headers: {
1428
+ "Content-Type": "application/json",
1429
+ "Authorization": `Bearer ${this.config.apiKey}`
1430
+ },
1431
+ body: JSON.stringify({ email })
1432
+ });
1433
+ if (!response.ok) {
1434
+ const body = await response.json().catch(() => ({}));
1435
+ return { success: false, error: body.error || `HTTP ${response.status}` };
1436
+ }
1437
+ const result = await response.json();
1438
+ const loginUrl = result?.data?.loginUrl;
1439
+ if (!loginUrl) {
1440
+ return { success: false, error: "No login URL in response" };
1441
+ }
1442
+ return { success: true, loginUrl };
1443
+ } catch (err) {
1444
+ const message = err instanceof Error ? err.message : "Failed to get dashboard login URL";
1445
+ return { success: false, error: message };
1446
+ }
1447
+ }
1374
1448
  /**
1375
1449
  * Capture an email for QA testing.
1376
1450
  * Called by the email interceptor — not typically called directly.
@@ -1429,6 +1503,15 @@ var BugBearClient = class {
1429
1503
  is_verification,
1430
1504
  original_report_id,
1431
1505
  notes,
1506
+ original_report:reports(
1507
+ id,
1508
+ title,
1509
+ description,
1510
+ severity,
1511
+ screenshot_urls,
1512
+ resolution_notes,
1513
+ app_context
1514
+ ),
1432
1515
  test_case:test_cases(
1433
1516
  id,
1434
1517
  title,
@@ -1478,6 +1561,16 @@ var BugBearClient = class {
1478
1561
  ];
1479
1562
  const mapItem = (item) => {
1480
1563
  const tc = item.test_case;
1564
+ const rpt = item.original_report;
1565
+ const originalReport = rpt ? {
1566
+ id: rpt.id,
1567
+ title: rpt.title,
1568
+ description: rpt.description,
1569
+ severity: rpt.severity,
1570
+ screenshotUrls: rpt.screenshot_urls || [],
1571
+ resolutionNotes: rpt.resolution_notes || void 0,
1572
+ route: rpt.app_context?.currentRoute || void 0
1573
+ } : void 0;
1481
1574
  return {
1482
1575
  id: item.id,
1483
1576
  status: item.status,
@@ -1485,6 +1578,7 @@ var BugBearClient = class {
1485
1578
  skipReason: item.skip_reason,
1486
1579
  isVerification: item.is_verification || false,
1487
1580
  originalReportId: item.original_report_id,
1581
+ originalReport,
1488
1582
  testCase: tc ? {
1489
1583
  id: tc.id,
1490
1584
  title: tc.title,
@@ -1519,15 +1613,15 @@ var BugBearClient = class {
1519
1613
  } : void 0,
1520
1614
  platforms: tc.platforms || void 0
1521
1615
  } : {
1522
- // Standalone verification assignment (bug reported without a test case)
1616
+ // Standalone verification use original report data when available
1523
1617
  id: item.original_report_id || item.id,
1524
- title: item.notes?.replace(/^Verification:\s*/i, "") || "Bug Verification",
1618
+ title: rpt?.title || (item.notes?.replace(/^Verification:\s*/i, "") || "Bug Verification"),
1525
1619
  testKey: "VERIFY",
1526
- description: "Verify that the reported bug has been fixed",
1620
+ description: rpt?.description || "Verify that the reported bug has been fixed",
1527
1621
  steps: [],
1528
1622
  expectedResult: "The bug should no longer be reproducible",
1529
1623
  priority: "P1",
1530
- targetRoute: void 0,
1624
+ targetRoute: rpt?.app_context?.currentRoute || void 0,
1531
1625
  track: void 0,
1532
1626
  group: void 0,
1533
1627
  role: void 0,
@@ -1563,6 +1657,18 @@ var BugBearClient = class {
1563
1657
  started_at,
1564
1658
  completed_at,
1565
1659
  duration_seconds,
1660
+ is_verification,
1661
+ original_report_id,
1662
+ notes,
1663
+ original_report:reports(
1664
+ id,
1665
+ title,
1666
+ description,
1667
+ severity,
1668
+ screenshot_urls,
1669
+ resolution_notes,
1670
+ app_context
1671
+ ),
1566
1672
  test_case:test_cases(
1567
1673
  id,
1568
1674
  title,
@@ -1585,17 +1691,30 @@ var BugBearClient = class {
1585
1691
  `).eq("id", assignmentId).single();
1586
1692
  if (error || !data) return null;
1587
1693
  const testCase = data.test_case;
1588
- if (!testCase) {
1694
+ const rpt = data.original_report;
1695
+ const originalReport = rpt ? {
1696
+ id: rpt.id,
1697
+ title: rpt.title,
1698
+ description: rpt.description,
1699
+ severity: rpt.severity,
1700
+ screenshotUrls: rpt.screenshot_urls || [],
1701
+ resolutionNotes: rpt.resolution_notes || void 0,
1702
+ route: rpt.app_context?.currentRoute || void 0
1703
+ } : void 0;
1704
+ if (!testCase && !data.is_verification) {
1589
1705
  console.error("BugBear: Assignment returned without test_case");
1590
1706
  return null;
1591
1707
  }
1592
- const track = testCase.track;
1708
+ const track = testCase?.track;
1593
1709
  return {
1594
1710
  id: data.id,
1595
1711
  status: data.status,
1596
1712
  startedAt: data.started_at,
1597
1713
  durationSeconds: data.duration_seconds,
1598
- testCase: {
1714
+ isVerification: data.is_verification || false,
1715
+ originalReportId: data.original_report_id,
1716
+ originalReport,
1717
+ testCase: testCase ? {
1599
1718
  id: testCase.id,
1600
1719
  title: testCase.title,
1601
1720
  testKey: testCase.test_key,
@@ -1613,6 +1732,16 @@ var BugBearClient = class {
1613
1732
  rubricMode: track.rubric_mode || "pass_fail",
1614
1733
  description: track.description
1615
1734
  } : void 0
1735
+ } : {
1736
+ id: data.original_report_id || data.id,
1737
+ title: rpt?.title || (data.notes?.replace(/^Verification:\s*/i, "") || "Bug Verification"),
1738
+ testKey: "VERIFY",
1739
+ description: rpt?.description || "Verify that the reported bug has been fixed",
1740
+ steps: [],
1741
+ expectedResult: "The bug should no longer be reproducible",
1742
+ priority: "P1",
1743
+ targetRoute: rpt?.app_context?.currentRoute || void 0,
1744
+ track: void 0
1616
1745
  }
1617
1746
  };
1618
1747
  } catch (err) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bbearai/core",
3
- "version": "0.9.6",
3
+ "version": "0.9.8",
4
4
  "description": "Core utilities and types for BugBear QA platform",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",