@bbearai/react-native 0.3.6 → 0.3.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.js +316 -167
- package/dist/index.mjs +316 -167
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -11392,6 +11392,239 @@ function shouldShowDeprecationWarning() {
|
|
|
11392
11392
|
if (shouldShowDeprecationWarning()) console.warn("\u26A0\uFE0F Node.js 18 and below are deprecated and will no longer be supported in future versions of @supabase/supabase-js. Please upgrade to Node.js 20 or later. For more information, visit: https://github.com/orgs/supabase/discussions/37217");
|
|
11393
11393
|
|
|
11394
11394
|
// ../core/dist/index.mjs
|
|
11395
|
+
var MAX_CONSOLE_LOGS = 50;
|
|
11396
|
+
var MAX_NETWORK_REQUESTS = 20;
|
|
11397
|
+
var MAX_NAVIGATION_HISTORY = 20;
|
|
11398
|
+
var MAX_RESPONSE_BODY_LENGTH = 500;
|
|
11399
|
+
var ContextCaptureManager = class {
|
|
11400
|
+
constructor() {
|
|
11401
|
+
this.consoleLogs = [];
|
|
11402
|
+
this.networkRequests = [];
|
|
11403
|
+
this.navigationHistory = [];
|
|
11404
|
+
this.originalConsole = {};
|
|
11405
|
+
this.isCapturing = false;
|
|
11406
|
+
}
|
|
11407
|
+
/**
|
|
11408
|
+
* Start capturing console logs, network requests, and navigation
|
|
11409
|
+
*/
|
|
11410
|
+
startCapture() {
|
|
11411
|
+
if (this.isCapturing) return;
|
|
11412
|
+
this.isCapturing = true;
|
|
11413
|
+
this.captureConsole();
|
|
11414
|
+
this.captureFetch();
|
|
11415
|
+
this.captureNavigation();
|
|
11416
|
+
}
|
|
11417
|
+
/**
|
|
11418
|
+
* Stop capturing and restore original functions
|
|
11419
|
+
*/
|
|
11420
|
+
stopCapture() {
|
|
11421
|
+
if (!this.isCapturing) return;
|
|
11422
|
+
this.isCapturing = false;
|
|
11423
|
+
if (this.originalConsole.log) console.log = this.originalConsole.log;
|
|
11424
|
+
if (this.originalConsole.warn) console.warn = this.originalConsole.warn;
|
|
11425
|
+
if (this.originalConsole.error) console.error = this.originalConsole.error;
|
|
11426
|
+
if (this.originalConsole.info) console.info = this.originalConsole.info;
|
|
11427
|
+
if (this.originalFetch && typeof window !== "undefined") {
|
|
11428
|
+
window.fetch = this.originalFetch;
|
|
11429
|
+
}
|
|
11430
|
+
if (typeof window !== "undefined" && typeof history !== "undefined") {
|
|
11431
|
+
if (this.originalPushState) {
|
|
11432
|
+
history.pushState = this.originalPushState;
|
|
11433
|
+
}
|
|
11434
|
+
if (this.originalReplaceState) {
|
|
11435
|
+
history.replaceState = this.originalReplaceState;
|
|
11436
|
+
}
|
|
11437
|
+
if (this.popstateHandler) {
|
|
11438
|
+
window.removeEventListener("popstate", this.popstateHandler);
|
|
11439
|
+
}
|
|
11440
|
+
}
|
|
11441
|
+
}
|
|
11442
|
+
/**
|
|
11443
|
+
* Get captured context for a bug report
|
|
11444
|
+
*/
|
|
11445
|
+
getEnhancedContext() {
|
|
11446
|
+
return {
|
|
11447
|
+
consoleLogs: [...this.consoleLogs],
|
|
11448
|
+
networkRequests: [...this.networkRequests],
|
|
11449
|
+
navigationHistory: [...this.navigationHistory],
|
|
11450
|
+
performanceMetrics: this.getPerformanceMetrics(),
|
|
11451
|
+
environment: this.getEnvironmentInfo()
|
|
11452
|
+
};
|
|
11453
|
+
}
|
|
11454
|
+
/**
|
|
11455
|
+
* Get the auto-captured navigation history
|
|
11456
|
+
*/
|
|
11457
|
+
getNavigationHistory() {
|
|
11458
|
+
return [...this.navigationHistory];
|
|
11459
|
+
}
|
|
11460
|
+
/**
|
|
11461
|
+
* Get the current route (last entry in navigation history, or window.location)
|
|
11462
|
+
*/
|
|
11463
|
+
getCurrentRoute() {
|
|
11464
|
+
if (this.navigationHistory.length > 0) {
|
|
11465
|
+
return this.navigationHistory[this.navigationHistory.length - 1];
|
|
11466
|
+
}
|
|
11467
|
+
if (typeof window !== "undefined") {
|
|
11468
|
+
return window.location.pathname;
|
|
11469
|
+
}
|
|
11470
|
+
return "unknown";
|
|
11471
|
+
}
|
|
11472
|
+
/**
|
|
11473
|
+
* Manually track a navigation event (for React Native or custom routing)
|
|
11474
|
+
*/
|
|
11475
|
+
trackNavigation(route) {
|
|
11476
|
+
const last = this.navigationHistory[this.navigationHistory.length - 1];
|
|
11477
|
+
if (route === last) return;
|
|
11478
|
+
this.navigationHistory.push(route);
|
|
11479
|
+
if (this.navigationHistory.length > MAX_NAVIGATION_HISTORY) {
|
|
11480
|
+
this.navigationHistory.shift();
|
|
11481
|
+
}
|
|
11482
|
+
}
|
|
11483
|
+
/**
|
|
11484
|
+
* Clear captured data
|
|
11485
|
+
*/
|
|
11486
|
+
clear() {
|
|
11487
|
+
this.consoleLogs = [];
|
|
11488
|
+
this.networkRequests = [];
|
|
11489
|
+
this.navigationHistory = [];
|
|
11490
|
+
}
|
|
11491
|
+
/**
|
|
11492
|
+
* Add a log entry manually (for custom logging)
|
|
11493
|
+
*/
|
|
11494
|
+
addLog(level, message, args) {
|
|
11495
|
+
this.consoleLogs.push({
|
|
11496
|
+
level,
|
|
11497
|
+
message,
|
|
11498
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11499
|
+
args
|
|
11500
|
+
});
|
|
11501
|
+
if (this.consoleLogs.length > MAX_CONSOLE_LOGS) {
|
|
11502
|
+
this.consoleLogs = this.consoleLogs.slice(-MAX_CONSOLE_LOGS);
|
|
11503
|
+
}
|
|
11504
|
+
}
|
|
11505
|
+
/**
|
|
11506
|
+
* Add a network request manually
|
|
11507
|
+
*/
|
|
11508
|
+
addNetworkRequest(request) {
|
|
11509
|
+
this.networkRequests.push(request);
|
|
11510
|
+
if (this.networkRequests.length > MAX_NETWORK_REQUESTS) {
|
|
11511
|
+
this.networkRequests = this.networkRequests.slice(-MAX_NETWORK_REQUESTS);
|
|
11512
|
+
}
|
|
11513
|
+
}
|
|
11514
|
+
captureConsole() {
|
|
11515
|
+
if (typeof console === "undefined") return;
|
|
11516
|
+
const levels = ["log", "warn", "error", "info"];
|
|
11517
|
+
levels.forEach((level) => {
|
|
11518
|
+
this.originalConsole[level] = console[level];
|
|
11519
|
+
console[level] = (...args) => {
|
|
11520
|
+
this.originalConsole[level]?.apply(console, args);
|
|
11521
|
+
try {
|
|
11522
|
+
const message = args.map((arg) => {
|
|
11523
|
+
if (typeof arg === "string") return arg;
|
|
11524
|
+
try {
|
|
11525
|
+
return JSON.stringify(arg);
|
|
11526
|
+
} catch {
|
|
11527
|
+
return String(arg);
|
|
11528
|
+
}
|
|
11529
|
+
}).join(" ");
|
|
11530
|
+
this.addLog(level, message.slice(0, 500));
|
|
11531
|
+
} catch {
|
|
11532
|
+
}
|
|
11533
|
+
};
|
|
11534
|
+
});
|
|
11535
|
+
}
|
|
11536
|
+
captureFetch() {
|
|
11537
|
+
if (typeof window === "undefined" || typeof fetch === "undefined") return;
|
|
11538
|
+
this.originalFetch = window.fetch;
|
|
11539
|
+
const self2 = this;
|
|
11540
|
+
window.fetch = async function(input, init) {
|
|
11541
|
+
const startTime = Date.now();
|
|
11542
|
+
const url = typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url;
|
|
11543
|
+
const method = init?.method || "GET";
|
|
11544
|
+
try {
|
|
11545
|
+
const response = await self2.originalFetch.call(window, input, init);
|
|
11546
|
+
const requestEntry = {
|
|
11547
|
+
method,
|
|
11548
|
+
url: url.slice(0, 200),
|
|
11549
|
+
// Limit URL length
|
|
11550
|
+
status: response.status,
|
|
11551
|
+
duration: Date.now() - startTime,
|
|
11552
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
11553
|
+
};
|
|
11554
|
+
if (response.status >= 400) {
|
|
11555
|
+
try {
|
|
11556
|
+
const cloned = response.clone();
|
|
11557
|
+
const body = await cloned.text();
|
|
11558
|
+
if (body) {
|
|
11559
|
+
requestEntry.responseBody = body.slice(0, MAX_RESPONSE_BODY_LENGTH);
|
|
11560
|
+
}
|
|
11561
|
+
} catch {
|
|
11562
|
+
}
|
|
11563
|
+
}
|
|
11564
|
+
self2.addNetworkRequest(requestEntry);
|
|
11565
|
+
return response;
|
|
11566
|
+
} catch (error) {
|
|
11567
|
+
self2.addNetworkRequest({
|
|
11568
|
+
method,
|
|
11569
|
+
url: url.slice(0, 200),
|
|
11570
|
+
duration: Date.now() - startTime,
|
|
11571
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11572
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
11573
|
+
});
|
|
11574
|
+
throw error;
|
|
11575
|
+
}
|
|
11576
|
+
};
|
|
11577
|
+
}
|
|
11578
|
+
captureNavigation() {
|
|
11579
|
+
if (typeof window === "undefined" || typeof history === "undefined") return;
|
|
11580
|
+
this.trackNavigation(window.location.pathname);
|
|
11581
|
+
const self2 = this;
|
|
11582
|
+
this.originalPushState = history.pushState;
|
|
11583
|
+
history.pushState = function(...args) {
|
|
11584
|
+
self2.originalPushState.apply(history, args);
|
|
11585
|
+
self2.trackNavigation(window.location.pathname);
|
|
11586
|
+
};
|
|
11587
|
+
this.originalReplaceState = history.replaceState;
|
|
11588
|
+
history.replaceState = function(...args) {
|
|
11589
|
+
self2.originalReplaceState.apply(history, args);
|
|
11590
|
+
self2.trackNavigation(window.location.pathname);
|
|
11591
|
+
};
|
|
11592
|
+
this.popstateHandler = () => {
|
|
11593
|
+
self2.trackNavigation(window.location.pathname);
|
|
11594
|
+
};
|
|
11595
|
+
window.addEventListener("popstate", this.popstateHandler);
|
|
11596
|
+
}
|
|
11597
|
+
getPerformanceMetrics() {
|
|
11598
|
+
if (typeof window === "undefined" || typeof performance === "undefined") return void 0;
|
|
11599
|
+
const metrics = {};
|
|
11600
|
+
try {
|
|
11601
|
+
const navigation = performance.getEntriesByType("navigation")[0];
|
|
11602
|
+
if (navigation) {
|
|
11603
|
+
metrics.pageLoadTime = Math.round(navigation.loadEventEnd - navigation.startTime);
|
|
11604
|
+
}
|
|
11605
|
+
} catch {
|
|
11606
|
+
}
|
|
11607
|
+
try {
|
|
11608
|
+
const memory = performance.memory;
|
|
11609
|
+
if (memory) {
|
|
11610
|
+
metrics.memoryUsage = Math.round(memory.usedJSHeapSize / 1024 / 1024);
|
|
11611
|
+
}
|
|
11612
|
+
} catch {
|
|
11613
|
+
}
|
|
11614
|
+
return Object.keys(metrics).length > 0 ? metrics : void 0;
|
|
11615
|
+
}
|
|
11616
|
+
getEnvironmentInfo() {
|
|
11617
|
+
if (typeof window === "undefined" || typeof navigator === "undefined") return void 0;
|
|
11618
|
+
return {
|
|
11619
|
+
language: navigator.language,
|
|
11620
|
+
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
11621
|
+
cookiesEnabled: navigator.cookieEnabled,
|
|
11622
|
+
localStorage: typeof localStorage !== "undefined",
|
|
11623
|
+
online: navigator.onLine
|
|
11624
|
+
};
|
|
11625
|
+
}
|
|
11626
|
+
};
|
|
11627
|
+
var contextCapture = new ContextCaptureManager();
|
|
11395
11628
|
var DEFAULT_SUPABASE_URL = "https://kyxgzjnqgvapvlnvqawz.supabase.co";
|
|
11396
11629
|
var getEnvVar = (key) => {
|
|
11397
11630
|
try {
|
|
@@ -11413,22 +11646,40 @@ var BugBearClient = class {
|
|
|
11413
11646
|
);
|
|
11414
11647
|
}
|
|
11415
11648
|
/**
|
|
11416
|
-
* Track navigation for context
|
|
11649
|
+
* Track navigation for context.
|
|
11650
|
+
* Also forwards to contextCapture for auto-tracked navigation.
|
|
11417
11651
|
*/
|
|
11418
11652
|
trackNavigation(route) {
|
|
11419
11653
|
this.navigationHistory.push(route);
|
|
11420
11654
|
if (this.navigationHistory.length > 10) {
|
|
11421
11655
|
this.navigationHistory.shift();
|
|
11422
11656
|
}
|
|
11657
|
+
contextCapture.trackNavigation(route);
|
|
11423
11658
|
}
|
|
11424
11659
|
/**
|
|
11425
|
-
* Get current navigation history
|
|
11660
|
+
* Get current navigation history.
|
|
11661
|
+
* Priority: config callback > manual tracking > auto-captured (pushState/popstate)
|
|
11426
11662
|
*/
|
|
11427
11663
|
getNavigationHistory() {
|
|
11428
11664
|
if (this.config.getNavigationHistory) {
|
|
11429
11665
|
return this.config.getNavigationHistory();
|
|
11430
11666
|
}
|
|
11431
|
-
|
|
11667
|
+
if (this.navigationHistory.length > 0) {
|
|
11668
|
+
return [...this.navigationHistory];
|
|
11669
|
+
}
|
|
11670
|
+
return contextCapture.getNavigationHistory();
|
|
11671
|
+
}
|
|
11672
|
+
/**
|
|
11673
|
+
* Get current app context.
|
|
11674
|
+
* Uses config.getAppContext() callback if provided, otherwise builds from available data.
|
|
11675
|
+
*/
|
|
11676
|
+
getAppContext() {
|
|
11677
|
+
if (this.config.getAppContext) {
|
|
11678
|
+
return this.config.getAppContext();
|
|
11679
|
+
}
|
|
11680
|
+
return {
|
|
11681
|
+
currentRoute: contextCapture.getCurrentRoute()
|
|
11682
|
+
};
|
|
11432
11683
|
}
|
|
11433
11684
|
/**
|
|
11434
11685
|
* Get current user info from host app or BugBear's own auth
|
|
@@ -11468,6 +11719,8 @@ var BugBearClient = class {
|
|
|
11468
11719
|
project_id: this.config.projectId,
|
|
11469
11720
|
reporter_id: userInfo.id,
|
|
11470
11721
|
// User ID from host app (required)
|
|
11722
|
+
reporter_name: testerInfo?.name || userInfo.name || null,
|
|
11723
|
+
reporter_email: userInfo.email || null,
|
|
11471
11724
|
tester_id: testerInfo?.id || null,
|
|
11472
11725
|
// Tester record ID (optional)
|
|
11473
11726
|
report_type: report.type,
|
|
@@ -11481,6 +11734,7 @@ var BugBearClient = class {
|
|
|
11481
11734
|
app_context: report.appContext,
|
|
11482
11735
|
device_info: report.deviceInfo || this.getDeviceInfo(),
|
|
11483
11736
|
navigation_history: this.getNavigationHistory(),
|
|
11737
|
+
enhanced_context: report.enhancedContext || contextCapture.getEnhancedContext(),
|
|
11484
11738
|
assignment_id: report.assignmentId,
|
|
11485
11739
|
test_case_id: report.testCaseId
|
|
11486
11740
|
};
|
|
@@ -11543,7 +11797,7 @@ var BugBearClient = class {
|
|
|
11543
11797
|
console.error("BugBear: Failed to fetch assignments", error);
|
|
11544
11798
|
return [];
|
|
11545
11799
|
}
|
|
11546
|
-
|
|
11800
|
+
const mapped = (data || []).map((item) => ({
|
|
11547
11801
|
id: item.id,
|
|
11548
11802
|
status: item.status,
|
|
11549
11803
|
startedAt: item.started_at,
|
|
@@ -11576,6 +11830,12 @@ var BugBearClient = class {
|
|
|
11576
11830
|
} : void 0
|
|
11577
11831
|
}
|
|
11578
11832
|
}));
|
|
11833
|
+
mapped.sort((a, b) => {
|
|
11834
|
+
if (a.isVerification && !b.isVerification) return -1;
|
|
11835
|
+
if (!a.isVerification && b.isVerification) return 1;
|
|
11836
|
+
return 0;
|
|
11837
|
+
});
|
|
11838
|
+
return mapped;
|
|
11579
11839
|
} catch (err) {
|
|
11580
11840
|
console.error("BugBear: Error fetching assignments", err);
|
|
11581
11841
|
return [];
|
|
@@ -12708,163 +12968,6 @@ var BugBearClient = class {
|
|
|
12708
12968
|
function createBugBear(config) {
|
|
12709
12969
|
return new BugBearClient(config);
|
|
12710
12970
|
}
|
|
12711
|
-
var MAX_CONSOLE_LOGS = 50;
|
|
12712
|
-
var MAX_NETWORK_REQUESTS = 20;
|
|
12713
|
-
var ContextCaptureManager = class {
|
|
12714
|
-
constructor() {
|
|
12715
|
-
this.consoleLogs = [];
|
|
12716
|
-
this.networkRequests = [];
|
|
12717
|
-
this.originalConsole = {};
|
|
12718
|
-
this.isCapturing = false;
|
|
12719
|
-
}
|
|
12720
|
-
/**
|
|
12721
|
-
* Start capturing console logs and network requests
|
|
12722
|
-
*/
|
|
12723
|
-
startCapture() {
|
|
12724
|
-
if (this.isCapturing) return;
|
|
12725
|
-
this.isCapturing = true;
|
|
12726
|
-
this.captureConsole();
|
|
12727
|
-
this.captureFetch();
|
|
12728
|
-
}
|
|
12729
|
-
/**
|
|
12730
|
-
* Stop capturing and restore original functions
|
|
12731
|
-
*/
|
|
12732
|
-
stopCapture() {
|
|
12733
|
-
if (!this.isCapturing) return;
|
|
12734
|
-
this.isCapturing = false;
|
|
12735
|
-
if (this.originalConsole.log) console.log = this.originalConsole.log;
|
|
12736
|
-
if (this.originalConsole.warn) console.warn = this.originalConsole.warn;
|
|
12737
|
-
if (this.originalConsole.error) console.error = this.originalConsole.error;
|
|
12738
|
-
if (this.originalConsole.info) console.info = this.originalConsole.info;
|
|
12739
|
-
if (this.originalFetch && typeof window !== "undefined") {
|
|
12740
|
-
window.fetch = this.originalFetch;
|
|
12741
|
-
}
|
|
12742
|
-
}
|
|
12743
|
-
/**
|
|
12744
|
-
* Get captured context for a bug report
|
|
12745
|
-
*/
|
|
12746
|
-
getEnhancedContext() {
|
|
12747
|
-
return {
|
|
12748
|
-
consoleLogs: [...this.consoleLogs],
|
|
12749
|
-
networkRequests: [...this.networkRequests],
|
|
12750
|
-
performanceMetrics: this.getPerformanceMetrics(),
|
|
12751
|
-
environment: this.getEnvironmentInfo()
|
|
12752
|
-
};
|
|
12753
|
-
}
|
|
12754
|
-
/**
|
|
12755
|
-
* Clear captured data
|
|
12756
|
-
*/
|
|
12757
|
-
clear() {
|
|
12758
|
-
this.consoleLogs = [];
|
|
12759
|
-
this.networkRequests = [];
|
|
12760
|
-
}
|
|
12761
|
-
/**
|
|
12762
|
-
* Add a log entry manually (for custom logging)
|
|
12763
|
-
*/
|
|
12764
|
-
addLog(level, message, args) {
|
|
12765
|
-
this.consoleLogs.push({
|
|
12766
|
-
level,
|
|
12767
|
-
message,
|
|
12768
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12769
|
-
args
|
|
12770
|
-
});
|
|
12771
|
-
if (this.consoleLogs.length > MAX_CONSOLE_LOGS) {
|
|
12772
|
-
this.consoleLogs = this.consoleLogs.slice(-MAX_CONSOLE_LOGS);
|
|
12773
|
-
}
|
|
12774
|
-
}
|
|
12775
|
-
/**
|
|
12776
|
-
* Add a network request manually
|
|
12777
|
-
*/
|
|
12778
|
-
addNetworkRequest(request) {
|
|
12779
|
-
this.networkRequests.push(request);
|
|
12780
|
-
if (this.networkRequests.length > MAX_NETWORK_REQUESTS) {
|
|
12781
|
-
this.networkRequests = this.networkRequests.slice(-MAX_NETWORK_REQUESTS);
|
|
12782
|
-
}
|
|
12783
|
-
}
|
|
12784
|
-
captureConsole() {
|
|
12785
|
-
if (typeof console === "undefined") return;
|
|
12786
|
-
const levels = ["log", "warn", "error", "info"];
|
|
12787
|
-
levels.forEach((level) => {
|
|
12788
|
-
this.originalConsole[level] = console[level];
|
|
12789
|
-
console[level] = (...args) => {
|
|
12790
|
-
this.originalConsole[level]?.apply(console, args);
|
|
12791
|
-
try {
|
|
12792
|
-
const message = args.map((arg) => {
|
|
12793
|
-
if (typeof arg === "string") return arg;
|
|
12794
|
-
try {
|
|
12795
|
-
return JSON.stringify(arg);
|
|
12796
|
-
} catch {
|
|
12797
|
-
return String(arg);
|
|
12798
|
-
}
|
|
12799
|
-
}).join(" ");
|
|
12800
|
-
this.addLog(level, message.slice(0, 500));
|
|
12801
|
-
} catch {
|
|
12802
|
-
}
|
|
12803
|
-
};
|
|
12804
|
-
});
|
|
12805
|
-
}
|
|
12806
|
-
captureFetch() {
|
|
12807
|
-
if (typeof window === "undefined" || typeof fetch === "undefined") return;
|
|
12808
|
-
this.originalFetch = window.fetch;
|
|
12809
|
-
const self2 = this;
|
|
12810
|
-
window.fetch = async function(input, init) {
|
|
12811
|
-
const startTime = Date.now();
|
|
12812
|
-
const url = typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url;
|
|
12813
|
-
const method = init?.method || "GET";
|
|
12814
|
-
try {
|
|
12815
|
-
const response = await self2.originalFetch.call(window, input, init);
|
|
12816
|
-
self2.addNetworkRequest({
|
|
12817
|
-
method,
|
|
12818
|
-
url: url.slice(0, 200),
|
|
12819
|
-
// Limit URL length
|
|
12820
|
-
status: response.status,
|
|
12821
|
-
duration: Date.now() - startTime,
|
|
12822
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
12823
|
-
});
|
|
12824
|
-
return response;
|
|
12825
|
-
} catch (error) {
|
|
12826
|
-
self2.addNetworkRequest({
|
|
12827
|
-
method,
|
|
12828
|
-
url: url.slice(0, 200),
|
|
12829
|
-
duration: Date.now() - startTime,
|
|
12830
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12831
|
-
error: error instanceof Error ? error.message : "Unknown error"
|
|
12832
|
-
});
|
|
12833
|
-
throw error;
|
|
12834
|
-
}
|
|
12835
|
-
};
|
|
12836
|
-
}
|
|
12837
|
-
getPerformanceMetrics() {
|
|
12838
|
-
if (typeof window === "undefined" || typeof performance === "undefined") return void 0;
|
|
12839
|
-
const metrics = {};
|
|
12840
|
-
try {
|
|
12841
|
-
const navigation = performance.getEntriesByType("navigation")[0];
|
|
12842
|
-
if (navigation) {
|
|
12843
|
-
metrics.pageLoadTime = Math.round(navigation.loadEventEnd - navigation.startTime);
|
|
12844
|
-
}
|
|
12845
|
-
} catch {
|
|
12846
|
-
}
|
|
12847
|
-
try {
|
|
12848
|
-
const memory = performance.memory;
|
|
12849
|
-
if (memory) {
|
|
12850
|
-
metrics.memoryUsage = Math.round(memory.usedJSHeapSize / 1024 / 1024);
|
|
12851
|
-
}
|
|
12852
|
-
} catch {
|
|
12853
|
-
}
|
|
12854
|
-
return Object.keys(metrics).length > 0 ? metrics : void 0;
|
|
12855
|
-
}
|
|
12856
|
-
getEnvironmentInfo() {
|
|
12857
|
-
if (typeof window === "undefined" || typeof navigator === "undefined") return void 0;
|
|
12858
|
-
return {
|
|
12859
|
-
language: navigator.language,
|
|
12860
|
-
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
12861
|
-
cookiesEnabled: navigator.cookieEnabled,
|
|
12862
|
-
localStorage: typeof localStorage !== "undefined",
|
|
12863
|
-
online: navigator.onLine
|
|
12864
|
-
};
|
|
12865
|
-
}
|
|
12866
|
-
};
|
|
12867
|
-
var contextCapture = new ContextCaptureManager();
|
|
12868
12971
|
|
|
12869
12972
|
// src/BugBearProvider.tsx
|
|
12870
12973
|
var import_react_native = require("react-native");
|
|
@@ -13065,6 +13168,7 @@ function BugBearProvider({ config, children, appVersion, enabled = true }) {
|
|
|
13065
13168
|
(0, import_react.useEffect)(() => {
|
|
13066
13169
|
if (enabled && !hasInitialized.current) {
|
|
13067
13170
|
hasInitialized.current = true;
|
|
13171
|
+
contextCapture.startCapture();
|
|
13068
13172
|
const newClient = createBugBear(config);
|
|
13069
13173
|
setClient(newClient);
|
|
13070
13174
|
initializeBugBear(newClient);
|
|
@@ -13344,7 +13448,9 @@ function HomeScreen({ nav }) {
|
|
|
13344
13448
|
refreshAssignments();
|
|
13345
13449
|
refreshThreads();
|
|
13346
13450
|
}, []);
|
|
13347
|
-
const
|
|
13451
|
+
const pendingAssignments = assignments.filter((a) => a.status === "pending" || a.status === "in_progress");
|
|
13452
|
+
const pendingCount = pendingAssignments.length;
|
|
13453
|
+
const retestCount = pendingAssignments.filter((a) => a.isVerification).length;
|
|
13348
13454
|
const completedCount = assignments.filter((a) => a.status === "passed" || a.status === "failed").length;
|
|
13349
13455
|
const totalTests = assignments.length;
|
|
13350
13456
|
return /* @__PURE__ */ import_react3.default.createElement(import_react_native3.View, null, pendingCount > 0 ? /* @__PURE__ */ import_react3.default.createElement(
|
|
@@ -13356,6 +13462,7 @@ function HomeScreen({ nav }) {
|
|
|
13356
13462
|
},
|
|
13357
13463
|
/* @__PURE__ */ import_react3.default.createElement(import_react_native3.Text, { style: styles.heroCount }, pendingCount),
|
|
13358
13464
|
/* @__PURE__ */ import_react3.default.createElement(import_react_native3.Text, { style: styles.heroLabel }, "test", pendingCount !== 1 ? "s" : "", " waiting"),
|
|
13465
|
+
retestCount > 0 && /* @__PURE__ */ import_react3.default.createElement(import_react_native3.View, { style: styles.retestPill }, /* @__PURE__ */ import_react3.default.createElement(import_react_native3.Text, { style: styles.retestPillText }, "\u{1F504} ", retestCount, " retest", retestCount !== 1 ? "s" : "")),
|
|
13359
13466
|
/* @__PURE__ */ import_react3.default.createElement(import_react_native3.Text, { style: styles.heroAction }, "Start Testing \u2192")
|
|
13360
13467
|
) : unreadCount > 0 ? /* @__PURE__ */ import_react3.default.createElement(
|
|
13361
13468
|
import_react_native3.TouchableOpacity,
|
|
@@ -13459,6 +13566,22 @@ var styles = import_react_native3.StyleSheet.create({
|
|
|
13459
13566
|
color: colors.blueText,
|
|
13460
13567
|
marginTop: 2
|
|
13461
13568
|
},
|
|
13569
|
+
retestPill: {
|
|
13570
|
+
flexDirection: "row",
|
|
13571
|
+
alignItems: "center",
|
|
13572
|
+
backgroundColor: "#422006",
|
|
13573
|
+
borderWidth: 1,
|
|
13574
|
+
borderColor: "#854d0e",
|
|
13575
|
+
borderRadius: 6,
|
|
13576
|
+
paddingHorizontal: 8,
|
|
13577
|
+
paddingVertical: 3,
|
|
13578
|
+
marginTop: 8
|
|
13579
|
+
},
|
|
13580
|
+
retestPillText: {
|
|
13581
|
+
fontSize: 12,
|
|
13582
|
+
fontWeight: "600",
|
|
13583
|
+
color: "#fbbf24"
|
|
13584
|
+
},
|
|
13462
13585
|
heroAction: {
|
|
13463
13586
|
fontSize: 14,
|
|
13464
13587
|
fontWeight: "600",
|
|
@@ -13669,7 +13792,7 @@ function TestDetailScreen({ testId, nav }) {
|
|
|
13669
13792
|
const steps = testCase.steps;
|
|
13670
13793
|
const info = templateInfo[template] || templateInfo.steps;
|
|
13671
13794
|
const rubricMode = testCase.track?.rubricMode || "pass_fail";
|
|
13672
|
-
return /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { style: styles2.container }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { style: styles2.topRow }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { style: styles2.positionInfo }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.positionText }, "Test ", currentIndex + 1, " of ", allTests.length), displayedAssignment.status === "in_progress" && assignmentElapsedTime > 0 && /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { style: styles2.timerBadge }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.timerText }, formatElapsedTime(assignmentElapsedTime)))), /* @__PURE__ */ import_react4.default.createElement(import_react_native4.TouchableOpacity, { onPress: () => nav.push({ name: "TEST_LIST" }) }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.viewAllLink }, "View All \u2192"))), /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.testTitle }, testCase.title), testCase.key && /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.testKey }, testCase.key), /* @__PURE__ */ import_react4.default.createElement(import_react_native4.TouchableOpacity, { onPress: () => setShowSteps(!showSteps), style: styles2.sectionHeader }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.sectionHeaderText }, showSteps ? "\u25BC" : "\u25B6", " ", info.icon, " ", template === "freeform" ? "Instructions" : `${steps.length} ${template === "checklist" ? "items" : template === "rubric" ? "criteria" : "steps"}`)), showSteps && /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { style: styles2.templateContent }, template === "steps" && steps.map((step, idx) => /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { key: idx, style: styles2.step }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { style: styles2.stepNumber }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.stepNumberText }, step.stepNumber)), /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { style: styles2.stepBody }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.stepAction }, step.action), step.expectedResult && /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.stepExpected }, "\u2192 ", step.expectedResult)))), template === "checklist" && /* @__PURE__ */ import_react4.default.createElement(import_react4.default.Fragment, null, steps.map((step, idx) => /* @__PURE__ */ import_react4.default.createElement(
|
|
13795
|
+
return /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { style: styles2.container }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { style: styles2.topRow }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { style: styles2.positionInfo }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.positionText }, "Test ", currentIndex + 1, " of ", allTests.length), displayedAssignment.status === "in_progress" && assignmentElapsedTime > 0 && /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { style: styles2.timerBadge }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.timerText }, formatElapsedTime(assignmentElapsedTime)))), /* @__PURE__ */ import_react4.default.createElement(import_react_native4.TouchableOpacity, { onPress: () => nav.push({ name: "TEST_LIST" }) }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.viewAllLink }, "View All \u2192"))), displayedAssignment.isVerification && /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { style: styles2.retestBanner }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.retestIcon }, "\u{1F504}"), /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.retestLabel }, "Retest"), /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.retestSub }, "\u2014 Verify bug fix")), /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.testTitle }, testCase.title), testCase.key && /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.testKey }, testCase.key), /* @__PURE__ */ import_react4.default.createElement(import_react_native4.TouchableOpacity, { onPress: () => setShowSteps(!showSteps), style: styles2.sectionHeader }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.sectionHeaderText }, showSteps ? "\u25BC" : "\u25B6", " ", info.icon, " ", template === "freeform" ? "Instructions" : `${steps.length} ${template === "checklist" ? "items" : template === "rubric" ? "criteria" : "steps"}`)), showSteps && /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { style: styles2.templateContent }, template === "steps" && steps.map((step, idx) => /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { key: idx, style: styles2.step }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { style: styles2.stepNumber }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.stepNumberText }, step.stepNumber)), /* @__PURE__ */ import_react4.default.createElement(import_react_native4.View, { style: styles2.stepBody }, /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.stepAction }, step.action), step.expectedResult && /* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.stepExpected }, "\u2192 ", step.expectedResult)))), template === "checklist" && /* @__PURE__ */ import_react4.default.createElement(import_react4.default.Fragment, null, steps.map((step, idx) => /* @__PURE__ */ import_react4.default.createElement(
|
|
13673
13796
|
import_react_native4.TouchableOpacity,
|
|
13674
13797
|
{
|
|
13675
13798
|
key: idx,
|
|
@@ -13753,6 +13876,10 @@ function TestDetailScreen({ testId, nav }) {
|
|
|
13753
13876
|
}
|
|
13754
13877
|
var styles2 = import_react_native4.StyleSheet.create({
|
|
13755
13878
|
container: { paddingBottom: 16 },
|
|
13879
|
+
retestBanner: { flexDirection: "row", alignItems: "center", gap: 6, backgroundColor: "#422006", borderWidth: 1, borderColor: "#854d0e", borderRadius: 8, paddingVertical: 6, paddingHorizontal: 10, marginBottom: 10 },
|
|
13880
|
+
retestIcon: { fontSize: 14 },
|
|
13881
|
+
retestLabel: { fontSize: 13, fontWeight: "600", color: "#fbbf24" },
|
|
13882
|
+
retestSub: { fontSize: 12, color: "#d97706" },
|
|
13756
13883
|
topRow: { flexDirection: "row", justifyContent: "space-between", alignItems: "center", marginBottom: 12 },
|
|
13757
13884
|
positionInfo: { flexDirection: "row", alignItems: "center", gap: 8 },
|
|
13758
13885
|
positionText: { fontSize: 13, color: colors.textMuted },
|
|
@@ -13868,6 +13995,8 @@ function TestListScreen({ nav }) {
|
|
|
13868
13995
|
const statusOrder = { in_progress: 0, pending: 1, failed: 2, skipped: 3, passed: 4 };
|
|
13869
13996
|
for (const folder of groups.values()) {
|
|
13870
13997
|
folder.assignments.sort((a, b) => {
|
|
13998
|
+
if (a.isVerification && !b.isVerification) return -1;
|
|
13999
|
+
if (!a.isVerification && b.isVerification) return 1;
|
|
13871
14000
|
const sd = (statusOrder[a.status] ?? 5) - (statusOrder[b.status] ?? 5);
|
|
13872
14001
|
if (sd !== 0) return sd;
|
|
13873
14002
|
return (priorityOrder[a.testCase.priority] ?? 4) - (priorityOrder[b.testCase.priority] ?? 4);
|
|
@@ -13909,7 +14038,7 @@ function TestListScreen({ nav }) {
|
|
|
13909
14038
|
onPress: () => nav.push({ name: "TEST_DETAIL", testId: assignment.id })
|
|
13910
14039
|
},
|
|
13911
14040
|
/* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles3.testBadge }, badge.icon),
|
|
13912
|
-
/* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: styles3.testInfo }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles3.testTitle, numberOfLines: 1 }, assignment.testCase.title), /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles3.testMeta }, assignment.testCase.key, " \xB7 ", assignment.testCase.priority))
|
|
14041
|
+
/* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: styles3.testInfo }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles3.testTitle, numberOfLines: 1 }, assignment.testCase.title), /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: styles3.testMetaRow }, assignment.isVerification && /* @__PURE__ */ import_react5.default.createElement(import_react_native5.View, { style: styles3.retestTag }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles3.retestTagText }, "Retest")), /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles3.testMeta }, assignment.testCase.key, " \xB7 ", assignment.testCase.priority)))
|
|
13913
14042
|
);
|
|
13914
14043
|
}));
|
|
13915
14044
|
}), /* @__PURE__ */ import_react5.default.createElement(import_react_native5.TouchableOpacity, { style: styles3.refreshBtn, onPress: refreshAssignments }, /* @__PURE__ */ import_react5.default.createElement(import_react_native5.Text, { style: styles3.refreshText }, "\u21BB Refresh")));
|
|
@@ -13932,6 +14061,9 @@ var styles3 = import_react_native5.StyleSheet.create({
|
|
|
13932
14061
|
testBadge: { fontSize: 16, marginRight: 10, width: 20 },
|
|
13933
14062
|
testInfo: { flex: 1 },
|
|
13934
14063
|
testTitle: { fontSize: 14, color: colors.textPrimary, marginBottom: 2 },
|
|
14064
|
+
testMetaRow: { flexDirection: "row", alignItems: "center", gap: 6 },
|
|
14065
|
+
retestTag: { backgroundColor: "#422006", borderWidth: 1, borderColor: "#854d0e", borderRadius: 4, paddingHorizontal: 5, paddingVertical: 1 },
|
|
14066
|
+
retestTagText: { fontSize: 10, fontWeight: "600", color: "#fbbf24" },
|
|
13935
14067
|
testMeta: { fontSize: 11, color: colors.textDim },
|
|
13936
14068
|
refreshBtn: { alignItems: "center", paddingVertical: 12 },
|
|
13937
14069
|
refreshText: { fontSize: 13, color: colors.blue }
|
|
@@ -14262,12 +14394,18 @@ function ReportScreen({ nav, prefill }) {
|
|
|
14262
14394
|
const [reportType, setReportType] = (0, import_react10.useState)(prefill?.type || "bug");
|
|
14263
14395
|
const [severity, setSeverity] = (0, import_react10.useState)("medium");
|
|
14264
14396
|
const [description, setDescription] = (0, import_react10.useState)("");
|
|
14397
|
+
const [affectedScreen, setAffectedScreen] = (0, import_react10.useState)("");
|
|
14265
14398
|
const [submitting, setSubmitting] = (0, import_react10.useState)(false);
|
|
14266
14399
|
const images = useImageAttachments(uploadImage, 5, "screenshots");
|
|
14267
14400
|
const isBugType = reportType === "bug" || reportType === "test_fail";
|
|
14268
14401
|
const handleSubmit = async () => {
|
|
14269
14402
|
if (!client || !description.trim()) return;
|
|
14270
14403
|
setSubmitting(true);
|
|
14404
|
+
const baseContext = client.getAppContext();
|
|
14405
|
+
const appContext = {
|
|
14406
|
+
...baseContext,
|
|
14407
|
+
currentRoute: affectedScreen.trim() || baseContext.currentRoute
|
|
14408
|
+
};
|
|
14271
14409
|
const screenshotUrls = images.getScreenshotUrls();
|
|
14272
14410
|
await client.submitReport({
|
|
14273
14411
|
type: reportType,
|
|
@@ -14275,7 +14413,7 @@ function ReportScreen({ nav, prefill }) {
|
|
|
14275
14413
|
severity: isBugType ? severity : void 0,
|
|
14276
14414
|
assignmentId: prefill?.assignmentId,
|
|
14277
14415
|
testCaseId: prefill?.testCaseId,
|
|
14278
|
-
appContext
|
|
14416
|
+
appContext,
|
|
14279
14417
|
deviceInfo: getDeviceInfo(),
|
|
14280
14418
|
screenshots: screenshotUrls.length > 0 ? screenshotUrls : void 0
|
|
14281
14419
|
});
|
|
@@ -14323,7 +14461,16 @@ function ReportScreen({ nav, prefill }) {
|
|
|
14323
14461
|
numberOfLines: 4,
|
|
14324
14462
|
textAlignVertical: "top"
|
|
14325
14463
|
}
|
|
14326
|
-
)), /* @__PURE__ */ import_react10.default.createElement(
|
|
14464
|
+
)), isBugType && /* @__PURE__ */ import_react10.default.createElement(import_react_native9.View, { style: styles7.section }, /* @__PURE__ */ import_react10.default.createElement(import_react_native9.Text, { style: shared.label }, "Which screen?"), /* @__PURE__ */ import_react10.default.createElement(
|
|
14465
|
+
import_react_native9.TextInput,
|
|
14466
|
+
{
|
|
14467
|
+
style: styles7.screenInput,
|
|
14468
|
+
value: affectedScreen,
|
|
14469
|
+
onChangeText: setAffectedScreen,
|
|
14470
|
+
placeholder: "e.g. Reservations, Settings...",
|
|
14471
|
+
placeholderTextColor: colors.textMuted
|
|
14472
|
+
}
|
|
14473
|
+
), /* @__PURE__ */ import_react10.default.createElement(import_react_native9.Text, { style: styles7.screenHint }, "Which screen or area was the bug on? (optional)")), /* @__PURE__ */ import_react10.default.createElement(
|
|
14327
14474
|
ImagePickerButtons,
|
|
14328
14475
|
{
|
|
14329
14476
|
images: images.images,
|
|
@@ -14354,7 +14501,9 @@ var styles7 = import_react_native9.StyleSheet.create({
|
|
|
14354
14501
|
severityRow: { flexDirection: "row", gap: 8 },
|
|
14355
14502
|
sevButton: { flex: 1, paddingVertical: 8, borderRadius: 8, alignItems: "center", borderWidth: 1, borderColor: colors.border, backgroundColor: colors.card },
|
|
14356
14503
|
sevText: { fontSize: 12, fontWeight: "500", color: colors.textSecondary, textTransform: "capitalize" },
|
|
14357
|
-
descInput: { backgroundColor: colors.card, borderWidth: 1, borderColor: colors.border, borderRadius: 12, paddingHorizontal: 14, paddingVertical: 12, fontSize: 14, color: colors.textPrimary, minHeight: 100 }
|
|
14504
|
+
descInput: { backgroundColor: colors.card, borderWidth: 1, borderColor: colors.border, borderRadius: 12, paddingHorizontal: 14, paddingVertical: 12, fontSize: 14, color: colors.textPrimary, minHeight: 100 },
|
|
14505
|
+
screenInput: { backgroundColor: colors.card, borderWidth: 1, borderColor: colors.border, borderRadius: 8, paddingHorizontal: 12, paddingVertical: 8, fontSize: 13, color: colors.textPrimary },
|
|
14506
|
+
screenHint: { fontSize: 11, color: colors.textMuted, marginTop: 4 }
|
|
14358
14507
|
});
|
|
14359
14508
|
|
|
14360
14509
|
// src/widget/screens/ReportSuccessScreen.tsx
|
package/dist/index.mjs
CHANGED
|
@@ -11361,6 +11361,239 @@ function shouldShowDeprecationWarning() {
|
|
|
11361
11361
|
if (shouldShowDeprecationWarning()) console.warn("\u26A0\uFE0F Node.js 18 and below are deprecated and will no longer be supported in future versions of @supabase/supabase-js. Please upgrade to Node.js 20 or later. For more information, visit: https://github.com/orgs/supabase/discussions/37217");
|
|
11362
11362
|
|
|
11363
11363
|
// ../core/dist/index.mjs
|
|
11364
|
+
var MAX_CONSOLE_LOGS = 50;
|
|
11365
|
+
var MAX_NETWORK_REQUESTS = 20;
|
|
11366
|
+
var MAX_NAVIGATION_HISTORY = 20;
|
|
11367
|
+
var MAX_RESPONSE_BODY_LENGTH = 500;
|
|
11368
|
+
var ContextCaptureManager = class {
|
|
11369
|
+
constructor() {
|
|
11370
|
+
this.consoleLogs = [];
|
|
11371
|
+
this.networkRequests = [];
|
|
11372
|
+
this.navigationHistory = [];
|
|
11373
|
+
this.originalConsole = {};
|
|
11374
|
+
this.isCapturing = false;
|
|
11375
|
+
}
|
|
11376
|
+
/**
|
|
11377
|
+
* Start capturing console logs, network requests, and navigation
|
|
11378
|
+
*/
|
|
11379
|
+
startCapture() {
|
|
11380
|
+
if (this.isCapturing) return;
|
|
11381
|
+
this.isCapturing = true;
|
|
11382
|
+
this.captureConsole();
|
|
11383
|
+
this.captureFetch();
|
|
11384
|
+
this.captureNavigation();
|
|
11385
|
+
}
|
|
11386
|
+
/**
|
|
11387
|
+
* Stop capturing and restore original functions
|
|
11388
|
+
*/
|
|
11389
|
+
stopCapture() {
|
|
11390
|
+
if (!this.isCapturing) return;
|
|
11391
|
+
this.isCapturing = false;
|
|
11392
|
+
if (this.originalConsole.log) console.log = this.originalConsole.log;
|
|
11393
|
+
if (this.originalConsole.warn) console.warn = this.originalConsole.warn;
|
|
11394
|
+
if (this.originalConsole.error) console.error = this.originalConsole.error;
|
|
11395
|
+
if (this.originalConsole.info) console.info = this.originalConsole.info;
|
|
11396
|
+
if (this.originalFetch && typeof window !== "undefined") {
|
|
11397
|
+
window.fetch = this.originalFetch;
|
|
11398
|
+
}
|
|
11399
|
+
if (typeof window !== "undefined" && typeof history !== "undefined") {
|
|
11400
|
+
if (this.originalPushState) {
|
|
11401
|
+
history.pushState = this.originalPushState;
|
|
11402
|
+
}
|
|
11403
|
+
if (this.originalReplaceState) {
|
|
11404
|
+
history.replaceState = this.originalReplaceState;
|
|
11405
|
+
}
|
|
11406
|
+
if (this.popstateHandler) {
|
|
11407
|
+
window.removeEventListener("popstate", this.popstateHandler);
|
|
11408
|
+
}
|
|
11409
|
+
}
|
|
11410
|
+
}
|
|
11411
|
+
/**
|
|
11412
|
+
* Get captured context for a bug report
|
|
11413
|
+
*/
|
|
11414
|
+
getEnhancedContext() {
|
|
11415
|
+
return {
|
|
11416
|
+
consoleLogs: [...this.consoleLogs],
|
|
11417
|
+
networkRequests: [...this.networkRequests],
|
|
11418
|
+
navigationHistory: [...this.navigationHistory],
|
|
11419
|
+
performanceMetrics: this.getPerformanceMetrics(),
|
|
11420
|
+
environment: this.getEnvironmentInfo()
|
|
11421
|
+
};
|
|
11422
|
+
}
|
|
11423
|
+
/**
|
|
11424
|
+
* Get the auto-captured navigation history
|
|
11425
|
+
*/
|
|
11426
|
+
getNavigationHistory() {
|
|
11427
|
+
return [...this.navigationHistory];
|
|
11428
|
+
}
|
|
11429
|
+
/**
|
|
11430
|
+
* Get the current route (last entry in navigation history, or window.location)
|
|
11431
|
+
*/
|
|
11432
|
+
getCurrentRoute() {
|
|
11433
|
+
if (this.navigationHistory.length > 0) {
|
|
11434
|
+
return this.navigationHistory[this.navigationHistory.length - 1];
|
|
11435
|
+
}
|
|
11436
|
+
if (typeof window !== "undefined") {
|
|
11437
|
+
return window.location.pathname;
|
|
11438
|
+
}
|
|
11439
|
+
return "unknown";
|
|
11440
|
+
}
|
|
11441
|
+
/**
|
|
11442
|
+
* Manually track a navigation event (for React Native or custom routing)
|
|
11443
|
+
*/
|
|
11444
|
+
trackNavigation(route) {
|
|
11445
|
+
const last = this.navigationHistory[this.navigationHistory.length - 1];
|
|
11446
|
+
if (route === last) return;
|
|
11447
|
+
this.navigationHistory.push(route);
|
|
11448
|
+
if (this.navigationHistory.length > MAX_NAVIGATION_HISTORY) {
|
|
11449
|
+
this.navigationHistory.shift();
|
|
11450
|
+
}
|
|
11451
|
+
}
|
|
11452
|
+
/**
|
|
11453
|
+
* Clear captured data
|
|
11454
|
+
*/
|
|
11455
|
+
clear() {
|
|
11456
|
+
this.consoleLogs = [];
|
|
11457
|
+
this.networkRequests = [];
|
|
11458
|
+
this.navigationHistory = [];
|
|
11459
|
+
}
|
|
11460
|
+
/**
|
|
11461
|
+
* Add a log entry manually (for custom logging)
|
|
11462
|
+
*/
|
|
11463
|
+
addLog(level, message, args) {
|
|
11464
|
+
this.consoleLogs.push({
|
|
11465
|
+
level,
|
|
11466
|
+
message,
|
|
11467
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11468
|
+
args
|
|
11469
|
+
});
|
|
11470
|
+
if (this.consoleLogs.length > MAX_CONSOLE_LOGS) {
|
|
11471
|
+
this.consoleLogs = this.consoleLogs.slice(-MAX_CONSOLE_LOGS);
|
|
11472
|
+
}
|
|
11473
|
+
}
|
|
11474
|
+
/**
|
|
11475
|
+
* Add a network request manually
|
|
11476
|
+
*/
|
|
11477
|
+
addNetworkRequest(request) {
|
|
11478
|
+
this.networkRequests.push(request);
|
|
11479
|
+
if (this.networkRequests.length > MAX_NETWORK_REQUESTS) {
|
|
11480
|
+
this.networkRequests = this.networkRequests.slice(-MAX_NETWORK_REQUESTS);
|
|
11481
|
+
}
|
|
11482
|
+
}
|
|
11483
|
+
captureConsole() {
|
|
11484
|
+
if (typeof console === "undefined") return;
|
|
11485
|
+
const levels = ["log", "warn", "error", "info"];
|
|
11486
|
+
levels.forEach((level) => {
|
|
11487
|
+
this.originalConsole[level] = console[level];
|
|
11488
|
+
console[level] = (...args) => {
|
|
11489
|
+
this.originalConsole[level]?.apply(console, args);
|
|
11490
|
+
try {
|
|
11491
|
+
const message = args.map((arg) => {
|
|
11492
|
+
if (typeof arg === "string") return arg;
|
|
11493
|
+
try {
|
|
11494
|
+
return JSON.stringify(arg);
|
|
11495
|
+
} catch {
|
|
11496
|
+
return String(arg);
|
|
11497
|
+
}
|
|
11498
|
+
}).join(" ");
|
|
11499
|
+
this.addLog(level, message.slice(0, 500));
|
|
11500
|
+
} catch {
|
|
11501
|
+
}
|
|
11502
|
+
};
|
|
11503
|
+
});
|
|
11504
|
+
}
|
|
11505
|
+
captureFetch() {
|
|
11506
|
+
if (typeof window === "undefined" || typeof fetch === "undefined") return;
|
|
11507
|
+
this.originalFetch = window.fetch;
|
|
11508
|
+
const self2 = this;
|
|
11509
|
+
window.fetch = async function(input, init) {
|
|
11510
|
+
const startTime = Date.now();
|
|
11511
|
+
const url = typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url;
|
|
11512
|
+
const method = init?.method || "GET";
|
|
11513
|
+
try {
|
|
11514
|
+
const response = await self2.originalFetch.call(window, input, init);
|
|
11515
|
+
const requestEntry = {
|
|
11516
|
+
method,
|
|
11517
|
+
url: url.slice(0, 200),
|
|
11518
|
+
// Limit URL length
|
|
11519
|
+
status: response.status,
|
|
11520
|
+
duration: Date.now() - startTime,
|
|
11521
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
11522
|
+
};
|
|
11523
|
+
if (response.status >= 400) {
|
|
11524
|
+
try {
|
|
11525
|
+
const cloned = response.clone();
|
|
11526
|
+
const body = await cloned.text();
|
|
11527
|
+
if (body) {
|
|
11528
|
+
requestEntry.responseBody = body.slice(0, MAX_RESPONSE_BODY_LENGTH);
|
|
11529
|
+
}
|
|
11530
|
+
} catch {
|
|
11531
|
+
}
|
|
11532
|
+
}
|
|
11533
|
+
self2.addNetworkRequest(requestEntry);
|
|
11534
|
+
return response;
|
|
11535
|
+
} catch (error) {
|
|
11536
|
+
self2.addNetworkRequest({
|
|
11537
|
+
method,
|
|
11538
|
+
url: url.slice(0, 200),
|
|
11539
|
+
duration: Date.now() - startTime,
|
|
11540
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11541
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
11542
|
+
});
|
|
11543
|
+
throw error;
|
|
11544
|
+
}
|
|
11545
|
+
};
|
|
11546
|
+
}
|
|
11547
|
+
captureNavigation() {
|
|
11548
|
+
if (typeof window === "undefined" || typeof history === "undefined") return;
|
|
11549
|
+
this.trackNavigation(window.location.pathname);
|
|
11550
|
+
const self2 = this;
|
|
11551
|
+
this.originalPushState = history.pushState;
|
|
11552
|
+
history.pushState = function(...args) {
|
|
11553
|
+
self2.originalPushState.apply(history, args);
|
|
11554
|
+
self2.trackNavigation(window.location.pathname);
|
|
11555
|
+
};
|
|
11556
|
+
this.originalReplaceState = history.replaceState;
|
|
11557
|
+
history.replaceState = function(...args) {
|
|
11558
|
+
self2.originalReplaceState.apply(history, args);
|
|
11559
|
+
self2.trackNavigation(window.location.pathname);
|
|
11560
|
+
};
|
|
11561
|
+
this.popstateHandler = () => {
|
|
11562
|
+
self2.trackNavigation(window.location.pathname);
|
|
11563
|
+
};
|
|
11564
|
+
window.addEventListener("popstate", this.popstateHandler);
|
|
11565
|
+
}
|
|
11566
|
+
getPerformanceMetrics() {
|
|
11567
|
+
if (typeof window === "undefined" || typeof performance === "undefined") return void 0;
|
|
11568
|
+
const metrics = {};
|
|
11569
|
+
try {
|
|
11570
|
+
const navigation = performance.getEntriesByType("navigation")[0];
|
|
11571
|
+
if (navigation) {
|
|
11572
|
+
metrics.pageLoadTime = Math.round(navigation.loadEventEnd - navigation.startTime);
|
|
11573
|
+
}
|
|
11574
|
+
} catch {
|
|
11575
|
+
}
|
|
11576
|
+
try {
|
|
11577
|
+
const memory = performance.memory;
|
|
11578
|
+
if (memory) {
|
|
11579
|
+
metrics.memoryUsage = Math.round(memory.usedJSHeapSize / 1024 / 1024);
|
|
11580
|
+
}
|
|
11581
|
+
} catch {
|
|
11582
|
+
}
|
|
11583
|
+
return Object.keys(metrics).length > 0 ? metrics : void 0;
|
|
11584
|
+
}
|
|
11585
|
+
getEnvironmentInfo() {
|
|
11586
|
+
if (typeof window === "undefined" || typeof navigator === "undefined") return void 0;
|
|
11587
|
+
return {
|
|
11588
|
+
language: navigator.language,
|
|
11589
|
+
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
11590
|
+
cookiesEnabled: navigator.cookieEnabled,
|
|
11591
|
+
localStorage: typeof localStorage !== "undefined",
|
|
11592
|
+
online: navigator.onLine
|
|
11593
|
+
};
|
|
11594
|
+
}
|
|
11595
|
+
};
|
|
11596
|
+
var contextCapture = new ContextCaptureManager();
|
|
11364
11597
|
var DEFAULT_SUPABASE_URL = "https://kyxgzjnqgvapvlnvqawz.supabase.co";
|
|
11365
11598
|
var getEnvVar = (key) => {
|
|
11366
11599
|
try {
|
|
@@ -11382,22 +11615,40 @@ var BugBearClient = class {
|
|
|
11382
11615
|
);
|
|
11383
11616
|
}
|
|
11384
11617
|
/**
|
|
11385
|
-
* Track navigation for context
|
|
11618
|
+
* Track navigation for context.
|
|
11619
|
+
* Also forwards to contextCapture for auto-tracked navigation.
|
|
11386
11620
|
*/
|
|
11387
11621
|
trackNavigation(route) {
|
|
11388
11622
|
this.navigationHistory.push(route);
|
|
11389
11623
|
if (this.navigationHistory.length > 10) {
|
|
11390
11624
|
this.navigationHistory.shift();
|
|
11391
11625
|
}
|
|
11626
|
+
contextCapture.trackNavigation(route);
|
|
11392
11627
|
}
|
|
11393
11628
|
/**
|
|
11394
|
-
* Get current navigation history
|
|
11629
|
+
* Get current navigation history.
|
|
11630
|
+
* Priority: config callback > manual tracking > auto-captured (pushState/popstate)
|
|
11395
11631
|
*/
|
|
11396
11632
|
getNavigationHistory() {
|
|
11397
11633
|
if (this.config.getNavigationHistory) {
|
|
11398
11634
|
return this.config.getNavigationHistory();
|
|
11399
11635
|
}
|
|
11400
|
-
|
|
11636
|
+
if (this.navigationHistory.length > 0) {
|
|
11637
|
+
return [...this.navigationHistory];
|
|
11638
|
+
}
|
|
11639
|
+
return contextCapture.getNavigationHistory();
|
|
11640
|
+
}
|
|
11641
|
+
/**
|
|
11642
|
+
* Get current app context.
|
|
11643
|
+
* Uses config.getAppContext() callback if provided, otherwise builds from available data.
|
|
11644
|
+
*/
|
|
11645
|
+
getAppContext() {
|
|
11646
|
+
if (this.config.getAppContext) {
|
|
11647
|
+
return this.config.getAppContext();
|
|
11648
|
+
}
|
|
11649
|
+
return {
|
|
11650
|
+
currentRoute: contextCapture.getCurrentRoute()
|
|
11651
|
+
};
|
|
11401
11652
|
}
|
|
11402
11653
|
/**
|
|
11403
11654
|
* Get current user info from host app or BugBear's own auth
|
|
@@ -11437,6 +11688,8 @@ var BugBearClient = class {
|
|
|
11437
11688
|
project_id: this.config.projectId,
|
|
11438
11689
|
reporter_id: userInfo.id,
|
|
11439
11690
|
// User ID from host app (required)
|
|
11691
|
+
reporter_name: testerInfo?.name || userInfo.name || null,
|
|
11692
|
+
reporter_email: userInfo.email || null,
|
|
11440
11693
|
tester_id: testerInfo?.id || null,
|
|
11441
11694
|
// Tester record ID (optional)
|
|
11442
11695
|
report_type: report.type,
|
|
@@ -11450,6 +11703,7 @@ var BugBearClient = class {
|
|
|
11450
11703
|
app_context: report.appContext,
|
|
11451
11704
|
device_info: report.deviceInfo || this.getDeviceInfo(),
|
|
11452
11705
|
navigation_history: this.getNavigationHistory(),
|
|
11706
|
+
enhanced_context: report.enhancedContext || contextCapture.getEnhancedContext(),
|
|
11453
11707
|
assignment_id: report.assignmentId,
|
|
11454
11708
|
test_case_id: report.testCaseId
|
|
11455
11709
|
};
|
|
@@ -11512,7 +11766,7 @@ var BugBearClient = class {
|
|
|
11512
11766
|
console.error("BugBear: Failed to fetch assignments", error);
|
|
11513
11767
|
return [];
|
|
11514
11768
|
}
|
|
11515
|
-
|
|
11769
|
+
const mapped = (data || []).map((item) => ({
|
|
11516
11770
|
id: item.id,
|
|
11517
11771
|
status: item.status,
|
|
11518
11772
|
startedAt: item.started_at,
|
|
@@ -11545,6 +11799,12 @@ var BugBearClient = class {
|
|
|
11545
11799
|
} : void 0
|
|
11546
11800
|
}
|
|
11547
11801
|
}));
|
|
11802
|
+
mapped.sort((a, b) => {
|
|
11803
|
+
if (a.isVerification && !b.isVerification) return -1;
|
|
11804
|
+
if (!a.isVerification && b.isVerification) return 1;
|
|
11805
|
+
return 0;
|
|
11806
|
+
});
|
|
11807
|
+
return mapped;
|
|
11548
11808
|
} catch (err) {
|
|
11549
11809
|
console.error("BugBear: Error fetching assignments", err);
|
|
11550
11810
|
return [];
|
|
@@ -12677,163 +12937,6 @@ var BugBearClient = class {
|
|
|
12677
12937
|
function createBugBear(config) {
|
|
12678
12938
|
return new BugBearClient(config);
|
|
12679
12939
|
}
|
|
12680
|
-
var MAX_CONSOLE_LOGS = 50;
|
|
12681
|
-
var MAX_NETWORK_REQUESTS = 20;
|
|
12682
|
-
var ContextCaptureManager = class {
|
|
12683
|
-
constructor() {
|
|
12684
|
-
this.consoleLogs = [];
|
|
12685
|
-
this.networkRequests = [];
|
|
12686
|
-
this.originalConsole = {};
|
|
12687
|
-
this.isCapturing = false;
|
|
12688
|
-
}
|
|
12689
|
-
/**
|
|
12690
|
-
* Start capturing console logs and network requests
|
|
12691
|
-
*/
|
|
12692
|
-
startCapture() {
|
|
12693
|
-
if (this.isCapturing) return;
|
|
12694
|
-
this.isCapturing = true;
|
|
12695
|
-
this.captureConsole();
|
|
12696
|
-
this.captureFetch();
|
|
12697
|
-
}
|
|
12698
|
-
/**
|
|
12699
|
-
* Stop capturing and restore original functions
|
|
12700
|
-
*/
|
|
12701
|
-
stopCapture() {
|
|
12702
|
-
if (!this.isCapturing) return;
|
|
12703
|
-
this.isCapturing = false;
|
|
12704
|
-
if (this.originalConsole.log) console.log = this.originalConsole.log;
|
|
12705
|
-
if (this.originalConsole.warn) console.warn = this.originalConsole.warn;
|
|
12706
|
-
if (this.originalConsole.error) console.error = this.originalConsole.error;
|
|
12707
|
-
if (this.originalConsole.info) console.info = this.originalConsole.info;
|
|
12708
|
-
if (this.originalFetch && typeof window !== "undefined") {
|
|
12709
|
-
window.fetch = this.originalFetch;
|
|
12710
|
-
}
|
|
12711
|
-
}
|
|
12712
|
-
/**
|
|
12713
|
-
* Get captured context for a bug report
|
|
12714
|
-
*/
|
|
12715
|
-
getEnhancedContext() {
|
|
12716
|
-
return {
|
|
12717
|
-
consoleLogs: [...this.consoleLogs],
|
|
12718
|
-
networkRequests: [...this.networkRequests],
|
|
12719
|
-
performanceMetrics: this.getPerformanceMetrics(),
|
|
12720
|
-
environment: this.getEnvironmentInfo()
|
|
12721
|
-
};
|
|
12722
|
-
}
|
|
12723
|
-
/**
|
|
12724
|
-
* Clear captured data
|
|
12725
|
-
*/
|
|
12726
|
-
clear() {
|
|
12727
|
-
this.consoleLogs = [];
|
|
12728
|
-
this.networkRequests = [];
|
|
12729
|
-
}
|
|
12730
|
-
/**
|
|
12731
|
-
* Add a log entry manually (for custom logging)
|
|
12732
|
-
*/
|
|
12733
|
-
addLog(level, message, args) {
|
|
12734
|
-
this.consoleLogs.push({
|
|
12735
|
-
level,
|
|
12736
|
-
message,
|
|
12737
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12738
|
-
args
|
|
12739
|
-
});
|
|
12740
|
-
if (this.consoleLogs.length > MAX_CONSOLE_LOGS) {
|
|
12741
|
-
this.consoleLogs = this.consoleLogs.slice(-MAX_CONSOLE_LOGS);
|
|
12742
|
-
}
|
|
12743
|
-
}
|
|
12744
|
-
/**
|
|
12745
|
-
* Add a network request manually
|
|
12746
|
-
*/
|
|
12747
|
-
addNetworkRequest(request) {
|
|
12748
|
-
this.networkRequests.push(request);
|
|
12749
|
-
if (this.networkRequests.length > MAX_NETWORK_REQUESTS) {
|
|
12750
|
-
this.networkRequests = this.networkRequests.slice(-MAX_NETWORK_REQUESTS);
|
|
12751
|
-
}
|
|
12752
|
-
}
|
|
12753
|
-
captureConsole() {
|
|
12754
|
-
if (typeof console === "undefined") return;
|
|
12755
|
-
const levels = ["log", "warn", "error", "info"];
|
|
12756
|
-
levels.forEach((level) => {
|
|
12757
|
-
this.originalConsole[level] = console[level];
|
|
12758
|
-
console[level] = (...args) => {
|
|
12759
|
-
this.originalConsole[level]?.apply(console, args);
|
|
12760
|
-
try {
|
|
12761
|
-
const message = args.map((arg) => {
|
|
12762
|
-
if (typeof arg === "string") return arg;
|
|
12763
|
-
try {
|
|
12764
|
-
return JSON.stringify(arg);
|
|
12765
|
-
} catch {
|
|
12766
|
-
return String(arg);
|
|
12767
|
-
}
|
|
12768
|
-
}).join(" ");
|
|
12769
|
-
this.addLog(level, message.slice(0, 500));
|
|
12770
|
-
} catch {
|
|
12771
|
-
}
|
|
12772
|
-
};
|
|
12773
|
-
});
|
|
12774
|
-
}
|
|
12775
|
-
captureFetch() {
|
|
12776
|
-
if (typeof window === "undefined" || typeof fetch === "undefined") return;
|
|
12777
|
-
this.originalFetch = window.fetch;
|
|
12778
|
-
const self2 = this;
|
|
12779
|
-
window.fetch = async function(input, init) {
|
|
12780
|
-
const startTime = Date.now();
|
|
12781
|
-
const url = typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url;
|
|
12782
|
-
const method = init?.method || "GET";
|
|
12783
|
-
try {
|
|
12784
|
-
const response = await self2.originalFetch.call(window, input, init);
|
|
12785
|
-
self2.addNetworkRequest({
|
|
12786
|
-
method,
|
|
12787
|
-
url: url.slice(0, 200),
|
|
12788
|
-
// Limit URL length
|
|
12789
|
-
status: response.status,
|
|
12790
|
-
duration: Date.now() - startTime,
|
|
12791
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
12792
|
-
});
|
|
12793
|
-
return response;
|
|
12794
|
-
} catch (error) {
|
|
12795
|
-
self2.addNetworkRequest({
|
|
12796
|
-
method,
|
|
12797
|
-
url: url.slice(0, 200),
|
|
12798
|
-
duration: Date.now() - startTime,
|
|
12799
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12800
|
-
error: error instanceof Error ? error.message : "Unknown error"
|
|
12801
|
-
});
|
|
12802
|
-
throw error;
|
|
12803
|
-
}
|
|
12804
|
-
};
|
|
12805
|
-
}
|
|
12806
|
-
getPerformanceMetrics() {
|
|
12807
|
-
if (typeof window === "undefined" || typeof performance === "undefined") return void 0;
|
|
12808
|
-
const metrics = {};
|
|
12809
|
-
try {
|
|
12810
|
-
const navigation = performance.getEntriesByType("navigation")[0];
|
|
12811
|
-
if (navigation) {
|
|
12812
|
-
metrics.pageLoadTime = Math.round(navigation.loadEventEnd - navigation.startTime);
|
|
12813
|
-
}
|
|
12814
|
-
} catch {
|
|
12815
|
-
}
|
|
12816
|
-
try {
|
|
12817
|
-
const memory = performance.memory;
|
|
12818
|
-
if (memory) {
|
|
12819
|
-
metrics.memoryUsage = Math.round(memory.usedJSHeapSize / 1024 / 1024);
|
|
12820
|
-
}
|
|
12821
|
-
} catch {
|
|
12822
|
-
}
|
|
12823
|
-
return Object.keys(metrics).length > 0 ? metrics : void 0;
|
|
12824
|
-
}
|
|
12825
|
-
getEnvironmentInfo() {
|
|
12826
|
-
if (typeof window === "undefined" || typeof navigator === "undefined") return void 0;
|
|
12827
|
-
return {
|
|
12828
|
-
language: navigator.language,
|
|
12829
|
-
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
12830
|
-
cookiesEnabled: navigator.cookieEnabled,
|
|
12831
|
-
localStorage: typeof localStorage !== "undefined",
|
|
12832
|
-
online: navigator.onLine
|
|
12833
|
-
};
|
|
12834
|
-
}
|
|
12835
|
-
};
|
|
12836
|
-
var contextCapture = new ContextCaptureManager();
|
|
12837
12940
|
|
|
12838
12941
|
// src/BugBearProvider.tsx
|
|
12839
12942
|
import { Platform, Dimensions } from "react-native";
|
|
@@ -13034,6 +13137,7 @@ function BugBearProvider({ config, children, appVersion, enabled = true }) {
|
|
|
13034
13137
|
useEffect(() => {
|
|
13035
13138
|
if (enabled && !hasInitialized.current) {
|
|
13036
13139
|
hasInitialized.current = true;
|
|
13140
|
+
contextCapture.startCapture();
|
|
13037
13141
|
const newClient = createBugBear(config);
|
|
13038
13142
|
setClient(newClient);
|
|
13039
13143
|
initializeBugBear(newClient);
|
|
@@ -13327,7 +13431,9 @@ function HomeScreen({ nav }) {
|
|
|
13327
13431
|
refreshAssignments();
|
|
13328
13432
|
refreshThreads();
|
|
13329
13433
|
}, []);
|
|
13330
|
-
const
|
|
13434
|
+
const pendingAssignments = assignments.filter((a) => a.status === "pending" || a.status === "in_progress");
|
|
13435
|
+
const pendingCount = pendingAssignments.length;
|
|
13436
|
+
const retestCount = pendingAssignments.filter((a) => a.isVerification).length;
|
|
13331
13437
|
const completedCount = assignments.filter((a) => a.status === "passed" || a.status === "failed").length;
|
|
13332
13438
|
const totalTests = assignments.length;
|
|
13333
13439
|
return /* @__PURE__ */ React2.createElement(View, null, pendingCount > 0 ? /* @__PURE__ */ React2.createElement(
|
|
@@ -13339,6 +13445,7 @@ function HomeScreen({ nav }) {
|
|
|
13339
13445
|
},
|
|
13340
13446
|
/* @__PURE__ */ React2.createElement(Text, { style: styles.heroCount }, pendingCount),
|
|
13341
13447
|
/* @__PURE__ */ React2.createElement(Text, { style: styles.heroLabel }, "test", pendingCount !== 1 ? "s" : "", " waiting"),
|
|
13448
|
+
retestCount > 0 && /* @__PURE__ */ React2.createElement(View, { style: styles.retestPill }, /* @__PURE__ */ React2.createElement(Text, { style: styles.retestPillText }, "\u{1F504} ", retestCount, " retest", retestCount !== 1 ? "s" : "")),
|
|
13342
13449
|
/* @__PURE__ */ React2.createElement(Text, { style: styles.heroAction }, "Start Testing \u2192")
|
|
13343
13450
|
) : unreadCount > 0 ? /* @__PURE__ */ React2.createElement(
|
|
13344
13451
|
TouchableOpacity,
|
|
@@ -13442,6 +13549,22 @@ var styles = StyleSheet2.create({
|
|
|
13442
13549
|
color: colors.blueText,
|
|
13443
13550
|
marginTop: 2
|
|
13444
13551
|
},
|
|
13552
|
+
retestPill: {
|
|
13553
|
+
flexDirection: "row",
|
|
13554
|
+
alignItems: "center",
|
|
13555
|
+
backgroundColor: "#422006",
|
|
13556
|
+
borderWidth: 1,
|
|
13557
|
+
borderColor: "#854d0e",
|
|
13558
|
+
borderRadius: 6,
|
|
13559
|
+
paddingHorizontal: 8,
|
|
13560
|
+
paddingVertical: 3,
|
|
13561
|
+
marginTop: 8
|
|
13562
|
+
},
|
|
13563
|
+
retestPillText: {
|
|
13564
|
+
fontSize: 12,
|
|
13565
|
+
fontWeight: "600",
|
|
13566
|
+
color: "#fbbf24"
|
|
13567
|
+
},
|
|
13445
13568
|
heroAction: {
|
|
13446
13569
|
fontSize: 14,
|
|
13447
13570
|
fontWeight: "600",
|
|
@@ -13652,7 +13775,7 @@ function TestDetailScreen({ testId, nav }) {
|
|
|
13652
13775
|
const steps = testCase.steps;
|
|
13653
13776
|
const info = templateInfo[template] || templateInfo.steps;
|
|
13654
13777
|
const rubricMode = testCase.track?.rubricMode || "pass_fail";
|
|
13655
|
-
return /* @__PURE__ */ React3.createElement(View2, { style: styles2.container }, /* @__PURE__ */ React3.createElement(View2, { style: styles2.topRow }, /* @__PURE__ */ React3.createElement(View2, { style: styles2.positionInfo }, /* @__PURE__ */ React3.createElement(Text2, { style: styles2.positionText }, "Test ", currentIndex + 1, " of ", allTests.length), displayedAssignment.status === "in_progress" && assignmentElapsedTime > 0 && /* @__PURE__ */ React3.createElement(View2, { style: styles2.timerBadge }, /* @__PURE__ */ React3.createElement(Text2, { style: styles2.timerText }, formatElapsedTime(assignmentElapsedTime)))), /* @__PURE__ */ React3.createElement(TouchableOpacity2, { onPress: () => nav.push({ name: "TEST_LIST" }) }, /* @__PURE__ */ React3.createElement(Text2, { style: styles2.viewAllLink }, "View All \u2192"))), /* @__PURE__ */ React3.createElement(Text2, { style: styles2.testTitle }, testCase.title), testCase.key && /* @__PURE__ */ React3.createElement(Text2, { style: styles2.testKey }, testCase.key), /* @__PURE__ */ React3.createElement(TouchableOpacity2, { onPress: () => setShowSteps(!showSteps), style: styles2.sectionHeader }, /* @__PURE__ */ React3.createElement(Text2, { style: styles2.sectionHeaderText }, showSteps ? "\u25BC" : "\u25B6", " ", info.icon, " ", template === "freeform" ? "Instructions" : `${steps.length} ${template === "checklist" ? "items" : template === "rubric" ? "criteria" : "steps"}`)), showSteps && /* @__PURE__ */ React3.createElement(View2, { style: styles2.templateContent }, template === "steps" && steps.map((step, idx) => /* @__PURE__ */ React3.createElement(View2, { key: idx, style: styles2.step }, /* @__PURE__ */ React3.createElement(View2, { style: styles2.stepNumber }, /* @__PURE__ */ React3.createElement(Text2, { style: styles2.stepNumberText }, step.stepNumber)), /* @__PURE__ */ React3.createElement(View2, { style: styles2.stepBody }, /* @__PURE__ */ React3.createElement(Text2, { style: styles2.stepAction }, step.action), step.expectedResult && /* @__PURE__ */ React3.createElement(Text2, { style: styles2.stepExpected }, "\u2192 ", step.expectedResult)))), template === "checklist" && /* @__PURE__ */ React3.createElement(React3.Fragment, null, steps.map((step, idx) => /* @__PURE__ */ React3.createElement(
|
|
13778
|
+
return /* @__PURE__ */ React3.createElement(View2, { style: styles2.container }, /* @__PURE__ */ React3.createElement(View2, { style: styles2.topRow }, /* @__PURE__ */ React3.createElement(View2, { style: styles2.positionInfo }, /* @__PURE__ */ React3.createElement(Text2, { style: styles2.positionText }, "Test ", currentIndex + 1, " of ", allTests.length), displayedAssignment.status === "in_progress" && assignmentElapsedTime > 0 && /* @__PURE__ */ React3.createElement(View2, { style: styles2.timerBadge }, /* @__PURE__ */ React3.createElement(Text2, { style: styles2.timerText }, formatElapsedTime(assignmentElapsedTime)))), /* @__PURE__ */ React3.createElement(TouchableOpacity2, { onPress: () => nav.push({ name: "TEST_LIST" }) }, /* @__PURE__ */ React3.createElement(Text2, { style: styles2.viewAllLink }, "View All \u2192"))), displayedAssignment.isVerification && /* @__PURE__ */ React3.createElement(View2, { style: styles2.retestBanner }, /* @__PURE__ */ React3.createElement(Text2, { style: styles2.retestIcon }, "\u{1F504}"), /* @__PURE__ */ React3.createElement(Text2, { style: styles2.retestLabel }, "Retest"), /* @__PURE__ */ React3.createElement(Text2, { style: styles2.retestSub }, "\u2014 Verify bug fix")), /* @__PURE__ */ React3.createElement(Text2, { style: styles2.testTitle }, testCase.title), testCase.key && /* @__PURE__ */ React3.createElement(Text2, { style: styles2.testKey }, testCase.key), /* @__PURE__ */ React3.createElement(TouchableOpacity2, { onPress: () => setShowSteps(!showSteps), style: styles2.sectionHeader }, /* @__PURE__ */ React3.createElement(Text2, { style: styles2.sectionHeaderText }, showSteps ? "\u25BC" : "\u25B6", " ", info.icon, " ", template === "freeform" ? "Instructions" : `${steps.length} ${template === "checklist" ? "items" : template === "rubric" ? "criteria" : "steps"}`)), showSteps && /* @__PURE__ */ React3.createElement(View2, { style: styles2.templateContent }, template === "steps" && steps.map((step, idx) => /* @__PURE__ */ React3.createElement(View2, { key: idx, style: styles2.step }, /* @__PURE__ */ React3.createElement(View2, { style: styles2.stepNumber }, /* @__PURE__ */ React3.createElement(Text2, { style: styles2.stepNumberText }, step.stepNumber)), /* @__PURE__ */ React3.createElement(View2, { style: styles2.stepBody }, /* @__PURE__ */ React3.createElement(Text2, { style: styles2.stepAction }, step.action), step.expectedResult && /* @__PURE__ */ React3.createElement(Text2, { style: styles2.stepExpected }, "\u2192 ", step.expectedResult)))), template === "checklist" && /* @__PURE__ */ React3.createElement(React3.Fragment, null, steps.map((step, idx) => /* @__PURE__ */ React3.createElement(
|
|
13656
13779
|
TouchableOpacity2,
|
|
13657
13780
|
{
|
|
13658
13781
|
key: idx,
|
|
@@ -13736,6 +13859,10 @@ function TestDetailScreen({ testId, nav }) {
|
|
|
13736
13859
|
}
|
|
13737
13860
|
var styles2 = StyleSheet3.create({
|
|
13738
13861
|
container: { paddingBottom: 16 },
|
|
13862
|
+
retestBanner: { flexDirection: "row", alignItems: "center", gap: 6, backgroundColor: "#422006", borderWidth: 1, borderColor: "#854d0e", borderRadius: 8, paddingVertical: 6, paddingHorizontal: 10, marginBottom: 10 },
|
|
13863
|
+
retestIcon: { fontSize: 14 },
|
|
13864
|
+
retestLabel: { fontSize: 13, fontWeight: "600", color: "#fbbf24" },
|
|
13865
|
+
retestSub: { fontSize: 12, color: "#d97706" },
|
|
13739
13866
|
topRow: { flexDirection: "row", justifyContent: "space-between", alignItems: "center", marginBottom: 12 },
|
|
13740
13867
|
positionInfo: { flexDirection: "row", alignItems: "center", gap: 8 },
|
|
13741
13868
|
positionText: { fontSize: 13, color: colors.textMuted },
|
|
@@ -13851,6 +13978,8 @@ function TestListScreen({ nav }) {
|
|
|
13851
13978
|
const statusOrder = { in_progress: 0, pending: 1, failed: 2, skipped: 3, passed: 4 };
|
|
13852
13979
|
for (const folder of groups.values()) {
|
|
13853
13980
|
folder.assignments.sort((a, b) => {
|
|
13981
|
+
if (a.isVerification && !b.isVerification) return -1;
|
|
13982
|
+
if (!a.isVerification && b.isVerification) return 1;
|
|
13854
13983
|
const sd = (statusOrder[a.status] ?? 5) - (statusOrder[b.status] ?? 5);
|
|
13855
13984
|
if (sd !== 0) return sd;
|
|
13856
13985
|
return (priorityOrder[a.testCase.priority] ?? 4) - (priorityOrder[b.testCase.priority] ?? 4);
|
|
@@ -13892,7 +14021,7 @@ function TestListScreen({ nav }) {
|
|
|
13892
14021
|
onPress: () => nav.push({ name: "TEST_DETAIL", testId: assignment.id })
|
|
13893
14022
|
},
|
|
13894
14023
|
/* @__PURE__ */ React4.createElement(Text3, { style: styles3.testBadge }, badge.icon),
|
|
13895
|
-
/* @__PURE__ */ React4.createElement(View3, { style: styles3.testInfo }, /* @__PURE__ */ React4.createElement(Text3, { style: styles3.testTitle, numberOfLines: 1 }, assignment.testCase.title), /* @__PURE__ */ React4.createElement(Text3, { style: styles3.testMeta }, assignment.testCase.key, " \xB7 ", assignment.testCase.priority))
|
|
14024
|
+
/* @__PURE__ */ React4.createElement(View3, { style: styles3.testInfo }, /* @__PURE__ */ React4.createElement(Text3, { style: styles3.testTitle, numberOfLines: 1 }, assignment.testCase.title), /* @__PURE__ */ React4.createElement(View3, { style: styles3.testMetaRow }, assignment.isVerification && /* @__PURE__ */ React4.createElement(View3, { style: styles3.retestTag }, /* @__PURE__ */ React4.createElement(Text3, { style: styles3.retestTagText }, "Retest")), /* @__PURE__ */ React4.createElement(Text3, { style: styles3.testMeta }, assignment.testCase.key, " \xB7 ", assignment.testCase.priority)))
|
|
13896
14025
|
);
|
|
13897
14026
|
}));
|
|
13898
14027
|
}), /* @__PURE__ */ React4.createElement(TouchableOpacity3, { style: styles3.refreshBtn, onPress: refreshAssignments }, /* @__PURE__ */ React4.createElement(Text3, { style: styles3.refreshText }, "\u21BB Refresh")));
|
|
@@ -13915,6 +14044,9 @@ var styles3 = StyleSheet4.create({
|
|
|
13915
14044
|
testBadge: { fontSize: 16, marginRight: 10, width: 20 },
|
|
13916
14045
|
testInfo: { flex: 1 },
|
|
13917
14046
|
testTitle: { fontSize: 14, color: colors.textPrimary, marginBottom: 2 },
|
|
14047
|
+
testMetaRow: { flexDirection: "row", alignItems: "center", gap: 6 },
|
|
14048
|
+
retestTag: { backgroundColor: "#422006", borderWidth: 1, borderColor: "#854d0e", borderRadius: 4, paddingHorizontal: 5, paddingVertical: 1 },
|
|
14049
|
+
retestTagText: { fontSize: 10, fontWeight: "600", color: "#fbbf24" },
|
|
13918
14050
|
testMeta: { fontSize: 11, color: colors.textDim },
|
|
13919
14051
|
refreshBtn: { alignItems: "center", paddingVertical: 12 },
|
|
13920
14052
|
refreshText: { fontSize: 13, color: colors.blue }
|
|
@@ -14245,12 +14377,18 @@ function ReportScreen({ nav, prefill }) {
|
|
|
14245
14377
|
const [reportType, setReportType] = useState6(prefill?.type || "bug");
|
|
14246
14378
|
const [severity, setSeverity] = useState6("medium");
|
|
14247
14379
|
const [description, setDescription] = useState6("");
|
|
14380
|
+
const [affectedScreen, setAffectedScreen] = useState6("");
|
|
14248
14381
|
const [submitting, setSubmitting] = useState6(false);
|
|
14249
14382
|
const images = useImageAttachments(uploadImage, 5, "screenshots");
|
|
14250
14383
|
const isBugType = reportType === "bug" || reportType === "test_fail";
|
|
14251
14384
|
const handleSubmit = async () => {
|
|
14252
14385
|
if (!client || !description.trim()) return;
|
|
14253
14386
|
setSubmitting(true);
|
|
14387
|
+
const baseContext = client.getAppContext();
|
|
14388
|
+
const appContext = {
|
|
14389
|
+
...baseContext,
|
|
14390
|
+
currentRoute: affectedScreen.trim() || baseContext.currentRoute
|
|
14391
|
+
};
|
|
14254
14392
|
const screenshotUrls = images.getScreenshotUrls();
|
|
14255
14393
|
await client.submitReport({
|
|
14256
14394
|
type: reportType,
|
|
@@ -14258,7 +14396,7 @@ function ReportScreen({ nav, prefill }) {
|
|
|
14258
14396
|
severity: isBugType ? severity : void 0,
|
|
14259
14397
|
assignmentId: prefill?.assignmentId,
|
|
14260
14398
|
testCaseId: prefill?.testCaseId,
|
|
14261
|
-
appContext
|
|
14399
|
+
appContext,
|
|
14262
14400
|
deviceInfo: getDeviceInfo(),
|
|
14263
14401
|
screenshots: screenshotUrls.length > 0 ? screenshotUrls : void 0
|
|
14264
14402
|
});
|
|
@@ -14306,7 +14444,16 @@ function ReportScreen({ nav, prefill }) {
|
|
|
14306
14444
|
numberOfLines: 4,
|
|
14307
14445
|
textAlignVertical: "top"
|
|
14308
14446
|
}
|
|
14309
|
-
)), /* @__PURE__ */ React8.createElement(
|
|
14447
|
+
)), isBugType && /* @__PURE__ */ React8.createElement(View7, { style: styles7.section }, /* @__PURE__ */ React8.createElement(Text7, { style: shared.label }, "Which screen?"), /* @__PURE__ */ React8.createElement(
|
|
14448
|
+
TextInput3,
|
|
14449
|
+
{
|
|
14450
|
+
style: styles7.screenInput,
|
|
14451
|
+
value: affectedScreen,
|
|
14452
|
+
onChangeText: setAffectedScreen,
|
|
14453
|
+
placeholder: "e.g. Reservations, Settings...",
|
|
14454
|
+
placeholderTextColor: colors.textMuted
|
|
14455
|
+
}
|
|
14456
|
+
), /* @__PURE__ */ React8.createElement(Text7, { style: styles7.screenHint }, "Which screen or area was the bug on? (optional)")), /* @__PURE__ */ React8.createElement(
|
|
14310
14457
|
ImagePickerButtons,
|
|
14311
14458
|
{
|
|
14312
14459
|
images: images.images,
|
|
@@ -14337,7 +14484,9 @@ var styles7 = StyleSheet8.create({
|
|
|
14337
14484
|
severityRow: { flexDirection: "row", gap: 8 },
|
|
14338
14485
|
sevButton: { flex: 1, paddingVertical: 8, borderRadius: 8, alignItems: "center", borderWidth: 1, borderColor: colors.border, backgroundColor: colors.card },
|
|
14339
14486
|
sevText: { fontSize: 12, fontWeight: "500", color: colors.textSecondary, textTransform: "capitalize" },
|
|
14340
|
-
descInput: { backgroundColor: colors.card, borderWidth: 1, borderColor: colors.border, borderRadius: 12, paddingHorizontal: 14, paddingVertical: 12, fontSize: 14, color: colors.textPrimary, minHeight: 100 }
|
|
14487
|
+
descInput: { backgroundColor: colors.card, borderWidth: 1, borderColor: colors.border, borderRadius: 12, paddingHorizontal: 14, paddingVertical: 12, fontSize: 14, color: colors.textPrimary, minHeight: 100 },
|
|
14488
|
+
screenInput: { backgroundColor: colors.card, borderWidth: 1, borderColor: colors.border, borderRadius: 8, paddingHorizontal: 12, paddingVertical: 8, fontSize: 13, color: colors.textPrimary },
|
|
14489
|
+
screenHint: { fontSize: 11, color: colors.textMuted, marginTop: 4 }
|
|
14341
14490
|
});
|
|
14342
14491
|
|
|
14343
14492
|
// src/widget/screens/ReportSuccessScreen.tsx
|