@bbearai/react-native 0.3.7 → 0.3.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +139 -92
- package/dist/index.js +343 -171
- package/dist/index.mjs +346 -173
- 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
|
};
|
|
@@ -11728,19 +11982,40 @@ var BugBearClient = class {
|
|
|
11728
11982
|
return { success: false, error: message };
|
|
11729
11983
|
}
|
|
11730
11984
|
}
|
|
11985
|
+
/**
|
|
11986
|
+
* Pass a test assignment — convenience wrapper around updateAssignmentStatus
|
|
11987
|
+
*/
|
|
11988
|
+
async passAssignment(assignmentId) {
|
|
11989
|
+
return this.updateAssignmentStatus(assignmentId, "passed");
|
|
11990
|
+
}
|
|
11991
|
+
/**
|
|
11992
|
+
* Fail a test assignment — convenience wrapper around updateAssignmentStatus
|
|
11993
|
+
*/
|
|
11994
|
+
async failAssignment(assignmentId) {
|
|
11995
|
+
return this.updateAssignmentStatus(assignmentId, "failed");
|
|
11996
|
+
}
|
|
11731
11997
|
/**
|
|
11732
11998
|
* Skip a test assignment with a required reason
|
|
11733
11999
|
* Marks the assignment as 'skipped' and records why it was skipped
|
|
11734
12000
|
*/
|
|
11735
12001
|
async skipAssignment(assignmentId, reason, notes) {
|
|
12002
|
+
let actualReason;
|
|
12003
|
+
let actualNotes;
|
|
12004
|
+
if (typeof reason === "object") {
|
|
12005
|
+
actualReason = reason.reason;
|
|
12006
|
+
actualNotes = reason.notes;
|
|
12007
|
+
} else {
|
|
12008
|
+
actualReason = reason;
|
|
12009
|
+
actualNotes = notes;
|
|
12010
|
+
}
|
|
11736
12011
|
try {
|
|
11737
12012
|
const updateData = {
|
|
11738
12013
|
status: "skipped",
|
|
11739
|
-
skip_reason:
|
|
12014
|
+
skip_reason: actualReason,
|
|
11740
12015
|
completed_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
11741
12016
|
};
|
|
11742
|
-
if (
|
|
11743
|
-
updateData.notes =
|
|
12017
|
+
if (actualNotes) {
|
|
12018
|
+
updateData.notes = actualNotes;
|
|
11744
12019
|
}
|
|
11745
12020
|
const { error } = await this.supabase.from("test_assignments").update(updateData).eq("id", assignmentId);
|
|
11746
12021
|
if (error) {
|
|
@@ -12714,163 +12989,6 @@ var BugBearClient = class {
|
|
|
12714
12989
|
function createBugBear(config) {
|
|
12715
12990
|
return new BugBearClient(config);
|
|
12716
12991
|
}
|
|
12717
|
-
var MAX_CONSOLE_LOGS = 50;
|
|
12718
|
-
var MAX_NETWORK_REQUESTS = 20;
|
|
12719
|
-
var ContextCaptureManager = class {
|
|
12720
|
-
constructor() {
|
|
12721
|
-
this.consoleLogs = [];
|
|
12722
|
-
this.networkRequests = [];
|
|
12723
|
-
this.originalConsole = {};
|
|
12724
|
-
this.isCapturing = false;
|
|
12725
|
-
}
|
|
12726
|
-
/**
|
|
12727
|
-
* Start capturing console logs and network requests
|
|
12728
|
-
*/
|
|
12729
|
-
startCapture() {
|
|
12730
|
-
if (this.isCapturing) return;
|
|
12731
|
-
this.isCapturing = true;
|
|
12732
|
-
this.captureConsole();
|
|
12733
|
-
this.captureFetch();
|
|
12734
|
-
}
|
|
12735
|
-
/**
|
|
12736
|
-
* Stop capturing and restore original functions
|
|
12737
|
-
*/
|
|
12738
|
-
stopCapture() {
|
|
12739
|
-
if (!this.isCapturing) return;
|
|
12740
|
-
this.isCapturing = false;
|
|
12741
|
-
if (this.originalConsole.log) console.log = this.originalConsole.log;
|
|
12742
|
-
if (this.originalConsole.warn) console.warn = this.originalConsole.warn;
|
|
12743
|
-
if (this.originalConsole.error) console.error = this.originalConsole.error;
|
|
12744
|
-
if (this.originalConsole.info) console.info = this.originalConsole.info;
|
|
12745
|
-
if (this.originalFetch && typeof window !== "undefined") {
|
|
12746
|
-
window.fetch = this.originalFetch;
|
|
12747
|
-
}
|
|
12748
|
-
}
|
|
12749
|
-
/**
|
|
12750
|
-
* Get captured context for a bug report
|
|
12751
|
-
*/
|
|
12752
|
-
getEnhancedContext() {
|
|
12753
|
-
return {
|
|
12754
|
-
consoleLogs: [...this.consoleLogs],
|
|
12755
|
-
networkRequests: [...this.networkRequests],
|
|
12756
|
-
performanceMetrics: this.getPerformanceMetrics(),
|
|
12757
|
-
environment: this.getEnvironmentInfo()
|
|
12758
|
-
};
|
|
12759
|
-
}
|
|
12760
|
-
/**
|
|
12761
|
-
* Clear captured data
|
|
12762
|
-
*/
|
|
12763
|
-
clear() {
|
|
12764
|
-
this.consoleLogs = [];
|
|
12765
|
-
this.networkRequests = [];
|
|
12766
|
-
}
|
|
12767
|
-
/**
|
|
12768
|
-
* Add a log entry manually (for custom logging)
|
|
12769
|
-
*/
|
|
12770
|
-
addLog(level, message, args) {
|
|
12771
|
-
this.consoleLogs.push({
|
|
12772
|
-
level,
|
|
12773
|
-
message,
|
|
12774
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12775
|
-
args
|
|
12776
|
-
});
|
|
12777
|
-
if (this.consoleLogs.length > MAX_CONSOLE_LOGS) {
|
|
12778
|
-
this.consoleLogs = this.consoleLogs.slice(-MAX_CONSOLE_LOGS);
|
|
12779
|
-
}
|
|
12780
|
-
}
|
|
12781
|
-
/**
|
|
12782
|
-
* Add a network request manually
|
|
12783
|
-
*/
|
|
12784
|
-
addNetworkRequest(request) {
|
|
12785
|
-
this.networkRequests.push(request);
|
|
12786
|
-
if (this.networkRequests.length > MAX_NETWORK_REQUESTS) {
|
|
12787
|
-
this.networkRequests = this.networkRequests.slice(-MAX_NETWORK_REQUESTS);
|
|
12788
|
-
}
|
|
12789
|
-
}
|
|
12790
|
-
captureConsole() {
|
|
12791
|
-
if (typeof console === "undefined") return;
|
|
12792
|
-
const levels = ["log", "warn", "error", "info"];
|
|
12793
|
-
levels.forEach((level) => {
|
|
12794
|
-
this.originalConsole[level] = console[level];
|
|
12795
|
-
console[level] = (...args) => {
|
|
12796
|
-
this.originalConsole[level]?.apply(console, args);
|
|
12797
|
-
try {
|
|
12798
|
-
const message = args.map((arg) => {
|
|
12799
|
-
if (typeof arg === "string") return arg;
|
|
12800
|
-
try {
|
|
12801
|
-
return JSON.stringify(arg);
|
|
12802
|
-
} catch {
|
|
12803
|
-
return String(arg);
|
|
12804
|
-
}
|
|
12805
|
-
}).join(" ");
|
|
12806
|
-
this.addLog(level, message.slice(0, 500));
|
|
12807
|
-
} catch {
|
|
12808
|
-
}
|
|
12809
|
-
};
|
|
12810
|
-
});
|
|
12811
|
-
}
|
|
12812
|
-
captureFetch() {
|
|
12813
|
-
if (typeof window === "undefined" || typeof fetch === "undefined") return;
|
|
12814
|
-
this.originalFetch = window.fetch;
|
|
12815
|
-
const self2 = this;
|
|
12816
|
-
window.fetch = async function(input, init) {
|
|
12817
|
-
const startTime = Date.now();
|
|
12818
|
-
const url = typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url;
|
|
12819
|
-
const method = init?.method || "GET";
|
|
12820
|
-
try {
|
|
12821
|
-
const response = await self2.originalFetch.call(window, input, init);
|
|
12822
|
-
self2.addNetworkRequest({
|
|
12823
|
-
method,
|
|
12824
|
-
url: url.slice(0, 200),
|
|
12825
|
-
// Limit URL length
|
|
12826
|
-
status: response.status,
|
|
12827
|
-
duration: Date.now() - startTime,
|
|
12828
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
12829
|
-
});
|
|
12830
|
-
return response;
|
|
12831
|
-
} catch (error) {
|
|
12832
|
-
self2.addNetworkRequest({
|
|
12833
|
-
method,
|
|
12834
|
-
url: url.slice(0, 200),
|
|
12835
|
-
duration: Date.now() - startTime,
|
|
12836
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12837
|
-
error: error instanceof Error ? error.message : "Unknown error"
|
|
12838
|
-
});
|
|
12839
|
-
throw error;
|
|
12840
|
-
}
|
|
12841
|
-
};
|
|
12842
|
-
}
|
|
12843
|
-
getPerformanceMetrics() {
|
|
12844
|
-
if (typeof window === "undefined" || typeof performance === "undefined") return void 0;
|
|
12845
|
-
const metrics = {};
|
|
12846
|
-
try {
|
|
12847
|
-
const navigation = performance.getEntriesByType("navigation")[0];
|
|
12848
|
-
if (navigation) {
|
|
12849
|
-
metrics.pageLoadTime = Math.round(navigation.loadEventEnd - navigation.startTime);
|
|
12850
|
-
}
|
|
12851
|
-
} catch {
|
|
12852
|
-
}
|
|
12853
|
-
try {
|
|
12854
|
-
const memory = performance.memory;
|
|
12855
|
-
if (memory) {
|
|
12856
|
-
metrics.memoryUsage = Math.round(memory.usedJSHeapSize / 1024 / 1024);
|
|
12857
|
-
}
|
|
12858
|
-
} catch {
|
|
12859
|
-
}
|
|
12860
|
-
return Object.keys(metrics).length > 0 ? metrics : void 0;
|
|
12861
|
-
}
|
|
12862
|
-
getEnvironmentInfo() {
|
|
12863
|
-
if (typeof window === "undefined" || typeof navigator === "undefined") return void 0;
|
|
12864
|
-
return {
|
|
12865
|
-
language: navigator.language,
|
|
12866
|
-
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
12867
|
-
cookiesEnabled: navigator.cookieEnabled,
|
|
12868
|
-
localStorage: typeof localStorage !== "undefined",
|
|
12869
|
-
online: navigator.onLine
|
|
12870
|
-
};
|
|
12871
|
-
}
|
|
12872
|
-
};
|
|
12873
|
-
var contextCapture = new ContextCaptureManager();
|
|
12874
12992
|
|
|
12875
12993
|
// src/BugBearProvider.tsx
|
|
12876
12994
|
var import_react_native = require("react-native");
|
|
@@ -13071,6 +13189,7 @@ function BugBearProvider({ config, children, appVersion, enabled = true }) {
|
|
|
13071
13189
|
(0, import_react.useEffect)(() => {
|
|
13072
13190
|
if (enabled && !hasInitialized.current) {
|
|
13073
13191
|
hasInitialized.current = true;
|
|
13192
|
+
contextCapture.startCapture();
|
|
13074
13193
|
const newClient = createBugBear(config);
|
|
13075
13194
|
setClient(newClient);
|
|
13076
13195
|
initializeBugBear(newClient);
|
|
@@ -13380,7 +13499,7 @@ function HomeScreen({ nav }) {
|
|
|
13380
13499
|
import_react_native3.TouchableOpacity,
|
|
13381
13500
|
{
|
|
13382
13501
|
style: styles.actionCard,
|
|
13383
|
-
onPress: () => nav.push({ name: "
|
|
13502
|
+
onPress: () => nav.push({ name: "TEST_LIST" }),
|
|
13384
13503
|
activeOpacity: 0.7
|
|
13385
13504
|
},
|
|
13386
13505
|
/* @__PURE__ */ import_react3.default.createElement(import_react_native3.Text, { style: styles.actionIcon }, "\u2705"),
|
|
@@ -13648,12 +13767,14 @@ function TestDetailScreen({ testId, nav }) {
|
|
|
13648
13767
|
const currentIndex = displayedAssignment ? assignments.indexOf(displayedAssignment) : -1;
|
|
13649
13768
|
const handlePass = (0, import_react4.useCallback)(async () => {
|
|
13650
13769
|
if (!client || !displayedAssignment) return;
|
|
13770
|
+
import_react_native4.Keyboard.dismiss();
|
|
13651
13771
|
await client.passAssignment(displayedAssignment.id);
|
|
13652
13772
|
await refreshAssignments();
|
|
13653
13773
|
nav.replace({ name: "TEST_FEEDBACK", status: "passed", assignmentId: displayedAssignment.id });
|
|
13654
13774
|
}, [client, displayedAssignment, refreshAssignments, nav]);
|
|
13655
13775
|
const handleFail = (0, import_react4.useCallback)(async () => {
|
|
13656
13776
|
if (!client || !displayedAssignment) return;
|
|
13777
|
+
import_react_native4.Keyboard.dismiss();
|
|
13657
13778
|
await client.failAssignment(displayedAssignment.id);
|
|
13658
13779
|
await refreshAssignments();
|
|
13659
13780
|
nav.replace({
|
|
@@ -13667,6 +13788,7 @@ function TestDetailScreen({ testId, nav }) {
|
|
|
13667
13788
|
}, [client, displayedAssignment, refreshAssignments, nav]);
|
|
13668
13789
|
const handleSkip = (0, import_react4.useCallback)(async () => {
|
|
13669
13790
|
if (!client || !displayedAssignment || !selectedSkipReason) return;
|
|
13791
|
+
import_react_native4.Keyboard.dismiss();
|
|
13670
13792
|
setSkipping(true);
|
|
13671
13793
|
await client.skipAssignment(displayedAssignment.id, {
|
|
13672
13794
|
reason: selectedSkipReason,
|
|
@@ -13735,7 +13857,9 @@ function TestDetailScreen({ testId, nav }) {
|
|
|
13735
13857
|
{
|
|
13736
13858
|
style: styles2.navigateButton,
|
|
13737
13859
|
onPress: () => {
|
|
13860
|
+
import_react_native4.Keyboard.dismiss();
|
|
13738
13861
|
onNavigate(testCase.targetRoute);
|
|
13862
|
+
nav.closeWidget?.();
|
|
13739
13863
|
}
|
|
13740
13864
|
},
|
|
13741
13865
|
/* @__PURE__ */ import_react4.default.createElement(import_react_native4.Text, { style: styles2.navigateText }, "\u{1F9ED} Go to test location")
|
|
@@ -14296,12 +14420,18 @@ function ReportScreen({ nav, prefill }) {
|
|
|
14296
14420
|
const [reportType, setReportType] = (0, import_react10.useState)(prefill?.type || "bug");
|
|
14297
14421
|
const [severity, setSeverity] = (0, import_react10.useState)("medium");
|
|
14298
14422
|
const [description, setDescription] = (0, import_react10.useState)("");
|
|
14423
|
+
const [affectedScreen, setAffectedScreen] = (0, import_react10.useState)("");
|
|
14299
14424
|
const [submitting, setSubmitting] = (0, import_react10.useState)(false);
|
|
14300
14425
|
const images = useImageAttachments(uploadImage, 5, "screenshots");
|
|
14301
14426
|
const isBugType = reportType === "bug" || reportType === "test_fail";
|
|
14302
14427
|
const handleSubmit = async () => {
|
|
14303
14428
|
if (!client || !description.trim()) return;
|
|
14304
14429
|
setSubmitting(true);
|
|
14430
|
+
const baseContext = client.getAppContext();
|
|
14431
|
+
const appContext = {
|
|
14432
|
+
...baseContext,
|
|
14433
|
+
currentRoute: affectedScreen.trim() || baseContext.currentRoute
|
|
14434
|
+
};
|
|
14305
14435
|
const screenshotUrls = images.getScreenshotUrls();
|
|
14306
14436
|
await client.submitReport({
|
|
14307
14437
|
type: reportType,
|
|
@@ -14309,7 +14439,7 @@ function ReportScreen({ nav, prefill }) {
|
|
|
14309
14439
|
severity: isBugType ? severity : void 0,
|
|
14310
14440
|
assignmentId: prefill?.assignmentId,
|
|
14311
14441
|
testCaseId: prefill?.testCaseId,
|
|
14312
|
-
appContext
|
|
14442
|
+
appContext,
|
|
14313
14443
|
deviceInfo: getDeviceInfo(),
|
|
14314
14444
|
screenshots: screenshotUrls.length > 0 ? screenshotUrls : void 0
|
|
14315
14445
|
});
|
|
@@ -14357,7 +14487,16 @@ function ReportScreen({ nav, prefill }) {
|
|
|
14357
14487
|
numberOfLines: 4,
|
|
14358
14488
|
textAlignVertical: "top"
|
|
14359
14489
|
}
|
|
14360
|
-
)), /* @__PURE__ */ import_react10.default.createElement(
|
|
14490
|
+
)), 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(
|
|
14491
|
+
import_react_native9.TextInput,
|
|
14492
|
+
{
|
|
14493
|
+
style: styles7.screenInput,
|
|
14494
|
+
value: affectedScreen,
|
|
14495
|
+
onChangeText: setAffectedScreen,
|
|
14496
|
+
placeholder: "e.g. Reservations, Settings...",
|
|
14497
|
+
placeholderTextColor: colors.textMuted
|
|
14498
|
+
}
|
|
14499
|
+
), /* @__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(
|
|
14361
14500
|
ImagePickerButtons,
|
|
14362
14501
|
{
|
|
14363
14502
|
images: images.images,
|
|
@@ -14388,7 +14527,9 @@ var styles7 = import_react_native9.StyleSheet.create({
|
|
|
14388
14527
|
severityRow: { flexDirection: "row", gap: 8 },
|
|
14389
14528
|
sevButton: { flex: 1, paddingVertical: 8, borderRadius: 8, alignItems: "center", borderWidth: 1, borderColor: colors.border, backgroundColor: colors.card },
|
|
14390
14529
|
sevText: { fontSize: 12, fontWeight: "500", color: colors.textSecondary, textTransform: "capitalize" },
|
|
14391
|
-
descInput: { backgroundColor: colors.card, borderWidth: 1, borderColor: colors.border, borderRadius: 12, paddingHorizontal: 14, paddingVertical: 12, fontSize: 14, color: colors.textPrimary, minHeight: 100 }
|
|
14530
|
+
descInput: { backgroundColor: colors.card, borderWidth: 1, borderColor: colors.border, borderRadius: 12, paddingHorizontal: 14, paddingVertical: 12, fontSize: 14, color: colors.textPrimary, minHeight: 100 },
|
|
14531
|
+
screenInput: { backgroundColor: colors.card, borderWidth: 1, borderColor: colors.border, borderRadius: 8, paddingHorizontal: 12, paddingVertical: 8, fontSize: 13, color: colors.textPrimary },
|
|
14532
|
+
screenHint: { fontSize: 11, color: colors.textMuted, marginTop: 4 }
|
|
14392
14533
|
});
|
|
14393
14534
|
|
|
14394
14535
|
// src/widget/screens/ReportSuccessScreen.tsx
|
|
@@ -14859,10 +15000,29 @@ function BugBearButton({
|
|
|
14859
15000
|
}
|
|
14860
15001
|
};
|
|
14861
15002
|
const handleClose = () => {
|
|
15003
|
+
import_react_native15.Keyboard.dismiss();
|
|
14862
15004
|
setModalVisible(false);
|
|
14863
|
-
reset();
|
|
14864
15005
|
};
|
|
14865
|
-
const nav = {
|
|
15006
|
+
const nav = {
|
|
15007
|
+
push: (screen) => {
|
|
15008
|
+
import_react_native15.Keyboard.dismiss();
|
|
15009
|
+
push(screen);
|
|
15010
|
+
},
|
|
15011
|
+
pop: () => {
|
|
15012
|
+
import_react_native15.Keyboard.dismiss();
|
|
15013
|
+
pop();
|
|
15014
|
+
},
|
|
15015
|
+
replace: (screen) => {
|
|
15016
|
+
import_react_native15.Keyboard.dismiss();
|
|
15017
|
+
replace(screen);
|
|
15018
|
+
},
|
|
15019
|
+
reset: () => {
|
|
15020
|
+
import_react_native15.Keyboard.dismiss();
|
|
15021
|
+
reset();
|
|
15022
|
+
},
|
|
15023
|
+
canGoBack,
|
|
15024
|
+
closeWidget: handleClose
|
|
15025
|
+
};
|
|
14866
15026
|
const renderScreen = () => {
|
|
14867
15027
|
switch (currentScreen.name) {
|
|
14868
15028
|
case "HOME":
|
|
@@ -14919,7 +15079,7 @@ function BugBearButton({
|
|
|
14919
15079
|
behavior: import_react_native15.Platform.OS === "ios" ? "padding" : "height",
|
|
14920
15080
|
style: styles13.modalOverlay
|
|
14921
15081
|
},
|
|
14922
|
-
/* @__PURE__ */ import_react16.default.createElement(import_react_native15.View, { style: styles13.modalContainer }, /* @__PURE__ */ import_react16.default.createElement(import_react_native15.View, { style: styles13.header }, /* @__PURE__ */ import_react16.default.createElement(import_react_native15.View, { style: styles13.headerLeft }, canGoBack ? /* @__PURE__ */ import_react16.default.createElement(import_react_native15.TouchableOpacity, { onPress: pop, style: styles13.backButton }, /* @__PURE__ */ import_react16.default.createElement(import_react_native15.Text, { style: styles13.backText }, "\u2190 Back")) : /* @__PURE__ */ import_react16.default.createElement(import_react_native15.View, { style: styles13.headerTitleRow }, /* @__PURE__ */ import_react16.default.createElement(import_react_native15.Text, { style: styles13.headerTitle }, "BugBear"), testerInfo && /* @__PURE__ */ import_react16.default.createElement(import_react_native15.TouchableOpacity, { onPress: () => push({ name: "PROFILE" }) }, /* @__PURE__ */ import_react16.default.createElement(import_react_native15.Text, { style: styles13.headerName }, testerInfo.name, " \u270E")))), getHeaderTitle() ? /* @__PURE__ */ import_react16.default.createElement(import_react_native15.Text, { style: styles13.headerScreenTitle, numberOfLines: 1 }, getHeaderTitle()) : null, /* @__PURE__ */ import_react16.default.createElement(import_react_native15.TouchableOpacity, { onPress: handleClose, style: styles13.closeButton }, /* @__PURE__ */ import_react16.default.createElement(import_react_native15.Text, { style: styles13.closeText }, "\u2715"))), /* @__PURE__ */ import_react16.default.createElement(
|
|
15082
|
+
/* @__PURE__ */ import_react16.default.createElement(import_react_native15.View, { style: styles13.modalContainer }, /* @__PURE__ */ import_react16.default.createElement(import_react_native15.View, { style: styles13.header }, /* @__PURE__ */ import_react16.default.createElement(import_react_native15.View, { style: styles13.headerLeft }, canGoBack ? /* @__PURE__ */ import_react16.default.createElement(import_react_native15.View, { style: styles13.headerNavRow }, /* @__PURE__ */ import_react16.default.createElement(import_react_native15.TouchableOpacity, { onPress: () => nav.pop(), style: styles13.backButton }, /* @__PURE__ */ import_react16.default.createElement(import_react_native15.Text, { style: styles13.backText }, "\u2190 Back")), /* @__PURE__ */ import_react16.default.createElement(import_react_native15.TouchableOpacity, { onPress: () => nav.reset(), style: styles13.homeButton }, /* @__PURE__ */ import_react16.default.createElement(import_react_native15.Text, { style: styles13.homeText }, "\u{1F3E0}"))) : /* @__PURE__ */ import_react16.default.createElement(import_react_native15.View, { style: styles13.headerTitleRow }, /* @__PURE__ */ import_react16.default.createElement(import_react_native15.Text, { style: styles13.headerTitle }, "BugBear"), testerInfo && /* @__PURE__ */ import_react16.default.createElement(import_react_native15.TouchableOpacity, { onPress: () => push({ name: "PROFILE" }) }, /* @__PURE__ */ import_react16.default.createElement(import_react_native15.Text, { style: styles13.headerName }, testerInfo.name, " \u270E")))), getHeaderTitle() ? /* @__PURE__ */ import_react16.default.createElement(import_react_native15.Text, { style: styles13.headerScreenTitle, numberOfLines: 1 }, getHeaderTitle()) : null, /* @__PURE__ */ import_react16.default.createElement(import_react_native15.TouchableOpacity, { onPress: handleClose, style: styles13.closeButton }, /* @__PURE__ */ import_react16.default.createElement(import_react_native15.Text, { style: styles13.closeText }, "\u2715"))), /* @__PURE__ */ import_react16.default.createElement(
|
|
14923
15083
|
import_react_native15.ScrollView,
|
|
14924
15084
|
{
|
|
14925
15085
|
style: styles13.content,
|
|
@@ -15020,15 +15180,27 @@ var styles13 = import_react_native15.StyleSheet.create({
|
|
|
15020
15180
|
flex: 1,
|
|
15021
15181
|
textAlign: "center"
|
|
15022
15182
|
},
|
|
15183
|
+
headerNavRow: {
|
|
15184
|
+
flexDirection: "row",
|
|
15185
|
+
alignItems: "center",
|
|
15186
|
+
gap: 8
|
|
15187
|
+
},
|
|
15023
15188
|
backButton: {
|
|
15024
15189
|
paddingVertical: 2,
|
|
15025
|
-
paddingRight:
|
|
15190
|
+
paddingRight: 4
|
|
15026
15191
|
},
|
|
15027
15192
|
backText: {
|
|
15028
15193
|
fontSize: 15,
|
|
15029
15194
|
color: colors.blue,
|
|
15030
15195
|
fontWeight: "500"
|
|
15031
15196
|
},
|
|
15197
|
+
homeButton: {
|
|
15198
|
+
paddingVertical: 2,
|
|
15199
|
+
paddingHorizontal: 6
|
|
15200
|
+
},
|
|
15201
|
+
homeText: {
|
|
15202
|
+
fontSize: 16
|
|
15203
|
+
},
|
|
15032
15204
|
closeButton: {
|
|
15033
15205
|
width: 32,
|
|
15034
15206
|
height: 32,
|