quick-bug-reporter-react 1.3.2 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +171 -36
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +171 -36
- package/dist/index.js.map +1 -1
- package/package.json +11 -9
package/dist/index.cjs
CHANGED
|
@@ -882,42 +882,100 @@ var CloudIntegration = class {
|
|
|
882
882
|
throw new Error("CloudIntegration: projectKey is required.");
|
|
883
883
|
}
|
|
884
884
|
this.projectKey = options.projectKey;
|
|
885
|
-
this.endpoint = options.endpoint ?? "/api/ingest";
|
|
885
|
+
this.endpoint = options.ingestUrl ?? options.endpoint ?? "/api/ingest";
|
|
886
|
+
this.appVersion = options.appVersion;
|
|
887
|
+
this.environment = options.environment;
|
|
886
888
|
this.fetchFn = options.fetchImpl ?? fetch.bind(globalThis);
|
|
887
889
|
}
|
|
888
890
|
async submit(payload, onProgress = noop3) {
|
|
889
891
|
onProgress("Preparing report\u2026");
|
|
890
|
-
const ua = payload.userAgent ||
|
|
892
|
+
const ua = payload.userAgent || getRuntimeUserAgent();
|
|
891
893
|
const browserName = parseBrowserName(ua);
|
|
894
|
+
const browserVersion = parseBrowserVersion(ua);
|
|
892
895
|
const osName = parseOsName(ua);
|
|
893
|
-
const
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
896
|
+
const osVersion = parseOsVersion(ua, osName);
|
|
897
|
+
const fd = new FormData();
|
|
898
|
+
fd.set("project_key", this.projectKey);
|
|
899
|
+
fd.set("title", payload.title);
|
|
900
|
+
fd.set("description", payload.description || "");
|
|
901
|
+
fd.set("provider", "cloud");
|
|
902
|
+
fd.set("capture_mode", payload.captureMode);
|
|
903
|
+
fd.set("has_screenshot", String(Boolean(payload.screenshotBlob)));
|
|
904
|
+
fd.set("has_video", String(Boolean(payload.videoBlob)));
|
|
905
|
+
fd.set("has_network_logs", String(payload.networkLogs.length > 0));
|
|
906
|
+
fd.set("has_console_logs", String(payload.consoleLogs.length > 0));
|
|
907
|
+
fd.set("js_error_count", String(payload.jsErrors.length));
|
|
908
|
+
fd.set("user_agent", ua);
|
|
909
|
+
fd.set("browser_name", browserName);
|
|
910
|
+
fd.set("browser_version", browserVersion ?? "");
|
|
911
|
+
fd.set("os_name", osName);
|
|
912
|
+
fd.set("os_version", osVersion ?? "");
|
|
913
|
+
fd.set("device_type", getDeviceType());
|
|
914
|
+
fd.set("screen_resolution", getScreenResolution());
|
|
915
|
+
fd.set("viewport", getViewport());
|
|
916
|
+
fd.set("color_scheme", payload.metadata.colorScheme !== "unknown" ? payload.metadata.colorScheme : "");
|
|
917
|
+
fd.set("locale", payload.metadata.locale ?? "");
|
|
918
|
+
fd.set("timezone", payload.metadata.timezone ?? "");
|
|
919
|
+
fd.set("connection_type", payload.metadata.connection?.effectiveType ?? "");
|
|
920
|
+
fd.set("page_url", payload.pageUrl || "");
|
|
921
|
+
fd.set("environment", this.environment ?? getEnvironment());
|
|
922
|
+
fd.set("app_version", this.appVersion ?? "");
|
|
923
|
+
fd.set("platform", payload.metadata.platform ?? "");
|
|
924
|
+
fd.set("duration_ms", String(payload.elapsedMs));
|
|
925
|
+
fd.set("stopped_at", payload.stoppedAt || "");
|
|
926
|
+
if (payload.metadata.mobile) {
|
|
927
|
+
fd.set("platform", payload.metadata.mobile.platform);
|
|
928
|
+
fd.set("device_model", payload.metadata.mobile.deviceModel ?? "");
|
|
929
|
+
fd.set("device_brand", payload.metadata.mobile.deviceBrand ?? "");
|
|
930
|
+
fd.set("os_version", payload.metadata.mobile.osVersion ?? "");
|
|
931
|
+
fd.set("app_build_number", payload.metadata.mobile.appBuildNumber ?? "");
|
|
932
|
+
fd.set("is_emulator", String(payload.metadata.mobile.isEmulator));
|
|
933
|
+
fd.set(
|
|
934
|
+
"battery_level",
|
|
935
|
+
payload.metadata.mobile.batteryLevel == null ? "" : String(payload.metadata.mobile.batteryLevel)
|
|
936
|
+
);
|
|
937
|
+
fd.set(
|
|
938
|
+
"free_storage_mb",
|
|
939
|
+
payload.metadata.mobile.freeStorageMb == null ? "" : String(payload.metadata.mobile.freeStorageMb)
|
|
940
|
+
);
|
|
941
|
+
fd.set("invocation_method", payload.metadata.mobile.invocationMethod);
|
|
942
|
+
}
|
|
943
|
+
if (payload.screenshotBlob) {
|
|
944
|
+
fd.append("screenshot", payload.screenshotBlob, "bug-screenshot.png");
|
|
945
|
+
}
|
|
946
|
+
if (payload.videoBlob) {
|
|
947
|
+
fd.append("video", payload.videoBlob, "bug-recording.webm");
|
|
948
|
+
}
|
|
949
|
+
fd.append(
|
|
950
|
+
"network_logs",
|
|
951
|
+
new Blob([formatNetworkLogs(payload.networkLogs)], { type: "text/plain" }),
|
|
952
|
+
"network-logs.txt"
|
|
953
|
+
);
|
|
954
|
+
const parts = [];
|
|
955
|
+
if (payload.jsErrors.length > 0) {
|
|
956
|
+
parts.push("=== JavaScript Errors ===\n" + formatJsErrors(payload.jsErrors));
|
|
957
|
+
} else {
|
|
958
|
+
parts.push("=== JavaScript Errors ===\nNo JavaScript errors captured.");
|
|
959
|
+
}
|
|
960
|
+
if (payload.consoleLogs.length > 0) {
|
|
961
|
+
parts.push("=== Console Output ===\n" + formatConsoleLogs(payload.consoleLogs));
|
|
962
|
+
} else {
|
|
963
|
+
parts.push("=== Console Output ===\nNo console output captured.");
|
|
964
|
+
}
|
|
965
|
+
fd.append(
|
|
966
|
+
"console_logs",
|
|
967
|
+
new Blob([parts.join("\n\n")], { type: "text/plain" }),
|
|
968
|
+
"console-logs.txt"
|
|
969
|
+
);
|
|
970
|
+
fd.append(
|
|
971
|
+
"metadata",
|
|
972
|
+
new Blob([JSON.stringify(payload.metadata, null, 2)], { type: "application/json" }),
|
|
973
|
+
"client-metadata.json"
|
|
974
|
+
);
|
|
916
975
|
onProgress("Sending report\u2026");
|
|
917
976
|
const response = await this.fetchFn(this.endpoint, {
|
|
918
977
|
method: "POST",
|
|
919
|
-
|
|
920
|
-
body: JSON.stringify(body)
|
|
978
|
+
body: fd
|
|
921
979
|
});
|
|
922
980
|
if (!response.ok) {
|
|
923
981
|
const errorBody = await response.json().catch(() => ({}));
|
|
@@ -926,12 +984,22 @@ var CloudIntegration = class {
|
|
|
926
984
|
}
|
|
927
985
|
const result = await response.json();
|
|
928
986
|
onProgress("Report submitted.");
|
|
987
|
+
const fwd = result.forwarding;
|
|
988
|
+
const externalKey = fwd?.key;
|
|
989
|
+
const externalUrl = fwd?.url;
|
|
990
|
+
const warnings = [];
|
|
991
|
+
if (result.forwarding_status === "queued") {
|
|
992
|
+
warnings.push("Tracker forwarding is running in the background.");
|
|
993
|
+
}
|
|
994
|
+
if (fwd?.error) {
|
|
995
|
+
warnings.push(`Forwarding: ${fwd.error}`);
|
|
996
|
+
}
|
|
929
997
|
return {
|
|
930
998
|
provider: "cloud",
|
|
931
999
|
issueId: result.id,
|
|
932
|
-
issueKey: `QB-${result.id.slice(0, 8)}`,
|
|
933
|
-
issueUrl: null,
|
|
934
|
-
warnings
|
|
1000
|
+
issueKey: externalKey || `QB-${result.id.slice(0, 8)}`,
|
|
1001
|
+
issueUrl: externalUrl || null,
|
|
1002
|
+
warnings
|
|
935
1003
|
};
|
|
936
1004
|
}
|
|
937
1005
|
};
|
|
@@ -943,14 +1011,50 @@ function parseBrowserName(ua) {
|
|
|
943
1011
|
if (ua.includes("Safari/") && !ua.includes("Chrome/")) return "Safari";
|
|
944
1012
|
return "Unknown";
|
|
945
1013
|
}
|
|
1014
|
+
function parseBrowserVersion(ua) {
|
|
1015
|
+
return matchVersion(ua, /Edg\/([\d.]+)/) || matchVersion(ua, /OPR\/([\d.]+)/) || matchVersion(ua, /Opera\/([\d.]+)/) || matchVersion(ua, /Chrome\/([\d.]+)/) || matchVersion(ua, /Firefox\/([\d.]+)/) || matchVersion(ua, /Version\/([\d.]+).*Safari/);
|
|
1016
|
+
}
|
|
1017
|
+
function getRuntimeUserAgent() {
|
|
1018
|
+
if (typeof navigator !== "undefined" && typeof navigator.userAgent === "string") {
|
|
1019
|
+
return navigator.userAgent;
|
|
1020
|
+
}
|
|
1021
|
+
return "";
|
|
1022
|
+
}
|
|
946
1023
|
function parseOsName(ua) {
|
|
947
1024
|
if (ua.includes("Windows")) return "Windows";
|
|
948
|
-
if (ua.includes("Mac OS")) return "macOS";
|
|
949
|
-
if (ua.includes("Linux")) return "Linux";
|
|
950
1025
|
if (ua.includes("Android")) return "Android";
|
|
951
1026
|
if (ua.includes("iPhone") || ua.includes("iPad")) return "iOS";
|
|
1027
|
+
if (ua.includes("Mac OS")) return "macOS";
|
|
1028
|
+
if (ua.includes("Linux")) return "Linux";
|
|
952
1029
|
return "Unknown";
|
|
953
1030
|
}
|
|
1031
|
+
function parseOsVersion(ua, osName) {
|
|
1032
|
+
if (osName === "Windows") {
|
|
1033
|
+
const nt = matchVersion(ua, /Windows NT ([\d.]+)/);
|
|
1034
|
+
if (!nt) return null;
|
|
1035
|
+
if (nt.startsWith("10.0")) return "10/11";
|
|
1036
|
+
if (nt.startsWith("6.3")) return "8.1";
|
|
1037
|
+
if (nt.startsWith("6.2")) return "8";
|
|
1038
|
+
if (nt.startsWith("6.1")) return "7";
|
|
1039
|
+
return nt;
|
|
1040
|
+
}
|
|
1041
|
+
if (osName === "macOS") {
|
|
1042
|
+
const mac = matchVersion(ua, /Mac OS X ([0-9_]+)/);
|
|
1043
|
+
return mac ? mac.replace(/_/g, ".") : null;
|
|
1044
|
+
}
|
|
1045
|
+
if (osName === "Android") {
|
|
1046
|
+
return matchVersion(ua, /Android ([\d.]+)/);
|
|
1047
|
+
}
|
|
1048
|
+
if (osName === "iOS") {
|
|
1049
|
+
const ios = matchVersion(ua, /OS ([0-9_]+) like Mac OS X/);
|
|
1050
|
+
return ios ? ios.replace(/_/g, ".") : null;
|
|
1051
|
+
}
|
|
1052
|
+
return null;
|
|
1053
|
+
}
|
|
1054
|
+
function matchVersion(ua, pattern) {
|
|
1055
|
+
const match = ua.match(pattern);
|
|
1056
|
+
return match?.[1] ?? null;
|
|
1057
|
+
}
|
|
954
1058
|
function getDeviceType() {
|
|
955
1059
|
if (typeof window === "undefined") return "unknown";
|
|
956
1060
|
const w = window.innerWidth;
|
|
@@ -1429,6 +1533,7 @@ var BugSession = class {
|
|
|
1429
1533
|
this.autoStopTimeout = null;
|
|
1430
1534
|
this.stopInFlight = null;
|
|
1431
1535
|
this.lastArtifacts = null;
|
|
1536
|
+
this.screenshotLogsPendingSubmit = false;
|
|
1432
1537
|
this.maxDurationMs = options.maxDurationMs ?? DEFAULT_MAX_RECORDING_MS;
|
|
1433
1538
|
this.screenRecorder = options.screenRecorder ?? new ScreenRecorder();
|
|
1434
1539
|
this.screenshotCapturer = options.screenshotCapturer ?? new ScreenshotCapturer();
|
|
@@ -1439,9 +1544,13 @@ var BugSession = class {
|
|
|
1439
1544
|
if (this.recording) {
|
|
1440
1545
|
return;
|
|
1441
1546
|
}
|
|
1547
|
+
if (this.networkLogger.isRecording()) {
|
|
1548
|
+
this.networkLogger.stop();
|
|
1549
|
+
}
|
|
1442
1550
|
this.clearAutoStopTimer();
|
|
1443
1551
|
this.networkLogger.clear();
|
|
1444
1552
|
this.lastArtifacts = null;
|
|
1553
|
+
this.screenshotLogsPendingSubmit = false;
|
|
1445
1554
|
this.networkLogger.start();
|
|
1446
1555
|
try {
|
|
1447
1556
|
await this.screenRecorder.start({
|
|
@@ -1464,14 +1573,18 @@ var BugSession = class {
|
|
|
1464
1573
|
if (this.recording) {
|
|
1465
1574
|
await this.stop("manual");
|
|
1466
1575
|
}
|
|
1576
|
+
if (this.networkLogger.isRecording()) {
|
|
1577
|
+
this.networkLogger.stop();
|
|
1578
|
+
}
|
|
1467
1579
|
this.clearAutoStopTimer();
|
|
1468
1580
|
this.networkLogger.clear();
|
|
1469
1581
|
this.lastArtifacts = null;
|
|
1582
|
+
this.screenshotLogsPendingSubmit = false;
|
|
1470
1583
|
const startedAtMs = Date.now();
|
|
1471
1584
|
this.networkLogger.start();
|
|
1472
1585
|
try {
|
|
1473
1586
|
const screenshotBlob = region ? await this.screenshotCapturer.captureRegion(region) : await this.screenshotCapturer.capture();
|
|
1474
|
-
const networkLogs = this.networkLogger.
|
|
1587
|
+
const networkLogs = this.networkLogger.getLogs();
|
|
1475
1588
|
const stoppedAtMs = Date.now();
|
|
1476
1589
|
const artifacts = {
|
|
1477
1590
|
videoBlob: null,
|
|
@@ -1484,10 +1597,12 @@ var BugSession = class {
|
|
|
1484
1597
|
stopReason: "manual"
|
|
1485
1598
|
};
|
|
1486
1599
|
this.lastArtifacts = artifacts;
|
|
1600
|
+
this.screenshotLogsPendingSubmit = true;
|
|
1487
1601
|
return artifacts;
|
|
1488
1602
|
} catch (error) {
|
|
1489
1603
|
this.networkLogger.stop();
|
|
1490
1604
|
this.networkLogger.clear();
|
|
1605
|
+
this.screenshotLogsPendingSubmit = false;
|
|
1491
1606
|
throw error;
|
|
1492
1607
|
}
|
|
1493
1608
|
}
|
|
@@ -1521,17 +1636,32 @@ var BugSession = class {
|
|
|
1521
1636
|
getLastCaptureMode() {
|
|
1522
1637
|
return this.lastArtifacts?.captureMode ?? null;
|
|
1523
1638
|
}
|
|
1639
|
+
finalizeNetworkLogsForSubmit(captureMode) {
|
|
1640
|
+
if (captureMode === "screenshot" && this.screenshotLogsPendingSubmit && this.networkLogger.isRecording()) {
|
|
1641
|
+
const logs = this.networkLogger.stop();
|
|
1642
|
+
this.screenshotLogsPendingSubmit = false;
|
|
1643
|
+
return logs;
|
|
1644
|
+
}
|
|
1645
|
+
return this.networkLogger.getLogs();
|
|
1646
|
+
}
|
|
1524
1647
|
resetArtifacts() {
|
|
1525
1648
|
this.lastArtifacts = null;
|
|
1526
1649
|
this.screenRecorder.clearLastBlob();
|
|
1650
|
+
if (this.networkLogger.isRecording()) {
|
|
1651
|
+
this.networkLogger.stop();
|
|
1652
|
+
}
|
|
1527
1653
|
this.networkLogger.clear();
|
|
1654
|
+
this.screenshotLogsPendingSubmit = false;
|
|
1528
1655
|
}
|
|
1529
1656
|
async dispose() {
|
|
1530
1657
|
await this.stop("manual");
|
|
1531
1658
|
this.clearAutoStopTimer();
|
|
1532
1659
|
this.screenRecorder.dispose();
|
|
1533
|
-
this.networkLogger.
|
|
1660
|
+
if (this.networkLogger.isRecording()) {
|
|
1661
|
+
this.networkLogger.stop();
|
|
1662
|
+
}
|
|
1534
1663
|
this.networkLogger.clear();
|
|
1664
|
+
this.screenshotLogsPendingSubmit = false;
|
|
1535
1665
|
}
|
|
1536
1666
|
async stopInternal(reason) {
|
|
1537
1667
|
this.clearAutoStopTimer();
|
|
@@ -1552,6 +1682,7 @@ var BugSession = class {
|
|
|
1552
1682
|
stopReason: reason
|
|
1553
1683
|
};
|
|
1554
1684
|
this.lastArtifacts = artifacts;
|
|
1685
|
+
this.screenshotLogsPendingSubmit = false;
|
|
1555
1686
|
return artifacts;
|
|
1556
1687
|
}
|
|
1557
1688
|
async handleForcedStop(reason) {
|
|
@@ -1704,7 +1835,7 @@ var BugReporter = class {
|
|
|
1704
1835
|
description: normalizedDescription,
|
|
1705
1836
|
videoBlob: artifacts.videoBlob,
|
|
1706
1837
|
screenshotBlob: options.screenshotBlob ?? artifacts.screenshotBlob,
|
|
1707
|
-
networkLogs: artifacts.
|
|
1838
|
+
networkLogs: this.session.finalizeNetworkLogsForSubmit(artifacts.captureMode),
|
|
1708
1839
|
consoleLogs: options.consoleLogs ?? [],
|
|
1709
1840
|
jsErrors: options.jsErrors ?? [],
|
|
1710
1841
|
captureMode: artifacts.captureMode,
|
|
@@ -2274,7 +2405,11 @@ function BugReporterProvider({
|
|
|
2274
2405
|
jsErrors,
|
|
2275
2406
|
onProgress: setSubmissionProgress
|
|
2276
2407
|
});
|
|
2277
|
-
|
|
2408
|
+
if (result.provider === "cloud" && !result.issueUrl) {
|
|
2409
|
+
setSuccess("Report received by QuickBugs Cloud. Tracker forwarding is running in the background.");
|
|
2410
|
+
} else {
|
|
2411
|
+
setSuccess(`Submitted to ${getProviderLabel(result.provider)} (${result.issueKey}).`);
|
|
2412
|
+
}
|
|
2278
2413
|
clearDraft();
|
|
2279
2414
|
setIsOpen(false);
|
|
2280
2415
|
return result;
|