@fogg/bug-reporter 1.0.0 → 1.0.2
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 +30 -0
- package/dist/index.cjs +552 -205
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +420 -93
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-6TCI6T2U.cjs +0 -45
- package/dist/chunk-6TCI6T2U.cjs.map +0 -1
- package/dist/chunk-S2YRP4GT.js +0 -22
- package/dist/chunk-S2YRP4GT.js.map +0 -1
- package/dist/recording-ML63ZQ6A.cjs +0 -120
- package/dist/recording-ML63ZQ6A.cjs.map +0 -1
- package/dist/recording-YSR6IORT.js +0 -118
- package/dist/recording-YSR6IORT.js.map +0 -1
- package/dist/screenshot-F4W72WRK.js +0 -176
- package/dist/screenshot-F4W72WRK.js.map +0 -1
- package/dist/screenshot-FRAZAS6B.cjs +0 -178
- package/dist/screenshot-FRAZAS6B.cjs.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1,8 +1,35 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var react = require('react');
|
|
3
|
+
var React = require('react');
|
|
5
4
|
var reactDom = require('react-dom');
|
|
5
|
+
var html2canvas = require('html2canvas');
|
|
6
|
+
|
|
7
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
8
|
+
|
|
9
|
+
function _interopNamespace(e) {
|
|
10
|
+
if (e && e.__esModule) return e;
|
|
11
|
+
var n = Object.create(null);
|
|
12
|
+
if (e) {
|
|
13
|
+
Object.keys(e).forEach(function (k) {
|
|
14
|
+
if (k !== 'default') {
|
|
15
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
16
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
17
|
+
enumerable: true,
|
|
18
|
+
get: function () { return e[k]; }
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
n.default = e;
|
|
24
|
+
return Object.freeze(n);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
28
|
+
var html2canvas__default = /*#__PURE__*/_interopDefault(html2canvas);
|
|
29
|
+
|
|
30
|
+
var __defProp = Object.defineProperty;
|
|
31
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
32
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
6
33
|
|
|
7
34
|
// src/diagnostics/ua.ts
|
|
8
35
|
function detectBrowserAndOS(userAgent) {
|
|
@@ -22,12 +49,13 @@ function detectBrowserAndOS(userAgent) {
|
|
|
22
49
|
|
|
23
50
|
// src/diagnostics/collect.ts
|
|
24
51
|
function getUserAgentDataSnapshot() {
|
|
52
|
+
var _a;
|
|
25
53
|
const userAgentData = navigator.userAgentData;
|
|
26
54
|
if (!userAgentData) {
|
|
27
55
|
return void 0;
|
|
28
56
|
}
|
|
29
57
|
return {
|
|
30
|
-
brands: userAgentData.brands
|
|
58
|
+
brands: (_a = userAgentData.brands) == null ? void 0 : _a.map((item) => ({
|
|
31
59
|
brand: item.brand,
|
|
32
60
|
version: item.version
|
|
33
61
|
})),
|
|
@@ -56,12 +84,12 @@ function collectDiagnostics(config, options) {
|
|
|
56
84
|
appVersion: config.appVersion,
|
|
57
85
|
environment: config.environment,
|
|
58
86
|
projectId: config.projectId,
|
|
59
|
-
logs: options
|
|
60
|
-
requests: options
|
|
87
|
+
logs: options == null ? void 0 : options.logs,
|
|
88
|
+
requests: options == null ? void 0 : options.requests,
|
|
61
89
|
navigationTiming: {
|
|
62
|
-
domComplete: nav
|
|
63
|
-
loadEventEnd: nav
|
|
64
|
-
responseEnd: nav
|
|
90
|
+
domComplete: nav == null ? void 0 : nav.domComplete,
|
|
91
|
+
loadEventEnd: nav == null ? void 0 : nav.loadEventEnd,
|
|
92
|
+
responseEnd: nav == null ? void 0 : nav.responseEnd
|
|
65
93
|
}
|
|
66
94
|
};
|
|
67
95
|
}
|
|
@@ -70,13 +98,14 @@ function collectDiagnostics(config, options) {
|
|
|
70
98
|
var ConsoleBuffer = class {
|
|
71
99
|
constructor(maxEntries) {
|
|
72
100
|
this.maxEntries = maxEntries;
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
101
|
+
__publicField(this, "entries", []);
|
|
102
|
+
__publicField(this, "originals", /* @__PURE__ */ new Map());
|
|
103
|
+
__publicField(this, "installed", false);
|
|
104
|
+
__publicField(this, "onWindowError", (event) => {
|
|
105
|
+
var _a;
|
|
106
|
+
this.push("error", [event.message, event.error instanceof Error ? (_a = event.error.stack) != null ? _a : "" : ""]);
|
|
78
107
|
});
|
|
79
|
-
|
|
108
|
+
__publicField(this, "onUnhandledRejection", (event) => {
|
|
80
109
|
this.push("error", ["Unhandled promise rejection", event.reason]);
|
|
81
110
|
});
|
|
82
111
|
}
|
|
@@ -126,7 +155,7 @@ var ConsoleBuffer = class {
|
|
|
126
155
|
}
|
|
127
156
|
try {
|
|
128
157
|
return JSON.stringify(arg);
|
|
129
|
-
} catch {
|
|
158
|
+
} catch (e) {
|
|
130
159
|
return String(arg);
|
|
131
160
|
}
|
|
132
161
|
}).join(" ");
|
|
@@ -153,7 +182,7 @@ function extractUrl(input) {
|
|
|
153
182
|
return input.url;
|
|
154
183
|
}
|
|
155
184
|
function extractMethod(input, init) {
|
|
156
|
-
if (init
|
|
185
|
+
if (init == null ? void 0 : init.method) {
|
|
157
186
|
return String(init.method).toUpperCase();
|
|
158
187
|
}
|
|
159
188
|
if (typeof Request !== "undefined" && input instanceof Request) {
|
|
@@ -164,11 +193,11 @@ function extractMethod(input, init) {
|
|
|
164
193
|
var NetworkBuffer = class {
|
|
165
194
|
constructor(maxEntries) {
|
|
166
195
|
this.maxEntries = maxEntries;
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
196
|
+
__publicField(this, "entries", []);
|
|
197
|
+
__publicField(this, "installed", false);
|
|
198
|
+
__publicField(this, "originalFetch");
|
|
199
|
+
__publicField(this, "originalXhrOpen");
|
|
200
|
+
__publicField(this, "originalXhrSend");
|
|
172
201
|
}
|
|
173
202
|
install() {
|
|
174
203
|
if (this.installed) {
|
|
@@ -243,15 +272,17 @@ var NetworkBuffer = class {
|
|
|
243
272
|
this.originalXhrSend = XMLHttpRequest.prototype.send;
|
|
244
273
|
const buffer = this;
|
|
245
274
|
XMLHttpRequest.prototype.open = function patchedOpen(method, url, async, username, password) {
|
|
275
|
+
var _a;
|
|
246
276
|
xhrMeta.set(this, {
|
|
247
277
|
method: String(method || "GET").toUpperCase(),
|
|
248
278
|
url: String(url),
|
|
249
279
|
startedAt: 0,
|
|
250
280
|
timestamp: ""
|
|
251
281
|
});
|
|
252
|
-
buffer.originalXhrOpen
|
|
282
|
+
(_a = buffer.originalXhrOpen) == null ? void 0 : _a.call(this, method, url, async != null ? async : true, username != null ? username : null, password != null ? password : null);
|
|
253
283
|
};
|
|
254
284
|
XMLHttpRequest.prototype.send = function patchedSend(body) {
|
|
285
|
+
var _a;
|
|
255
286
|
const existing = xhrMeta.get(this);
|
|
256
287
|
if (existing) {
|
|
257
288
|
existing.startedAt = performance.now();
|
|
@@ -297,7 +328,7 @@ var NetworkBuffer = class {
|
|
|
297
328
|
this.addEventListener("loadend", onLoadEnd);
|
|
298
329
|
this.addEventListener("error", onError);
|
|
299
330
|
}
|
|
300
|
-
buffer.originalXhrSend
|
|
331
|
+
(_a = buffer.originalXhrSend) == null ? void 0 : _a.call(this, body);
|
|
301
332
|
};
|
|
302
333
|
}
|
|
303
334
|
push(entry) {
|
|
@@ -307,7 +338,7 @@ var NetworkBuffer = class {
|
|
|
307
338
|
}
|
|
308
339
|
}
|
|
309
340
|
};
|
|
310
|
-
var BugReporterContext =
|
|
341
|
+
var BugReporterContext = React.createContext(void 0);
|
|
311
342
|
|
|
312
343
|
// src/core/defaults.ts
|
|
313
344
|
var DEFAULT_MASK_SELECTORS = [
|
|
@@ -315,57 +346,70 @@ var DEFAULT_MASK_SELECTORS = [
|
|
|
315
346
|
"[data-bug-reporter-mask='true']"
|
|
316
347
|
];
|
|
317
348
|
function withDefaults(config) {
|
|
349
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L, _M, _N, _O, _P, _Q, _R, _S, _T, _U, _V;
|
|
318
350
|
return {
|
|
319
351
|
apiEndpoint: config.apiEndpoint,
|
|
320
352
|
projectId: config.projectId,
|
|
321
353
|
appVersion: config.appVersion,
|
|
322
354
|
environment: config.environment,
|
|
323
355
|
storage: {
|
|
324
|
-
mode: config.storage
|
|
325
|
-
s3: config.storage
|
|
326
|
-
local: config.storage
|
|
327
|
-
proxy: config.storage
|
|
356
|
+
mode: (_b = (_a = config.storage) == null ? void 0 : _a.mode) != null ? _b : "proxy",
|
|
357
|
+
s3: (_c = config.storage) == null ? void 0 : _c.s3,
|
|
358
|
+
local: (_d = config.storage) == null ? void 0 : _d.local,
|
|
359
|
+
proxy: (_e = config.storage) == null ? void 0 : _e.proxy,
|
|
328
360
|
limits: {
|
|
329
|
-
maxVideoSeconds: config.storage
|
|
330
|
-
maxVideoBytes: config.storage
|
|
331
|
-
maxScreenshotBytes: config.storage
|
|
361
|
+
maxVideoSeconds: (_h = (_g = (_f = config.storage) == null ? void 0 : _f.limits) == null ? void 0 : _g.maxVideoSeconds) != null ? _h : 30,
|
|
362
|
+
maxVideoBytes: (_k = (_j = (_i = config.storage) == null ? void 0 : _i.limits) == null ? void 0 : _j.maxVideoBytes) != null ? _k : 50 * 1024 * 1024,
|
|
363
|
+
maxScreenshotBytes: (_n = (_m = (_l = config.storage) == null ? void 0 : _l.limits) == null ? void 0 : _m.maxScreenshotBytes) != null ? _n : 8 * 1024 * 1024
|
|
332
364
|
}
|
|
333
365
|
},
|
|
334
366
|
auth: {
|
|
335
|
-
headers: config.auth
|
|
336
|
-
withCredentials: config.auth
|
|
367
|
+
headers: (_p = (_o = config.auth) == null ? void 0 : _o.headers) != null ? _p : {},
|
|
368
|
+
withCredentials: (_r = (_q = config.auth) == null ? void 0 : _q.withCredentials) != null ? _r : false
|
|
337
369
|
},
|
|
338
370
|
theme: {
|
|
339
|
-
primaryColor: config.theme
|
|
340
|
-
position: config.theme
|
|
341
|
-
zIndex: config.theme
|
|
342
|
-
borderRadius: config.theme
|
|
371
|
+
primaryColor: (_t = (_s = config.theme) == null ? void 0 : _s.primaryColor) != null ? _t : "#1b74e4",
|
|
372
|
+
position: (_v = (_u = config.theme) == null ? void 0 : _u.position) != null ? _v : "bottom-right",
|
|
373
|
+
zIndex: (_x = (_w = config.theme) == null ? void 0 : _w.zIndex) != null ? _x : 2147483e3,
|
|
374
|
+
borderRadius: (_z = (_y = config.theme) == null ? void 0 : _y.borderRadius) != null ? _z : "999px"
|
|
343
375
|
},
|
|
344
376
|
features: {
|
|
345
|
-
screenshot: config.features
|
|
346
|
-
recording: config.features
|
|
347
|
-
annotations: config.features
|
|
348
|
-
consoleLogs: config.features
|
|
349
|
-
networkInfo: config.features
|
|
377
|
+
screenshot: (_B = (_A = config.features) == null ? void 0 : _A.screenshot) != null ? _B : true,
|
|
378
|
+
recording: (_D = (_C = config.features) == null ? void 0 : _C.recording) != null ? _D : true,
|
|
379
|
+
annotations: (_F = (_E = config.features) == null ? void 0 : _E.annotations) != null ? _F : true,
|
|
380
|
+
consoleLogs: (_H = (_G = config.features) == null ? void 0 : _G.consoleLogs) != null ? _H : false,
|
|
381
|
+
networkInfo: (_J = (_I = config.features) == null ? void 0 : _I.networkInfo) != null ? _J : false
|
|
350
382
|
},
|
|
351
383
|
user: config.user,
|
|
352
|
-
attributes: config.attributes
|
|
384
|
+
attributes: (_K = config.attributes) != null ? _K : {},
|
|
353
385
|
privacy: {
|
|
354
|
-
maskSelectors: config.privacy
|
|
355
|
-
redactTextPatterns: config.privacy
|
|
386
|
+
maskSelectors: (_M = (_L = config.privacy) == null ? void 0 : _L.maskSelectors) != null ? _M : DEFAULT_MASK_SELECTORS,
|
|
387
|
+
redactTextPatterns: (_O = (_N = config.privacy) == null ? void 0 : _N.redactTextPatterns) != null ? _O : []
|
|
356
388
|
},
|
|
357
389
|
diagnostics: {
|
|
358
|
-
consoleBufferSize: config.diagnostics
|
|
359
|
-
requestBufferSize: config.diagnostics
|
|
390
|
+
consoleBufferSize: (_Q = (_P = config.diagnostics) == null ? void 0 : _P.consoleBufferSize) != null ? _Q : 100,
|
|
391
|
+
requestBufferSize: (_S = (_R = config.diagnostics) == null ? void 0 : _R.requestBufferSize) != null ? _S : 200
|
|
360
392
|
},
|
|
361
393
|
hooks: {
|
|
362
|
-
beforeSubmit: config.hooks
|
|
363
|
-
onSuccess: config.hooks
|
|
364
|
-
onError: config.hooks
|
|
394
|
+
beforeSubmit: (_T = config.hooks) == null ? void 0 : _T.beforeSubmit,
|
|
395
|
+
onSuccess: (_U = config.hooks) == null ? void 0 : _U.onSuccess,
|
|
396
|
+
onError: (_V = config.hooks) == null ? void 0 : _V.onError
|
|
365
397
|
}
|
|
366
398
|
};
|
|
367
399
|
}
|
|
368
400
|
|
|
401
|
+
// src/types/index.ts
|
|
402
|
+
var BugReporterError = class extends Error {
|
|
403
|
+
constructor(code, message, cause) {
|
|
404
|
+
super(message);
|
|
405
|
+
__publicField(this, "code");
|
|
406
|
+
__publicField(this, "cause");
|
|
407
|
+
this.name = "BugReporterError";
|
|
408
|
+
this.code = code;
|
|
409
|
+
this.cause = cause;
|
|
410
|
+
}
|
|
411
|
+
};
|
|
412
|
+
|
|
369
413
|
// src/storage/local-public.ts
|
|
370
414
|
var LocalPublicProvider = class {
|
|
371
415
|
constructor(options) {
|
|
@@ -381,7 +425,7 @@ var LocalPublicProvider = class {
|
|
|
381
425
|
}));
|
|
382
426
|
}
|
|
383
427
|
async upload(instruction, blob, onProgress) {
|
|
384
|
-
onProgress
|
|
428
|
+
onProgress == null ? void 0 : onProgress(0);
|
|
385
429
|
const form = new FormData();
|
|
386
430
|
form.append("file", blob, instruction.id);
|
|
387
431
|
form.append("id", instruction.id);
|
|
@@ -393,10 +437,10 @@ var LocalPublicProvider = class {
|
|
|
393
437
|
body: form
|
|
394
438
|
});
|
|
395
439
|
if (!response.ok) {
|
|
396
|
-
throw new
|
|
440
|
+
throw new BugReporterError("UPLOAD_ERROR", `Local upload failed (${response.status}).`);
|
|
397
441
|
}
|
|
398
442
|
const payload = await response.json();
|
|
399
|
-
onProgress
|
|
443
|
+
onProgress == null ? void 0 : onProgress(1);
|
|
400
444
|
return {
|
|
401
445
|
id: instruction.id,
|
|
402
446
|
type: instruction.type,
|
|
@@ -423,7 +467,7 @@ var ProxyProvider = class {
|
|
|
423
467
|
}));
|
|
424
468
|
}
|
|
425
469
|
async upload(instruction, blob, onProgress) {
|
|
426
|
-
onProgress
|
|
470
|
+
onProgress == null ? void 0 : onProgress(0);
|
|
427
471
|
const response = await fetch(instruction.uploadUrl, {
|
|
428
472
|
method: "POST",
|
|
429
473
|
headers: {
|
|
@@ -436,10 +480,10 @@ var ProxyProvider = class {
|
|
|
436
480
|
body: blob
|
|
437
481
|
});
|
|
438
482
|
if (!response.ok) {
|
|
439
|
-
throw new
|
|
483
|
+
throw new BugReporterError("UPLOAD_ERROR", `Proxy upload failed (${response.status}).`);
|
|
440
484
|
}
|
|
441
485
|
const payload = await response.json();
|
|
442
|
-
onProgress
|
|
486
|
+
onProgress == null ? void 0 : onProgress(1);
|
|
443
487
|
return {
|
|
444
488
|
id: instruction.id,
|
|
445
489
|
type: instruction.type,
|
|
@@ -457,6 +501,7 @@ var S3PresignedProvider = class {
|
|
|
457
501
|
this.options = options;
|
|
458
502
|
}
|
|
459
503
|
async prepareUploads(files) {
|
|
504
|
+
var _a;
|
|
460
505
|
const response = await fetch(this.options.presignEndpoint, {
|
|
461
506
|
method: "POST",
|
|
462
507
|
headers: {
|
|
@@ -467,16 +512,17 @@ var S3PresignedProvider = class {
|
|
|
467
512
|
body: JSON.stringify({ files })
|
|
468
513
|
});
|
|
469
514
|
if (!response.ok) {
|
|
470
|
-
throw new
|
|
515
|
+
throw new BugReporterError("UPLOAD_ERROR", `Failed to prepare uploads (${response.status}).`);
|
|
471
516
|
}
|
|
472
517
|
const payload = await response.json();
|
|
473
|
-
if (!payload.uploads
|
|
474
|
-
throw new
|
|
518
|
+
if (!((_a = payload.uploads) == null ? void 0 : _a.length)) {
|
|
519
|
+
throw new BugReporterError("UPLOAD_ERROR", "Presign endpoint did not return upload instructions.");
|
|
475
520
|
}
|
|
476
521
|
return payload.uploads;
|
|
477
522
|
}
|
|
478
523
|
async upload(instruction, blob, onProgress) {
|
|
479
|
-
|
|
524
|
+
var _a;
|
|
525
|
+
onProgress == null ? void 0 : onProgress(0);
|
|
480
526
|
if (instruction.method === "POST" && instruction.fields) {
|
|
481
527
|
const formData = new FormData();
|
|
482
528
|
Object.entries(instruction.fields).forEach(([key, value]) => formData.append(key, value));
|
|
@@ -486,7 +532,7 @@ var S3PresignedProvider = class {
|
|
|
486
532
|
body: formData
|
|
487
533
|
});
|
|
488
534
|
if (!response.ok) {
|
|
489
|
-
throw new
|
|
535
|
+
throw new BugReporterError("UPLOAD_ERROR", `S3 form upload failed (${response.status}).`);
|
|
490
536
|
}
|
|
491
537
|
} else {
|
|
492
538
|
const response = await fetch(instruction.uploadUrl, {
|
|
@@ -495,11 +541,11 @@ var S3PresignedProvider = class {
|
|
|
495
541
|
body: blob
|
|
496
542
|
});
|
|
497
543
|
if (!response.ok) {
|
|
498
|
-
throw new
|
|
544
|
+
throw new BugReporterError("UPLOAD_ERROR", `S3 upload failed (${response.status}).`);
|
|
499
545
|
}
|
|
500
546
|
}
|
|
501
|
-
onProgress
|
|
502
|
-
const publicUrl = instruction.publicUrl
|
|
547
|
+
onProgress == null ? void 0 : onProgress(1);
|
|
548
|
+
const publicUrl = (_a = instruction.publicUrl) != null ? _a : this.options.publicBaseUrl && instruction.key ? `${this.options.publicBaseUrl.replace(/\/$/, "")}/${instruction.key}` : instruction.uploadUrl;
|
|
503
549
|
return {
|
|
504
550
|
id: instruction.id,
|
|
505
551
|
type: instruction.type,
|
|
@@ -513,31 +559,32 @@ var S3PresignedProvider = class {
|
|
|
513
559
|
|
|
514
560
|
// src/storage/factory.ts
|
|
515
561
|
function createStorageProvider(config) {
|
|
562
|
+
var _a, _b, _c, _d, _e;
|
|
516
563
|
if (config.storage.mode === "s3-presigned") {
|
|
517
|
-
const presignEndpoint = config.storage.s3
|
|
564
|
+
const presignEndpoint = (_a = config.storage.s3) == null ? void 0 : _a.presignEndpoint;
|
|
518
565
|
if (!presignEndpoint) {
|
|
519
566
|
throw new Error("storage.s3.presignEndpoint is required for s3-presigned mode.");
|
|
520
567
|
}
|
|
521
568
|
return new S3PresignedProvider({
|
|
522
569
|
presignEndpoint,
|
|
523
|
-
publicBaseUrl: config.storage.s3
|
|
570
|
+
publicBaseUrl: (_b = config.storage.s3) == null ? void 0 : _b.publicBaseUrl,
|
|
524
571
|
authHeaders: config.auth.headers,
|
|
525
572
|
withCredentials: config.auth.withCredentials
|
|
526
573
|
});
|
|
527
574
|
}
|
|
528
575
|
if (config.storage.mode === "local-public") {
|
|
529
|
-
const uploadEndpoint2 = config.storage.local
|
|
576
|
+
const uploadEndpoint2 = (_c = config.storage.local) == null ? void 0 : _c.uploadEndpoint;
|
|
530
577
|
if (!uploadEndpoint2) {
|
|
531
578
|
throw new Error("storage.local.uploadEndpoint is required for local-public mode.");
|
|
532
579
|
}
|
|
533
580
|
return new LocalPublicProvider({
|
|
534
581
|
uploadEndpoint: uploadEndpoint2,
|
|
535
|
-
publicBaseUrl: config.storage.local
|
|
582
|
+
publicBaseUrl: (_d = config.storage.local) == null ? void 0 : _d.publicBaseUrl,
|
|
536
583
|
authHeaders: config.auth.headers,
|
|
537
584
|
withCredentials: config.auth.withCredentials
|
|
538
585
|
});
|
|
539
586
|
}
|
|
540
|
-
const uploadEndpoint = config.storage.proxy
|
|
587
|
+
const uploadEndpoint = (_e = config.storage.proxy) == null ? void 0 : _e.uploadEndpoint;
|
|
541
588
|
if (!uploadEndpoint) {
|
|
542
589
|
throw new Error("storage.proxy.uploadEndpoint is required for proxy mode.");
|
|
543
590
|
}
|
|
@@ -581,6 +628,7 @@ async function withRetry(fn, retries) {
|
|
|
581
628
|
throw lastError;
|
|
582
629
|
}
|
|
583
630
|
async function uploadAssets(options) {
|
|
631
|
+
var _a, _b;
|
|
584
632
|
const files = options.assets.map((asset) => ({
|
|
585
633
|
id: asset.id,
|
|
586
634
|
name: asset.filename,
|
|
@@ -595,24 +643,26 @@ async function uploadAssets(options) {
|
|
|
595
643
|
for (const asset of options.assets) {
|
|
596
644
|
const instruction = byId.get(asset.id);
|
|
597
645
|
if (!instruction) {
|
|
598
|
-
throw new
|
|
646
|
+
throw new BugReporterError("UPLOAD_ERROR", `No upload instruction for asset ${asset.id}.`);
|
|
599
647
|
}
|
|
600
648
|
const ref = await withRetry(
|
|
601
649
|
() => options.provider.upload(instruction, asset.blob, (inner) => {
|
|
650
|
+
var _a2;
|
|
602
651
|
const aggregate = (completed + inner) / options.assets.length;
|
|
603
|
-
options.onProgress
|
|
652
|
+
(_a2 = options.onProgress) == null ? void 0 : _a2.call(options, aggregate);
|
|
604
653
|
}),
|
|
605
|
-
options.retries
|
|
654
|
+
(_a = options.retries) != null ? _a : 2
|
|
606
655
|
);
|
|
607
656
|
refs.push(ref);
|
|
608
657
|
completed += 1;
|
|
609
|
-
options.onProgress
|
|
658
|
+
(_b = options.onProgress) == null ? void 0 : _b.call(options, completed / options.assets.length);
|
|
610
659
|
}
|
|
611
660
|
return refs;
|
|
612
661
|
}
|
|
613
662
|
|
|
614
663
|
// src/core/submit.ts
|
|
615
664
|
async function submitReport(options) {
|
|
665
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
|
|
616
666
|
const provider = createStorageProvider(options.config);
|
|
617
667
|
const assetReferences = await uploadAssets({
|
|
618
668
|
provider,
|
|
@@ -649,18 +699,18 @@ async function submitReport(options) {
|
|
|
649
699
|
requests: options.diagnostics.requests
|
|
650
700
|
},
|
|
651
701
|
reporter: {
|
|
652
|
-
id: options.config.user
|
|
653
|
-
name: options.config.user
|
|
654
|
-
email: options.config.user
|
|
655
|
-
role: options.config.user
|
|
656
|
-
ip: options.config.user
|
|
657
|
-
anonymous: options.config.user
|
|
702
|
+
id: (_a = options.config.user) == null ? void 0 : _a.id,
|
|
703
|
+
name: (_b = options.config.user) == null ? void 0 : _b.name,
|
|
704
|
+
email: (_c = options.config.user) == null ? void 0 : _c.email,
|
|
705
|
+
role: (_d = options.config.user) == null ? void 0 : _d.role,
|
|
706
|
+
ip: (_e = options.config.user) == null ? void 0 : _e.ip,
|
|
707
|
+
anonymous: (_j = (_f = options.config.user) == null ? void 0 : _f.anonymous) != null ? _j : !(((_g = options.config.user) == null ? void 0 : _g.id) || ((_h = options.config.user) == null ? void 0 : _h.email) || ((_i = options.config.user) == null ? void 0 : _i.name))
|
|
658
708
|
},
|
|
659
709
|
attributes: options.attributes
|
|
660
710
|
};
|
|
661
711
|
const transformed = options.config.hooks.beforeSubmit ? await options.config.hooks.beforeSubmit(payloadBase) : payloadBase;
|
|
662
712
|
if (!transformed) {
|
|
663
|
-
throw new
|
|
713
|
+
throw new BugReporterError("ABORTED", "Submission aborted by beforeSubmit hook.");
|
|
664
714
|
}
|
|
665
715
|
console.log("[bug-reporter] payload to submit", transformed);
|
|
666
716
|
console.log("[bug-reporter] payload to submit (json)", JSON.stringify(transformed, null, 2));
|
|
@@ -675,7 +725,7 @@ async function submitReport(options) {
|
|
|
675
725
|
});
|
|
676
726
|
if (!response.ok) {
|
|
677
727
|
const body = await response.text().catch(() => "");
|
|
678
|
-
throw new
|
|
728
|
+
throw new BugReporterError("SUBMIT_ERROR", `Report submit failed (${response.status}): ${body || response.statusText}`);
|
|
679
729
|
}
|
|
680
730
|
return await response.json();
|
|
681
731
|
}
|
|
@@ -700,21 +750,21 @@ var BASE_STATE = {
|
|
|
700
750
|
error: void 0
|
|
701
751
|
};
|
|
702
752
|
function BugReporterProvider({ config, children }) {
|
|
703
|
-
const resolvedConfig =
|
|
753
|
+
const resolvedConfig = React.useMemo(() => withDefaults(config), [config]);
|
|
704
754
|
const initialDockSide = resolvedConfig.theme.position === "bottom-left" || resolvedConfig.theme.position === "top-left" ? "left" : "right";
|
|
705
|
-
const [state, setState] =
|
|
755
|
+
const [state, setState] = React.useState(() => ({
|
|
706
756
|
...BASE_STATE,
|
|
707
757
|
dockSide: initialDockSide,
|
|
708
758
|
attributes: { ...resolvedConfig.attributes }
|
|
709
759
|
}));
|
|
710
|
-
const [sessionActive, setSessionActive] =
|
|
711
|
-
const consoleBufferRef =
|
|
712
|
-
const networkBufferRef =
|
|
713
|
-
const assetsRef =
|
|
714
|
-
const resetAssets =
|
|
760
|
+
const [sessionActive, setSessionActive] = React.useState(false);
|
|
761
|
+
const consoleBufferRef = React.useRef(null);
|
|
762
|
+
const networkBufferRef = React.useRef(null);
|
|
763
|
+
const assetsRef = React.useRef([]);
|
|
764
|
+
const resetAssets = React.useCallback((assets) => {
|
|
715
765
|
assets.forEach((asset) => revokeObjectUrl(asset.previewUrl));
|
|
716
766
|
}, []);
|
|
717
|
-
const open =
|
|
767
|
+
const open = React.useCallback(() => {
|
|
718
768
|
setSessionActive(true);
|
|
719
769
|
setState((prev) => ({
|
|
720
770
|
...prev,
|
|
@@ -722,13 +772,14 @@ function BugReporterProvider({ config, children }) {
|
|
|
722
772
|
error: void 0
|
|
723
773
|
}));
|
|
724
774
|
}, []);
|
|
725
|
-
const close =
|
|
775
|
+
const close = React.useCallback(() => {
|
|
726
776
|
setState((prev) => ({
|
|
727
777
|
...prev,
|
|
728
778
|
isOpen: false
|
|
729
779
|
}));
|
|
730
780
|
}, []);
|
|
731
|
-
const reset =
|
|
781
|
+
const reset = React.useCallback(() => {
|
|
782
|
+
var _a, _b;
|
|
732
783
|
setSessionActive(false);
|
|
733
784
|
setState((prev) => {
|
|
734
785
|
resetAssets(prev.assets);
|
|
@@ -739,16 +790,16 @@ function BugReporterProvider({ config, children }) {
|
|
|
739
790
|
isOpen: prev.isOpen
|
|
740
791
|
};
|
|
741
792
|
});
|
|
742
|
-
consoleBufferRef.current
|
|
743
|
-
networkBufferRef.current
|
|
793
|
+
(_a = consoleBufferRef.current) == null ? void 0 : _a.clear();
|
|
794
|
+
(_b = networkBufferRef.current) == null ? void 0 : _b.clear();
|
|
744
795
|
}, [resetAssets, resolvedConfig.attributes]);
|
|
745
|
-
const setStep =
|
|
796
|
+
const setStep = React.useCallback((step) => {
|
|
746
797
|
setState((prev) => ({ ...prev, step }));
|
|
747
798
|
}, []);
|
|
748
|
-
const setDockSide =
|
|
799
|
+
const setDockSide = React.useCallback((dockSide) => {
|
|
749
800
|
setState((prev) => ({ ...prev, dockSide }));
|
|
750
801
|
}, []);
|
|
751
|
-
const updateDraft =
|
|
802
|
+
const updateDraft = React.useCallback((next) => {
|
|
752
803
|
setState((prev) => ({
|
|
753
804
|
...prev,
|
|
754
805
|
draft: {
|
|
@@ -757,13 +808,13 @@ function BugReporterProvider({ config, children }) {
|
|
|
757
808
|
}
|
|
758
809
|
}));
|
|
759
810
|
}, []);
|
|
760
|
-
const setAttributes =
|
|
811
|
+
const setAttributes = React.useCallback((next) => {
|
|
761
812
|
setState((prev) => ({
|
|
762
813
|
...prev,
|
|
763
814
|
attributes: next
|
|
764
815
|
}));
|
|
765
816
|
}, []);
|
|
766
|
-
const updateAttribute =
|
|
817
|
+
const updateAttribute = React.useCallback((key, value2) => {
|
|
767
818
|
setState((prev) => ({
|
|
768
819
|
...prev,
|
|
769
820
|
attributes: {
|
|
@@ -772,7 +823,7 @@ function BugReporterProvider({ config, children }) {
|
|
|
772
823
|
}
|
|
773
824
|
}));
|
|
774
825
|
}, []);
|
|
775
|
-
const setAssetByType =
|
|
826
|
+
const setAssetByType = React.useCallback((type, next) => {
|
|
776
827
|
setState((prev) => {
|
|
777
828
|
const previous = prev.assets.find((asset) => asset.type === type);
|
|
778
829
|
if (previous) {
|
|
@@ -785,13 +836,14 @@ function BugReporterProvider({ config, children }) {
|
|
|
785
836
|
};
|
|
786
837
|
});
|
|
787
838
|
}, []);
|
|
788
|
-
const setScreenshot =
|
|
839
|
+
const setScreenshot = React.useCallback((asset) => {
|
|
789
840
|
setAssetByType("screenshot", asset);
|
|
790
841
|
}, [setAssetByType]);
|
|
791
|
-
const setRecording =
|
|
842
|
+
const setRecording = React.useCallback((asset) => {
|
|
792
843
|
setAssetByType("recording", asset);
|
|
793
844
|
}, [setAssetByType]);
|
|
794
|
-
const submit =
|
|
845
|
+
const submit = React.useCallback(async () => {
|
|
846
|
+
var _a, _b, _c, _d, _e, _f;
|
|
795
847
|
setState((prev) => ({
|
|
796
848
|
...prev,
|
|
797
849
|
step: "submitting",
|
|
@@ -800,8 +852,8 @@ function BugReporterProvider({ config, children }) {
|
|
|
800
852
|
error: void 0
|
|
801
853
|
}));
|
|
802
854
|
try {
|
|
803
|
-
const logs = resolvedConfig.features.consoleLogs ? consoleBufferRef.current
|
|
804
|
-
const requests = resolvedConfig.features.networkInfo ? networkBufferRef.current
|
|
855
|
+
const logs = resolvedConfig.features.consoleLogs ? (_a = consoleBufferRef.current) == null ? void 0 : _a.snapshot() : void 0;
|
|
856
|
+
const requests = resolvedConfig.features.networkInfo ? (_b = networkBufferRef.current) == null ? void 0 : _b.snapshot() : void 0;
|
|
805
857
|
const diagnostics = collectDiagnostics(resolvedConfig, {
|
|
806
858
|
logs,
|
|
807
859
|
requests
|
|
@@ -823,7 +875,7 @@ function BugReporterProvider({ config, children }) {
|
|
|
823
875
|
uploadProgress: 1,
|
|
824
876
|
step: "success"
|
|
825
877
|
}));
|
|
826
|
-
resolvedConfig.hooks.onSuccess
|
|
878
|
+
(_d = (_c = resolvedConfig.hooks).onSuccess) == null ? void 0 : _d.call(_c, response);
|
|
827
879
|
} catch (error) {
|
|
828
880
|
const message = error instanceof Error ? error.message : "Unexpected submit failure.";
|
|
829
881
|
setState((prev) => ({
|
|
@@ -832,21 +884,25 @@ function BugReporterProvider({ config, children }) {
|
|
|
832
884
|
step: "review",
|
|
833
885
|
error: message
|
|
834
886
|
}));
|
|
835
|
-
resolvedConfig.hooks.onError
|
|
887
|
+
(_f = (_e = resolvedConfig.hooks).onError) == null ? void 0 : _f.call(_e, error);
|
|
836
888
|
}
|
|
837
889
|
}, [resolvedConfig, state.assets, state.attributes, state.draft]);
|
|
838
|
-
const retrySubmit =
|
|
890
|
+
const retrySubmit = React.useCallback(async () => {
|
|
839
891
|
await submit();
|
|
840
892
|
}, [submit]);
|
|
841
|
-
const getDiagnosticsPreview =
|
|
842
|
-
|
|
843
|
-
const
|
|
893
|
+
const getDiagnosticsPreview = React.useCallback(() => {
|
|
894
|
+
var _a, _b, _c, _d;
|
|
895
|
+
const logs = resolvedConfig.features.consoleLogs ? (_b = (_a = consoleBufferRef.current) == null ? void 0 : _a.snapshot()) != null ? _b : [] : [];
|
|
896
|
+
const requests = resolvedConfig.features.networkInfo ? (_d = (_c = networkBufferRef.current) == null ? void 0 : _c.snapshot()) != null ? _d : [] : [];
|
|
844
897
|
return {
|
|
845
898
|
errorLogs: logs.filter((entry) => entry.level === "error"),
|
|
846
|
-
failedRequests: requests.filter((request) =>
|
|
899
|
+
failedRequests: requests.filter((request) => {
|
|
900
|
+
var _a2;
|
|
901
|
+
return Boolean(request.error) || request.ok === false || ((_a2 = request.status) != null ? _a2 : 0) >= 400;
|
|
902
|
+
})
|
|
847
903
|
};
|
|
848
904
|
}, [resolvedConfig.features.consoleLogs, resolvedConfig.features.networkInfo]);
|
|
849
|
-
|
|
905
|
+
React.useEffect(() => {
|
|
850
906
|
if (!sessionActive) {
|
|
851
907
|
return;
|
|
852
908
|
}
|
|
@@ -863,8 +919,8 @@ function BugReporterProvider({ config, children }) {
|
|
|
863
919
|
networkBufferRef.current = networkBuffer;
|
|
864
920
|
}
|
|
865
921
|
return () => {
|
|
866
|
-
consoleBuffer
|
|
867
|
-
networkBuffer
|
|
922
|
+
consoleBuffer == null ? void 0 : consoleBuffer.uninstall();
|
|
923
|
+
networkBuffer == null ? void 0 : networkBuffer.uninstall();
|
|
868
924
|
consoleBufferRef.current = null;
|
|
869
925
|
networkBufferRef.current = null;
|
|
870
926
|
};
|
|
@@ -875,17 +931,18 @@ function BugReporterProvider({ config, children }) {
|
|
|
875
931
|
resolvedConfig.features.consoleLogs,
|
|
876
932
|
resolvedConfig.features.networkInfo
|
|
877
933
|
]);
|
|
878
|
-
|
|
934
|
+
React.useEffect(() => {
|
|
879
935
|
assetsRef.current = state.assets;
|
|
880
936
|
}, [state.assets]);
|
|
881
|
-
|
|
937
|
+
React.useEffect(() => {
|
|
882
938
|
return () => {
|
|
939
|
+
var _a, _b;
|
|
883
940
|
resetAssets(assetsRef.current);
|
|
884
|
-
consoleBufferRef.current
|
|
885
|
-
networkBufferRef.current
|
|
941
|
+
(_a = consoleBufferRef.current) == null ? void 0 : _a.uninstall();
|
|
942
|
+
(_b = networkBufferRef.current) == null ? void 0 : _b.uninstall();
|
|
886
943
|
};
|
|
887
944
|
}, [resetAssets]);
|
|
888
|
-
const value =
|
|
945
|
+
const value = React.useMemo(
|
|
889
946
|
() => ({
|
|
890
947
|
config: resolvedConfig,
|
|
891
948
|
state,
|
|
@@ -921,10 +978,10 @@ function BugReporterProvider({ config, children }) {
|
|
|
921
978
|
getDiagnosticsPreview
|
|
922
979
|
]
|
|
923
980
|
);
|
|
924
|
-
return /* @__PURE__ */
|
|
981
|
+
return /* @__PURE__ */ React__namespace.createElement(BugReporterContext.Provider, { value }, children);
|
|
925
982
|
}
|
|
926
983
|
function useBugReporter() {
|
|
927
|
-
const context =
|
|
984
|
+
const context = React.useContext(BugReporterContext);
|
|
928
985
|
if (!context) {
|
|
929
986
|
throw new Error("useBugReporter must be used inside BugReporterProvider.");
|
|
930
987
|
}
|
|
@@ -938,7 +995,7 @@ function getFocusable(node) {
|
|
|
938
995
|
).filter((el) => !el.hasAttribute("disabled"));
|
|
939
996
|
}
|
|
940
997
|
function useFocusTrap(enabled, containerRef) {
|
|
941
|
-
|
|
998
|
+
React.useEffect(() => {
|
|
942
999
|
const container = containerRef.current;
|
|
943
1000
|
if (!enabled || !container) {
|
|
944
1001
|
return;
|
|
@@ -946,7 +1003,7 @@ function useFocusTrap(enabled, containerRef) {
|
|
|
946
1003
|
const focusable = getFocusable(container);
|
|
947
1004
|
const first = focusable[0];
|
|
948
1005
|
const last = focusable[focusable.length - 1];
|
|
949
|
-
first
|
|
1006
|
+
first == null ? void 0 : first.focus();
|
|
950
1007
|
const onKeyDown = (event) => {
|
|
951
1008
|
if (event.key !== "Tab") {
|
|
952
1009
|
return;
|
|
@@ -1289,9 +1346,10 @@ var inlineStyles = {
|
|
|
1289
1346
|
}
|
|
1290
1347
|
};
|
|
1291
1348
|
function getButtonStyle(variant, options) {
|
|
1292
|
-
|
|
1293
|
-
const
|
|
1294
|
-
const
|
|
1349
|
+
var _a, _b, _c;
|
|
1350
|
+
const disabled = (_a = options == null ? void 0 : options.disabled) != null ? _a : false;
|
|
1351
|
+
const active = (_b = options == null ? void 0 : options.active) != null ? _b : false;
|
|
1352
|
+
const fullWidth = (_c = options == null ? void 0 : options.fullWidth) != null ? _c : false;
|
|
1295
1353
|
const base = {
|
|
1296
1354
|
border: "1px solid transparent",
|
|
1297
1355
|
borderRadius: "10px",
|
|
@@ -1329,6 +1387,7 @@ function getDockButtonStyle(isActive) {
|
|
|
1329
1387
|
|
|
1330
1388
|
// src/components/LauncherButton.tsx
|
|
1331
1389
|
function LauncherButton({ position, text, themeMode = "dark", buttonColor }) {
|
|
1390
|
+
var _a;
|
|
1332
1391
|
const {
|
|
1333
1392
|
config,
|
|
1334
1393
|
state: { isOpen },
|
|
@@ -1337,9 +1396,9 @@ function LauncherButton({ position, text, themeMode = "dark", buttonColor }) {
|
|
|
1337
1396
|
if (isOpen) {
|
|
1338
1397
|
return null;
|
|
1339
1398
|
}
|
|
1340
|
-
const resolvedPosition = position
|
|
1341
|
-
const label = text
|
|
1342
|
-
const resolvedButtonColor = buttonColor
|
|
1399
|
+
const resolvedPosition = (_a = position != null ? position : config.theme.position) != null ? _a : "bottom-right";
|
|
1400
|
+
const label = text != null ? text : "Get Help";
|
|
1401
|
+
const resolvedButtonColor = buttonColor != null ? buttonColor : config.theme.primaryColor;
|
|
1343
1402
|
const launcherStyle = getLauncherStyle({
|
|
1344
1403
|
position: resolvedPosition,
|
|
1345
1404
|
borderRadius: config.theme.borderRadius,
|
|
@@ -1347,7 +1406,7 @@ function LauncherButton({ position, text, themeMode = "dark", buttonColor }) {
|
|
|
1347
1406
|
buttonColor: resolvedButtonColor,
|
|
1348
1407
|
themeMode
|
|
1349
1408
|
});
|
|
1350
|
-
return /* @__PURE__ */
|
|
1409
|
+
return /* @__PURE__ */ React__namespace.createElement(
|
|
1351
1410
|
"button",
|
|
1352
1411
|
{
|
|
1353
1412
|
type: "button",
|
|
@@ -1359,9 +1418,9 @@ function LauncherButton({ position, text, themeMode = "dark", buttonColor }) {
|
|
|
1359
1418
|
);
|
|
1360
1419
|
}
|
|
1361
1420
|
function Modal({ isOpen, dockSide, themeMode, buttonColor, title, zIndex, onRequestClose, children }) {
|
|
1362
|
-
const dialogRef =
|
|
1421
|
+
const dialogRef = React.useRef(null);
|
|
1363
1422
|
useFocusTrap(isOpen, dialogRef);
|
|
1364
|
-
|
|
1423
|
+
React.useEffect(() => {
|
|
1365
1424
|
if (!isOpen) {
|
|
1366
1425
|
return;
|
|
1367
1426
|
}
|
|
@@ -1380,23 +1439,309 @@ function Modal({ isOpen, dockSide, themeMode, buttonColor, title, zIndex, onRequ
|
|
|
1380
1439
|
const overlayStyle = getModalOverlayStyle({ dockSide, themeMode, zIndex });
|
|
1381
1440
|
const modalStyle = getModalStyle({ dockSide, themeMode, buttonColor });
|
|
1382
1441
|
return reactDom.createPortal(
|
|
1383
|
-
/* @__PURE__ */
|
|
1442
|
+
/* @__PURE__ */ React__namespace.createElement("div", { style: overlayStyle }, /* @__PURE__ */ React__namespace.createElement("div", { ref: dialogRef, style: modalStyle, role: "dialog", "aria-modal": "true", "aria-label": title }, children)),
|
|
1384
1443
|
document.body
|
|
1385
1444
|
);
|
|
1386
1445
|
}
|
|
1446
|
+
function applyMasking(selectors) {
|
|
1447
|
+
const masked = [];
|
|
1448
|
+
for (const selector of selectors) {
|
|
1449
|
+
document.querySelectorAll(selector).forEach((element) => {
|
|
1450
|
+
masked.push({ element, previous: element.style.filter });
|
|
1451
|
+
element.style.filter = "blur(12px)";
|
|
1452
|
+
});
|
|
1453
|
+
}
|
|
1454
|
+
return masked;
|
|
1455
|
+
}
|
|
1456
|
+
function resetMasking(masked) {
|
|
1457
|
+
masked.forEach(({ element, previous }) => {
|
|
1458
|
+
element.style.filter = previous;
|
|
1459
|
+
});
|
|
1460
|
+
}
|
|
1461
|
+
function scrubText(root, patterns) {
|
|
1462
|
+
var _a, _b;
|
|
1463
|
+
if (!patterns.length) {
|
|
1464
|
+
return [];
|
|
1465
|
+
}
|
|
1466
|
+
const walkers = [];
|
|
1467
|
+
const regexes = patterns.map((pattern) => typeof pattern === "string" ? new RegExp(pattern, "g") : pattern);
|
|
1468
|
+
const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);
|
|
1469
|
+
while (walker.nextNode()) {
|
|
1470
|
+
const text = walker.currentNode;
|
|
1471
|
+
let replaced = (_a = text.textContent) != null ? _a : "";
|
|
1472
|
+
for (const regex of regexes) {
|
|
1473
|
+
replaced = replaced.replace(regex, "[redacted]");
|
|
1474
|
+
}
|
|
1475
|
+
if (replaced !== text.textContent) {
|
|
1476
|
+
walkers.push({ node: text, previous: (_b = text.textContent) != null ? _b : "" });
|
|
1477
|
+
text.textContent = replaced;
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
return walkers;
|
|
1481
|
+
}
|
|
1482
|
+
function restoreText(changed) {
|
|
1483
|
+
changed.forEach(({ node, previous }) => {
|
|
1484
|
+
node.textContent = previous;
|
|
1485
|
+
});
|
|
1486
|
+
}
|
|
1487
|
+
function createSelectionOverlay() {
|
|
1488
|
+
return new Promise((resolve, reject) => {
|
|
1489
|
+
const overlay = document.createElement("div");
|
|
1490
|
+
overlay.setAttribute("data-bug-reporter-overlay", "true");
|
|
1491
|
+
overlay.style.position = "fixed";
|
|
1492
|
+
overlay.style.inset = "0";
|
|
1493
|
+
overlay.style.background = "rgba(0,0,0,0.35)";
|
|
1494
|
+
overlay.style.cursor = "crosshair";
|
|
1495
|
+
overlay.style.zIndex = "2147483647";
|
|
1496
|
+
const box = document.createElement("div");
|
|
1497
|
+
box.style.position = "fixed";
|
|
1498
|
+
box.style.border = "2px solid #ffffff";
|
|
1499
|
+
box.style.background = "rgba(27, 116, 228, 0.2)";
|
|
1500
|
+
box.style.pointerEvents = "none";
|
|
1501
|
+
box.style.display = "none";
|
|
1502
|
+
overlay.appendChild(box);
|
|
1503
|
+
const cleanup = () => {
|
|
1504
|
+
overlay.removeEventListener("mousedown", onMouseDown);
|
|
1505
|
+
overlay.removeEventListener("mousemove", onMouseMove);
|
|
1506
|
+
overlay.removeEventListener("mouseup", onMouseUp);
|
|
1507
|
+
window.removeEventListener("keydown", onKeyDown);
|
|
1508
|
+
overlay.remove();
|
|
1509
|
+
};
|
|
1510
|
+
let startX = 0;
|
|
1511
|
+
let startY = 0;
|
|
1512
|
+
let isDragging = false;
|
|
1513
|
+
const onKeyDown = (event) => {
|
|
1514
|
+
if (event.key === "Escape") {
|
|
1515
|
+
cleanup();
|
|
1516
|
+
reject(new BugReporterError("ABORTED", "Screenshot capture cancelled."));
|
|
1517
|
+
}
|
|
1518
|
+
};
|
|
1519
|
+
const onMouseDown = (event) => {
|
|
1520
|
+
isDragging = true;
|
|
1521
|
+
startX = event.clientX;
|
|
1522
|
+
startY = event.clientY;
|
|
1523
|
+
box.style.display = "block";
|
|
1524
|
+
box.style.left = `${startX}px`;
|
|
1525
|
+
box.style.top = `${startY}px`;
|
|
1526
|
+
box.style.width = "0px";
|
|
1527
|
+
box.style.height = "0px";
|
|
1528
|
+
};
|
|
1529
|
+
const onMouseMove = (event) => {
|
|
1530
|
+
if (!isDragging) {
|
|
1531
|
+
return;
|
|
1532
|
+
}
|
|
1533
|
+
const left = Math.min(startX, event.clientX);
|
|
1534
|
+
const top = Math.min(startY, event.clientY);
|
|
1535
|
+
const width = Math.abs(startX - event.clientX);
|
|
1536
|
+
const height = Math.abs(startY - event.clientY);
|
|
1537
|
+
box.style.left = `${left}px`;
|
|
1538
|
+
box.style.top = `${top}px`;
|
|
1539
|
+
box.style.width = `${width}px`;
|
|
1540
|
+
box.style.height = `${height}px`;
|
|
1541
|
+
};
|
|
1542
|
+
const onMouseUp = (event) => {
|
|
1543
|
+
if (!isDragging) {
|
|
1544
|
+
return;
|
|
1545
|
+
}
|
|
1546
|
+
isDragging = false;
|
|
1547
|
+
const left = Math.min(startX, event.clientX);
|
|
1548
|
+
const top = Math.min(startY, event.clientY);
|
|
1549
|
+
const width = Math.abs(startX - event.clientX);
|
|
1550
|
+
const height = Math.abs(startY - event.clientY);
|
|
1551
|
+
cleanup();
|
|
1552
|
+
if (width < 8 || height < 8) {
|
|
1553
|
+
reject(new BugReporterError("CAPTURE_ERROR", "Selection area is too small."));
|
|
1554
|
+
return;
|
|
1555
|
+
}
|
|
1556
|
+
resolve({ left, top, width, height });
|
|
1557
|
+
};
|
|
1558
|
+
overlay.addEventListener("mousedown", onMouseDown);
|
|
1559
|
+
overlay.addEventListener("mousemove", onMouseMove);
|
|
1560
|
+
overlay.addEventListener("mouseup", onMouseUp);
|
|
1561
|
+
window.addEventListener("keydown", onKeyDown);
|
|
1562
|
+
document.body.appendChild(overlay);
|
|
1563
|
+
});
|
|
1564
|
+
}
|
|
1565
|
+
function canvasToBlob(canvas) {
|
|
1566
|
+
return new Promise((resolve, reject) => {
|
|
1567
|
+
canvas.toBlob((blob) => {
|
|
1568
|
+
if (!blob) {
|
|
1569
|
+
reject(new BugReporterError("CAPTURE_ERROR", "Failed to build screenshot blob."));
|
|
1570
|
+
return;
|
|
1571
|
+
}
|
|
1572
|
+
resolve(blob);
|
|
1573
|
+
}, "image/png");
|
|
1574
|
+
});
|
|
1575
|
+
}
|
|
1576
|
+
async function captureScreenshotArea(options) {
|
|
1577
|
+
const selection = await createSelectionOverlay();
|
|
1578
|
+
const masked = applyMasking(options.maskSelectors);
|
|
1579
|
+
const textChanges = scrubText(document.body, options.redactTextPatterns);
|
|
1580
|
+
try {
|
|
1581
|
+
const baseCanvas = await html2canvas__default.default(document.documentElement, {
|
|
1582
|
+
useCORS: true,
|
|
1583
|
+
scrollX: -window.scrollX,
|
|
1584
|
+
scrollY: -window.scrollY,
|
|
1585
|
+
backgroundColor: null,
|
|
1586
|
+
logging: false,
|
|
1587
|
+
windowWidth: document.documentElement.scrollWidth,
|
|
1588
|
+
windowHeight: document.documentElement.scrollHeight
|
|
1589
|
+
});
|
|
1590
|
+
const scaleX = baseCanvas.width / window.innerWidth;
|
|
1591
|
+
const scaleY = baseCanvas.height / window.innerHeight;
|
|
1592
|
+
const sx = Math.round(selection.left * scaleX);
|
|
1593
|
+
const sy = Math.round(selection.top * scaleY);
|
|
1594
|
+
const sw = Math.round(selection.width * scaleX);
|
|
1595
|
+
const sh = Math.round(selection.height * scaleY);
|
|
1596
|
+
const cropped = document.createElement("canvas");
|
|
1597
|
+
cropped.width = sw;
|
|
1598
|
+
cropped.height = sh;
|
|
1599
|
+
const context = cropped.getContext("2d");
|
|
1600
|
+
if (!context) {
|
|
1601
|
+
throw new BugReporterError("CAPTURE_ERROR", "Canvas 2D context unavailable.");
|
|
1602
|
+
}
|
|
1603
|
+
context.drawImage(baseCanvas, sx, sy, sw, sh, 0, 0, sw, sh);
|
|
1604
|
+
return await canvasToBlob(cropped);
|
|
1605
|
+
} catch (error) {
|
|
1606
|
+
if (error instanceof BugReporterError) {
|
|
1607
|
+
throw error;
|
|
1608
|
+
}
|
|
1609
|
+
throw new BugReporterError("CAPTURE_ERROR", "Screenshot capture failed.", error);
|
|
1610
|
+
} finally {
|
|
1611
|
+
resetMasking(masked);
|
|
1612
|
+
restoreText(textChanges);
|
|
1613
|
+
}
|
|
1614
|
+
}
|
|
1615
|
+
|
|
1616
|
+
// src/core/recording.ts
|
|
1617
|
+
function pickMimeType() {
|
|
1618
|
+
const candidates = ["video/webm;codecs=vp9", "video/webm;codecs=vp8", "video/webm"];
|
|
1619
|
+
for (const candidate of candidates) {
|
|
1620
|
+
if (typeof MediaRecorder !== "undefined" && MediaRecorder.isTypeSupported(candidate)) {
|
|
1621
|
+
return candidate;
|
|
1622
|
+
}
|
|
1623
|
+
}
|
|
1624
|
+
return "video/webm";
|
|
1625
|
+
}
|
|
1626
|
+
async function startScreenRecording(options) {
|
|
1627
|
+
var _a;
|
|
1628
|
+
if (!((_a = navigator.mediaDevices) == null ? void 0 : _a.getDisplayMedia)) {
|
|
1629
|
+
throw new BugReporterError("RECORDING_ERROR", "Screen recording is not supported by this browser.");
|
|
1630
|
+
}
|
|
1631
|
+
let stream;
|
|
1632
|
+
try {
|
|
1633
|
+
stream = await navigator.mediaDevices.getDisplayMedia({
|
|
1634
|
+
video: true,
|
|
1635
|
+
audio: false
|
|
1636
|
+
});
|
|
1637
|
+
} catch (error) {
|
|
1638
|
+
throw new BugReporterError("PERMISSION_DENIED", "Permission denied for screen recording.", error);
|
|
1639
|
+
}
|
|
1640
|
+
const mimeType = pickMimeType();
|
|
1641
|
+
let recorder;
|
|
1642
|
+
try {
|
|
1643
|
+
recorder = new MediaRecorder(stream, { mimeType });
|
|
1644
|
+
} catch (error) {
|
|
1645
|
+
stream.getTracks().forEach((track) => track.stop());
|
|
1646
|
+
throw new BugReporterError("RECORDING_ERROR", "Could not initialize MediaRecorder.", error);
|
|
1647
|
+
}
|
|
1648
|
+
const chunks = [];
|
|
1649
|
+
const startedAt = Date.now();
|
|
1650
|
+
let latestSize = 0;
|
|
1651
|
+
let tickSeconds = 0;
|
|
1652
|
+
let completed = false;
|
|
1653
|
+
let isCancelled = false;
|
|
1654
|
+
let resolvePromise;
|
|
1655
|
+
let rejectPromise;
|
|
1656
|
+
const promise = new Promise((resolve, reject) => {
|
|
1657
|
+
resolvePromise = resolve;
|
|
1658
|
+
rejectPromise = reject;
|
|
1659
|
+
});
|
|
1660
|
+
const tickInterval = window.setInterval(() => {
|
|
1661
|
+
var _a2;
|
|
1662
|
+
tickSeconds += 1;
|
|
1663
|
+
(_a2 = options.onTick) == null ? void 0 : _a2.call(options, tickSeconds);
|
|
1664
|
+
}, 1e3);
|
|
1665
|
+
const hardStop = window.setTimeout(() => {
|
|
1666
|
+
if (recorder.state !== "inactive") {
|
|
1667
|
+
recorder.stop();
|
|
1668
|
+
}
|
|
1669
|
+
}, options.maxSeconds * 1e3);
|
|
1670
|
+
const teardown = () => {
|
|
1671
|
+
if (completed) {
|
|
1672
|
+
return;
|
|
1673
|
+
}
|
|
1674
|
+
completed = true;
|
|
1675
|
+
window.clearInterval(tickInterval);
|
|
1676
|
+
window.clearTimeout(hardStop);
|
|
1677
|
+
stream.getTracks().forEach((track) => track.stop());
|
|
1678
|
+
};
|
|
1679
|
+
recorder.addEventListener("dataavailable", (event) => {
|
|
1680
|
+
if (!event.data || event.data.size === 0) {
|
|
1681
|
+
return;
|
|
1682
|
+
}
|
|
1683
|
+
chunks.push(event.data);
|
|
1684
|
+
latestSize += event.data.size;
|
|
1685
|
+
if (latestSize > options.maxBytes) {
|
|
1686
|
+
isCancelled = true;
|
|
1687
|
+
recorder.stop();
|
|
1688
|
+
rejectPromise(
|
|
1689
|
+
new BugReporterError(
|
|
1690
|
+
"VALIDATION_ERROR",
|
|
1691
|
+
`Recording exceeds max size (${Math.round(options.maxBytes / 1024 / 1024)}MB).`
|
|
1692
|
+
)
|
|
1693
|
+
);
|
|
1694
|
+
}
|
|
1695
|
+
});
|
|
1696
|
+
recorder.addEventListener("error", (event) => {
|
|
1697
|
+
teardown();
|
|
1698
|
+
rejectPromise(new BugReporterError("RECORDING_ERROR", "Recording failed.", event));
|
|
1699
|
+
});
|
|
1700
|
+
recorder.addEventListener("stop", () => {
|
|
1701
|
+
teardown();
|
|
1702
|
+
if (isCancelled) {
|
|
1703
|
+
return;
|
|
1704
|
+
}
|
|
1705
|
+
const blob = new Blob(chunks, { type: mimeType });
|
|
1706
|
+
resolvePromise({
|
|
1707
|
+
blob,
|
|
1708
|
+
mimeType,
|
|
1709
|
+
durationMs: Date.now() - startedAt
|
|
1710
|
+
});
|
|
1711
|
+
});
|
|
1712
|
+
recorder.start(300);
|
|
1713
|
+
return {
|
|
1714
|
+
stop: () => {
|
|
1715
|
+
if (recorder.state !== "inactive") {
|
|
1716
|
+
recorder.stop();
|
|
1717
|
+
}
|
|
1718
|
+
},
|
|
1719
|
+
cancel: () => {
|
|
1720
|
+
isCancelled = true;
|
|
1721
|
+
if (recorder.state !== "inactive") {
|
|
1722
|
+
recorder.stop();
|
|
1723
|
+
}
|
|
1724
|
+
teardown();
|
|
1725
|
+
rejectPromise(new BugReporterError("ABORTED", "Recording cancelled by user."));
|
|
1726
|
+
},
|
|
1727
|
+
promise
|
|
1728
|
+
};
|
|
1729
|
+
}
|
|
1387
1730
|
|
|
1388
1731
|
// src/core/lazy.ts
|
|
1732
|
+
var screenshotCaptureModule = { captureScreenshotArea };
|
|
1733
|
+
var screenRecordingModule = { startScreenRecording };
|
|
1389
1734
|
async function loadScreenshotCapture() {
|
|
1390
|
-
return
|
|
1735
|
+
return screenshotCaptureModule;
|
|
1391
1736
|
}
|
|
1392
1737
|
async function loadScreenRecording() {
|
|
1393
|
-
return
|
|
1738
|
+
return screenRecordingModule;
|
|
1394
1739
|
}
|
|
1395
1740
|
|
|
1396
1741
|
// src/core/validation.ts
|
|
1397
1742
|
function validateScreenshotSize(size, maxBytes) {
|
|
1398
1743
|
if (size > maxBytes) {
|
|
1399
|
-
throw new
|
|
1744
|
+
throw new BugReporterError(
|
|
1400
1745
|
"VALIDATION_ERROR",
|
|
1401
1746
|
`Screenshot exceeds max size (${Math.round(maxBytes / 1024 / 1024)}MB).`
|
|
1402
1747
|
);
|
|
@@ -1404,7 +1749,7 @@ function validateScreenshotSize(size, maxBytes) {
|
|
|
1404
1749
|
}
|
|
1405
1750
|
function validateVideoSize(size, maxBytes) {
|
|
1406
1751
|
if (size > maxBytes) {
|
|
1407
|
-
throw new
|
|
1752
|
+
throw new BugReporterError("VALIDATION_ERROR", `Recording exceeds max size (${Math.round(maxBytes / 1024 / 1024)}MB).`);
|
|
1408
1753
|
}
|
|
1409
1754
|
}
|
|
1410
1755
|
function drawArrow(ctx, start, end) {
|
|
@@ -1421,14 +1766,14 @@ function drawArrow(ctx, start, end) {
|
|
|
1421
1766
|
ctx.closePath();
|
|
1422
1767
|
ctx.fill();
|
|
1423
1768
|
}
|
|
1424
|
-
var AnnotationCanvas =
|
|
1425
|
-
const canvasRef =
|
|
1426
|
-
const imageRef =
|
|
1427
|
-
const [tool, setTool] =
|
|
1428
|
-
const [shapes, setShapes] =
|
|
1429
|
-
const [draftShape, setDraftShape] =
|
|
1430
|
-
const dragStartRef =
|
|
1431
|
-
const redraw =
|
|
1769
|
+
var AnnotationCanvas = React.forwardRef(function AnnotationCanvas2({ imageUrl }, ref) {
|
|
1770
|
+
const canvasRef = React.useRef(null);
|
|
1771
|
+
const imageRef = React.useRef(null);
|
|
1772
|
+
const [tool, setTool] = React.useState("rectangle");
|
|
1773
|
+
const [shapes, setShapes] = React.useState([]);
|
|
1774
|
+
const [draftShape, setDraftShape] = React.useState(null);
|
|
1775
|
+
const dragStartRef = React.useRef(null);
|
|
1776
|
+
const redraw = React.useCallback(
|
|
1432
1777
|
(ctx) => {
|
|
1433
1778
|
const canvas = canvasRef.current;
|
|
1434
1779
|
const image = imageRef.current;
|
|
@@ -1457,7 +1802,7 @@ var AnnotationCanvas = react.forwardRef(function AnnotationCanvas2({ imageUrl },
|
|
|
1457
1802
|
},
|
|
1458
1803
|
[draftShape, shapes]
|
|
1459
1804
|
);
|
|
1460
|
-
|
|
1805
|
+
React.useEffect(() => {
|
|
1461
1806
|
const image = new Image();
|
|
1462
1807
|
image.crossOrigin = "anonymous";
|
|
1463
1808
|
image.onload = () => {
|
|
@@ -1476,7 +1821,7 @@ var AnnotationCanvas = react.forwardRef(function AnnotationCanvas2({ imageUrl },
|
|
|
1476
1821
|
};
|
|
1477
1822
|
image.src = imageUrl;
|
|
1478
1823
|
}, [imageUrl, redraw]);
|
|
1479
|
-
|
|
1824
|
+
React.useEffect(() => {
|
|
1480
1825
|
const canvas = canvasRef.current;
|
|
1481
1826
|
if (!canvas) {
|
|
1482
1827
|
return;
|
|
@@ -1487,7 +1832,7 @@ var AnnotationCanvas = react.forwardRef(function AnnotationCanvas2({ imageUrl },
|
|
|
1487
1832
|
}
|
|
1488
1833
|
redraw(ctx);
|
|
1489
1834
|
}, [redraw]);
|
|
1490
|
-
const getCoords =
|
|
1835
|
+
const getCoords = React.useCallback((event) => {
|
|
1491
1836
|
const canvas = canvasRef.current;
|
|
1492
1837
|
if (!canvas) {
|
|
1493
1838
|
return { x: 0, y: 0 };
|
|
@@ -1530,7 +1875,7 @@ var AnnotationCanvas = react.forwardRef(function AnnotationCanvas2({ imageUrl },
|
|
|
1530
1875
|
}
|
|
1531
1876
|
setDraftShape(null);
|
|
1532
1877
|
};
|
|
1533
|
-
const
|
|
1878
|
+
const canvasToBlob2 = React.useCallback(async () => {
|
|
1534
1879
|
const canvas = canvasRef.current;
|
|
1535
1880
|
if (!canvas) {
|
|
1536
1881
|
throw new Error("Annotation canvas unavailable.");
|
|
@@ -1543,23 +1888,23 @@ var AnnotationCanvas = react.forwardRef(function AnnotationCanvas2({ imageUrl },
|
|
|
1543
1888
|
}
|
|
1544
1889
|
return blob;
|
|
1545
1890
|
}, []);
|
|
1546
|
-
|
|
1891
|
+
React.useImperativeHandle(
|
|
1547
1892
|
ref,
|
|
1548
1893
|
() => ({
|
|
1549
|
-
exportBlob:
|
|
1894
|
+
exportBlob: canvasToBlob2,
|
|
1550
1895
|
clear: () => setShapes([]),
|
|
1551
1896
|
hasAnnotations: () => shapes.length > 0
|
|
1552
1897
|
}),
|
|
1553
|
-
[
|
|
1898
|
+
[canvasToBlob2, shapes.length]
|
|
1554
1899
|
);
|
|
1555
|
-
const toolButtons =
|
|
1900
|
+
const toolButtons = React.useMemo(
|
|
1556
1901
|
() => [
|
|
1557
1902
|
{ value: "rectangle", label: "Rectangle" },
|
|
1558
1903
|
{ value: "arrow", label: "Arrow" }
|
|
1559
1904
|
],
|
|
1560
1905
|
[]
|
|
1561
1906
|
);
|
|
1562
|
-
return /* @__PURE__ */
|
|
1907
|
+
return /* @__PURE__ */ React__namespace.createElement("div", { style: inlineStyles.annotation }, /* @__PURE__ */ React__namespace.createElement("div", { style: inlineStyles.annotationTools, role: "toolbar", "aria-label": "Annotation tools" }, toolButtons.map((option) => /* @__PURE__ */ React__namespace.createElement(
|
|
1563
1908
|
"button",
|
|
1564
1909
|
{
|
|
1565
1910
|
key: option.value,
|
|
@@ -1568,7 +1913,7 @@ var AnnotationCanvas = react.forwardRef(function AnnotationCanvas2({ imageUrl },
|
|
|
1568
1913
|
onClick: () => setTool(option.value)
|
|
1569
1914
|
},
|
|
1570
1915
|
option.label
|
|
1571
|
-
)), /* @__PURE__ */
|
|
1916
|
+
)), /* @__PURE__ */ React__namespace.createElement("button", { type: "button", style: getButtonStyle("secondary"), onClick: () => setShapes([]) }, "Clear")), /* @__PURE__ */ React__namespace.createElement(
|
|
1572
1917
|
"canvas",
|
|
1573
1918
|
{
|
|
1574
1919
|
ref: canvasRef,
|
|
@@ -1586,17 +1931,18 @@ function notifySubscribers() {
|
|
|
1586
1931
|
subscribers.forEach((handler) => handler());
|
|
1587
1932
|
}
|
|
1588
1933
|
function StepRecording({ onBack, onNext, embedded = false, compact = false }) {
|
|
1934
|
+
var _a;
|
|
1589
1935
|
const {
|
|
1590
1936
|
config,
|
|
1591
1937
|
state: { assets },
|
|
1592
1938
|
setRecording
|
|
1593
1939
|
} = useBugReporter();
|
|
1594
|
-
const recording =
|
|
1595
|
-
const activeRef =
|
|
1596
|
-
const mountedRef =
|
|
1597
|
-
const [isRecording, setIsRecording] =
|
|
1598
|
-
const [seconds, setSeconds] =
|
|
1599
|
-
const [error, setError] =
|
|
1940
|
+
const recording = React.useMemo(() => assets.find((asset) => asset.type === "recording"), [assets]);
|
|
1941
|
+
const activeRef = React.useRef(null);
|
|
1942
|
+
const mountedRef = React.useRef(true);
|
|
1943
|
+
const [isRecording, setIsRecording] = React.useState(Boolean(sharedRecording));
|
|
1944
|
+
const [seconds, setSeconds] = React.useState((_a = sharedRecording == null ? void 0 : sharedRecording.seconds) != null ? _a : 0);
|
|
1945
|
+
const [error, setError] = React.useState(null);
|
|
1600
1946
|
const start = async () => {
|
|
1601
1947
|
if (sharedRecording) {
|
|
1602
1948
|
setError("Recording is already in progress.");
|
|
@@ -1648,18 +1994,20 @@ function StepRecording({ onBack, onNext, embedded = false, compact = false }) {
|
|
|
1648
1994
|
}
|
|
1649
1995
|
};
|
|
1650
1996
|
const stop = () => {
|
|
1997
|
+
var _a2;
|
|
1651
1998
|
if (sharedRecording) {
|
|
1652
1999
|
sharedRecording.active.stop();
|
|
1653
2000
|
return;
|
|
1654
2001
|
}
|
|
1655
|
-
activeRef.current
|
|
2002
|
+
(_a2 = activeRef.current) == null ? void 0 : _a2.stop();
|
|
1656
2003
|
};
|
|
1657
|
-
|
|
2004
|
+
React.useEffect(() => {
|
|
1658
2005
|
mountedRef.current = true;
|
|
1659
2006
|
const sync = () => {
|
|
1660
|
-
|
|
2007
|
+
var _a2, _b;
|
|
2008
|
+
activeRef.current = (_a2 = sharedRecording == null ? void 0 : sharedRecording.active) != null ? _a2 : null;
|
|
1661
2009
|
setIsRecording(Boolean(sharedRecording));
|
|
1662
|
-
setSeconds(sharedRecording
|
|
2010
|
+
setSeconds((_b = sharedRecording == null ? void 0 : sharedRecording.seconds) != null ? _b : 0);
|
|
1663
2011
|
};
|
|
1664
2012
|
sync();
|
|
1665
2013
|
subscribers.add(sync);
|
|
@@ -1669,10 +2017,10 @@ function StepRecording({ onBack, onNext, embedded = false, compact = false }) {
|
|
|
1669
2017
|
};
|
|
1670
2018
|
}, []);
|
|
1671
2019
|
if (compact) {
|
|
1672
|
-
const compactRecordingAction = !isRecording ? /* @__PURE__ */
|
|
1673
|
-
return /* @__PURE__ */
|
|
2020
|
+
const compactRecordingAction = !isRecording ? /* @__PURE__ */ React__namespace.createElement("button", { type: "button", style: { ...getButtonStyle("primary", { fullWidth: true }), ...inlineStyles.captureButton }, onClick: start }, /* @__PURE__ */ React__namespace.createElement("svg", { style: inlineStyles.captureIcon, viewBox: "0 0 24 24", "aria-hidden": "true", focusable: "false" }, /* @__PURE__ */ React__namespace.createElement("circle", { cx: "12", cy: "12", r: "4.5" }), /* @__PURE__ */ React__namespace.createElement("path", { d: "M3.5 8.5h3l1.2-2h8.6l1.2 2h3v7h-3l-1.2 2H7.7l-1.2-2h-3z" })), /* @__PURE__ */ React__namespace.createElement("span", null, recording ? "Retake recording" : "Record a video"), recording ? /* @__PURE__ */ React__namespace.createElement("span", { style: inlineStyles.captureDone }, "Saved") : null) : /* @__PURE__ */ React__namespace.createElement("button", { type: "button", style: { ...getButtonStyle("danger", { fullWidth: true }), ...inlineStyles.captureButton }, onClick: stop }, /* @__PURE__ */ React__namespace.createElement("svg", { style: inlineStyles.captureIcon, viewBox: "0 0 24 24", "aria-hidden": "true", focusable: "false" }, /* @__PURE__ */ React__namespace.createElement("rect", { x: "7", y: "7", width: "10", height: "10" })), /* @__PURE__ */ React__namespace.createElement("span", null, "Stop (", seconds, "s)"));
|
|
2021
|
+
return /* @__PURE__ */ React__namespace.createElement("div", { style: inlineStyles.captureItem }, compactRecordingAction, error ? /* @__PURE__ */ React__namespace.createElement("p", { style: { ...inlineStyles.error, marginTop: "8px" } }, error) : null);
|
|
1674
2022
|
}
|
|
1675
|
-
return /* @__PURE__ */
|
|
2023
|
+
return /* @__PURE__ */ React__namespace.createElement("div", { style: embedded ? void 0 : inlineStyles.step }, embedded ? /* @__PURE__ */ React__namespace.createElement("h3", { style: inlineStyles.h3 }, "Screen recording") : /* @__PURE__ */ React__namespace.createElement("h2", { style: inlineStyles.h2 }, "Screen recording"), /* @__PURE__ */ React__namespace.createElement("p", { style: inlineStyles.p }, "Record up to ", config.storage.limits.maxVideoSeconds, " seconds. You can minimize this sidebar while recording."), /* @__PURE__ */ React__namespace.createElement("div", { style: inlineStyles.actions }, onBack ? /* @__PURE__ */ React__namespace.createElement("button", { type: "button", style: getButtonStyle("secondary", { disabled: isRecording }), onClick: onBack, disabled: isRecording }, "Back") : null, !isRecording ? /* @__PURE__ */ React__namespace.createElement("button", { type: "button", style: getButtonStyle("primary"), onClick: start }, recording ? "Retake recording" : "Record a video") : /* @__PURE__ */ React__namespace.createElement("button", { type: "button", style: getButtonStyle("danger"), onClick: stop }, "Stop (", seconds, "s)")), recording ? /* @__PURE__ */ React__namespace.createElement("video", { src: recording.previewUrl, style: inlineStyles.preview, controls: true }) : null, error ? /* @__PURE__ */ React__namespace.createElement("p", { style: inlineStyles.error }, error) : null, onNext ? /* @__PURE__ */ React__namespace.createElement("div", { style: inlineStyles.actions }, /* @__PURE__ */ React__namespace.createElement("button", { type: "button", style: getButtonStyle("primary"), onClick: onNext }, "Continue")) : null);
|
|
1676
2024
|
}
|
|
1677
2025
|
|
|
1678
2026
|
// src/components/StepDescribe.tsx
|
|
@@ -1685,13 +2033,13 @@ function StepDescribe({ onNext, CustomForm }) {
|
|
|
1685
2033
|
updateAttribute,
|
|
1686
2034
|
setScreenshot
|
|
1687
2035
|
} = useBugReporter();
|
|
1688
|
-
const screenshot =
|
|
1689
|
-
const recording =
|
|
1690
|
-
const annotationRef =
|
|
1691
|
-
const customFormRef =
|
|
1692
|
-
const [isCapturing, setIsCapturing] =
|
|
1693
|
-
const [error, setError] =
|
|
1694
|
-
|
|
2036
|
+
const screenshot = React.useMemo(() => assets.find((asset) => asset.type === "screenshot"), [assets]);
|
|
2037
|
+
const recording = React.useMemo(() => assets.find((asset) => asset.type === "recording"), [assets]);
|
|
2038
|
+
const annotationRef = React.useRef(null);
|
|
2039
|
+
const customFormRef = React.useRef(null);
|
|
2040
|
+
const [isCapturing, setIsCapturing] = React.useState(false);
|
|
2041
|
+
const [error, setError] = React.useState(null);
|
|
2042
|
+
React.useEffect(() => {
|
|
1695
2043
|
if (!CustomForm) {
|
|
1696
2044
|
return;
|
|
1697
2045
|
}
|
|
@@ -1751,12 +2099,13 @@ function StepDescribe({ onNext, CustomForm }) {
|
|
|
1751
2099
|
}
|
|
1752
2100
|
};
|
|
1753
2101
|
const continueToNext = async () => {
|
|
2102
|
+
var _a;
|
|
1754
2103
|
setError(null);
|
|
1755
2104
|
if (config.features.screenshot && !screenshot) {
|
|
1756
2105
|
setError("Capture a screenshot to continue.");
|
|
1757
2106
|
return;
|
|
1758
2107
|
}
|
|
1759
|
-
if (config.features.screenshot && screenshot && config.features.annotations && annotationRef.current
|
|
2108
|
+
if (config.features.screenshot && screenshot && config.features.annotations && ((_a = annotationRef.current) == null ? void 0 : _a.hasAnnotations())) {
|
|
1760
2109
|
const annotatedBlob = await annotationRef.current.exportBlob();
|
|
1761
2110
|
validateScreenshotSize(annotatedBlob.size, config.storage.limits.maxScreenshotBytes);
|
|
1762
2111
|
setScreenshot({
|
|
@@ -1770,7 +2119,7 @@ function StepDescribe({ onNext, CustomForm }) {
|
|
|
1770
2119
|
onNext();
|
|
1771
2120
|
};
|
|
1772
2121
|
const canContinue = Boolean(draft.title.trim()) && (!config.features.screenshot || Boolean(screenshot));
|
|
1773
|
-
return /* @__PURE__ */
|
|
2122
|
+
return /* @__PURE__ */ React__namespace.createElement("div", { style: { ...inlineStyles.step, display: "flex", flexDirection: "column", minHeight: "100%" } }, /* @__PURE__ */ React__namespace.createElement("h2", { style: inlineStyles.h2 }, "Report a bug"), /* @__PURE__ */ React__namespace.createElement("p", { style: inlineStyles.p }, "Provide enough context so engineers can reproduce what happened."), /* @__PURE__ */ React__namespace.createElement("label", { style: inlineStyles.field }, "Title", /* @__PURE__ */ React__namespace.createElement(
|
|
1774
2123
|
"input",
|
|
1775
2124
|
{
|
|
1776
2125
|
style: inlineStyles.input,
|
|
@@ -1779,7 +2128,7 @@ function StepDescribe({ onNext, CustomForm }) {
|
|
|
1779
2128
|
placeholder: "Short summary",
|
|
1780
2129
|
required: true
|
|
1781
2130
|
}
|
|
1782
|
-
)), /* @__PURE__ */
|
|
2131
|
+
)), /* @__PURE__ */ React__namespace.createElement("label", { style: inlineStyles.field }, "Description", /* @__PURE__ */ React__namespace.createElement(
|
|
1783
2132
|
"textarea",
|
|
1784
2133
|
{
|
|
1785
2134
|
style: inlineStyles.input,
|
|
@@ -1788,7 +2137,7 @@ function StepDescribe({ onNext, CustomForm }) {
|
|
|
1788
2137
|
placeholder: "What happened?",
|
|
1789
2138
|
rows: 4
|
|
1790
2139
|
}
|
|
1791
|
-
)), CustomForm ? /* @__PURE__ */
|
|
2140
|
+
)), CustomForm ? /* @__PURE__ */ React__namespace.createElement("div", { ref: customFormRef }, /* @__PURE__ */ React__namespace.createElement(CustomForm, { attributes, setAttributes, updateAttribute })) : null, config.features.screenshot || config.features.recording ? /* @__PURE__ */ React__namespace.createElement(React__namespace.Fragment, null, /* @__PURE__ */ React__namespace.createElement("h3", { style: inlineStyles.h3 }, "Capture"), /* @__PURE__ */ React__namespace.createElement("div", { style: inlineStyles.captureRow }, config.features.screenshot ? /* @__PURE__ */ React__namespace.createElement("div", { style: inlineStyles.captureItem }, /* @__PURE__ */ React__namespace.createElement(
|
|
1792
2141
|
"button",
|
|
1793
2142
|
{
|
|
1794
2143
|
type: "button",
|
|
@@ -1796,10 +2145,10 @@ function StepDescribe({ onNext, CustomForm }) {
|
|
|
1796
2145
|
onClick: startCapture,
|
|
1797
2146
|
disabled: isCapturing
|
|
1798
2147
|
},
|
|
1799
|
-
/* @__PURE__ */
|
|
1800
|
-
/* @__PURE__ */
|
|
1801
|
-
screenshot ? /* @__PURE__ */
|
|
1802
|
-
)) : null, config.features.recording ? /* @__PURE__ */
|
|
2148
|
+
/* @__PURE__ */ React__namespace.createElement("svg", { style: inlineStyles.captureIcon, viewBox: "0 0 24 24", "aria-hidden": "true", focusable: "false" }, /* @__PURE__ */ React__namespace.createElement("path", { d: "M4 8.5h3l1.2-2h7.6l1.2 2h3v9H4z" }), /* @__PURE__ */ React__namespace.createElement("circle", { cx: "12", cy: "13", r: "3.5" })),
|
|
2149
|
+
/* @__PURE__ */ React__namespace.createElement("span", null, isCapturing ? "Capturing..." : screenshot ? "Retake screenshot" : "Screenshot"),
|
|
2150
|
+
screenshot ? /* @__PURE__ */ React__namespace.createElement("span", { style: inlineStyles.captureDone }, "Saved") : null
|
|
2151
|
+
)) : null, config.features.recording ? /* @__PURE__ */ React__namespace.createElement(StepRecording, { embedded: true, compact: true }) : null), /* @__PURE__ */ React__namespace.createElement("p", { style: inlineStyles.captureNote }, config.features.screenshot && config.features.recording ? `Capture a screenshot and optionally record up to ${config.storage.limits.maxVideoSeconds} seconds.` : config.features.screenshot ? "Capture the relevant area before continuing." : `Record up to ${config.storage.limits.maxVideoSeconds} seconds.`), screenshot ? /* @__PURE__ */ React__namespace.createElement("div", { style: inlineStyles.previewWrapper }, config.features.annotations ? /* @__PURE__ */ React__namespace.createElement(AnnotationCanvas, { ref: annotationRef, imageUrl: screenshot.previewUrl }) : /* @__PURE__ */ React__namespace.createElement("img", { src: screenshot.previewUrl, alt: "Screenshot preview", style: inlineStyles.preview })) : null, !screenshot && recording ? /* @__PURE__ */ React__namespace.createElement("p", { style: inlineStyles.captureNote }, "Recording saved.") : null) : null, error ? /* @__PURE__ */ React__namespace.createElement("p", { style: inlineStyles.error }, error) : null, /* @__PURE__ */ React__namespace.createElement(
|
|
1803
2152
|
"div",
|
|
1804
2153
|
{
|
|
1805
2154
|
style: {
|
|
@@ -1812,7 +2161,7 @@ function StepDescribe({ onNext, CustomForm }) {
|
|
|
1812
2161
|
paddingBottom: "12px"
|
|
1813
2162
|
}
|
|
1814
2163
|
},
|
|
1815
|
-
/* @__PURE__ */
|
|
2164
|
+
/* @__PURE__ */ React__namespace.createElement(
|
|
1816
2165
|
"button",
|
|
1817
2166
|
{
|
|
1818
2167
|
type: "button",
|
|
@@ -1831,7 +2180,7 @@ function StepReview({ onBack }) {
|
|
|
1831
2180
|
state: { assets, draft, isSubmitting, uploadProgress, error },
|
|
1832
2181
|
submit
|
|
1833
2182
|
} = useBugReporter();
|
|
1834
|
-
return /* @__PURE__ */
|
|
2183
|
+
return /* @__PURE__ */ React__namespace.createElement("div", { style: { ...inlineStyles.step, display: "flex", flexDirection: "column", minHeight: "100%" } }, /* @__PURE__ */ React__namespace.createElement("h2", { style: inlineStyles.h2 }, "Review and submit"), /* @__PURE__ */ React__namespace.createElement("p", { style: inlineStyles.p }, "Confirm details, then send your report."), /* @__PURE__ */ React__namespace.createElement("div", { style: inlineStyles.summary }, /* @__PURE__ */ React__namespace.createElement("strong", null, draft.title || "Untitled bug report"), /* @__PURE__ */ React__namespace.createElement("p", { style: inlineStyles.p }, draft.description || "No description provided.")), /* @__PURE__ */ React__namespace.createElement("div", { style: inlineStyles.assets }, assets.map((asset) => /* @__PURE__ */ React__namespace.createElement("div", { key: asset.id, style: inlineStyles.assetCard }, /* @__PURE__ */ React__namespace.createElement("span", { style: inlineStyles.assetType }, asset.type), asset.type === "recording" ? /* @__PURE__ */ React__namespace.createElement("video", { src: asset.previewUrl, controls: true, style: inlineStyles.preview }) : /* @__PURE__ */ React__namespace.createElement("img", { src: asset.previewUrl, alt: `${asset.type} preview`, style: inlineStyles.preview })))), isSubmitting ? /* @__PURE__ */ React__namespace.createElement("div", { style: inlineStyles.uploadProgress, "aria-live": "polite" }, "Uploading assets: ", Math.round(uploadProgress * 100), "%", /* @__PURE__ */ React__namespace.createElement("div", { style: inlineStyles.progressTrack }, /* @__PURE__ */ React__namespace.createElement("div", { style: { ...inlineStyles.progressFill, width: `${Math.round(uploadProgress * 100)}%` } }))) : null, error ? /* @__PURE__ */ React__namespace.createElement("p", { style: inlineStyles.error }, error) : null, /* @__PURE__ */ React__namespace.createElement(
|
|
1835
2184
|
"div",
|
|
1836
2185
|
{
|
|
1837
2186
|
style: {
|
|
@@ -1844,7 +2193,7 @@ function StepReview({ onBack }) {
|
|
|
1844
2193
|
paddingBottom: "12px"
|
|
1845
2194
|
}
|
|
1846
2195
|
},
|
|
1847
|
-
/* @__PURE__ */
|
|
2196
|
+
/* @__PURE__ */ React__namespace.createElement(
|
|
1848
2197
|
"button",
|
|
1849
2198
|
{
|
|
1850
2199
|
type: "button",
|
|
@@ -1854,7 +2203,7 @@ function StepReview({ onBack }) {
|
|
|
1854
2203
|
},
|
|
1855
2204
|
"Back"
|
|
1856
2205
|
),
|
|
1857
|
-
/* @__PURE__ */
|
|
2206
|
+
/* @__PURE__ */ React__namespace.createElement(
|
|
1858
2207
|
"button",
|
|
1859
2208
|
{
|
|
1860
2209
|
type: "button",
|
|
@@ -1871,15 +2220,15 @@ function StepReview({ onBack }) {
|
|
|
1871
2220
|
var DOCK_SIDES = ["left", "right", "top", "bottom"];
|
|
1872
2221
|
function DockIcon({ side }) {
|
|
1873
2222
|
if (side === "left") {
|
|
1874
|
-
return /* @__PURE__ */
|
|
2223
|
+
return /* @__PURE__ */ React__namespace.createElement("svg", { viewBox: "0 0 24 24", "aria-hidden": "true", focusable: "false", style: inlineStyles.iconSvg }, /* @__PURE__ */ React__namespace.createElement("path", { d: "M3.5 5.5h17v13h-17z" }), /* @__PURE__ */ React__namespace.createElement("path", { d: "M3.5 5.5h4.5v13H3.5z", fill: "currentColor", stroke: "none", opacity: "0.85" }));
|
|
1875
2224
|
}
|
|
1876
2225
|
if (side === "right") {
|
|
1877
|
-
return /* @__PURE__ */
|
|
2226
|
+
return /* @__PURE__ */ React__namespace.createElement("svg", { viewBox: "0 0 24 24", "aria-hidden": "true", focusable: "false", style: inlineStyles.iconSvg }, /* @__PURE__ */ React__namespace.createElement("path", { d: "M3.5 5.5h17v13h-17z" }), /* @__PURE__ */ React__namespace.createElement("path", { d: "M16 5.5h4.5v13H16z", fill: "currentColor", stroke: "none", opacity: "0.85" }));
|
|
1878
2227
|
}
|
|
1879
2228
|
if (side === "top") {
|
|
1880
|
-
return /* @__PURE__ */
|
|
2229
|
+
return /* @__PURE__ */ React__namespace.createElement("svg", { viewBox: "0 0 24 24", "aria-hidden": "true", focusable: "false", style: inlineStyles.iconSvg }, /* @__PURE__ */ React__namespace.createElement("path", { d: "M3.5 5.5h17v13h-17z" }), /* @__PURE__ */ React__namespace.createElement("path", { d: "M3.5 5.5h17v4.5h-17z", fill: "currentColor", stroke: "none", opacity: "0.85" }));
|
|
1881
2230
|
}
|
|
1882
|
-
return /* @__PURE__ */
|
|
2231
|
+
return /* @__PURE__ */ React__namespace.createElement("svg", { viewBox: "0 0 24 24", "aria-hidden": "true", focusable: "false", style: inlineStyles.iconSvg }, /* @__PURE__ */ React__namespace.createElement("path", { d: "M3.5 5.5h17v13h-17z" }), /* @__PURE__ */ React__namespace.createElement("path", { d: "M3.5 14h17v4.5h-17z", fill: "currentColor", stroke: "none", opacity: "0.85" }));
|
|
1883
2232
|
}
|
|
1884
2233
|
function BugReporterShell({ CustomForm, launcherPosition, launcherText, themeMode, buttonColor }) {
|
|
1885
2234
|
const { config, state, setDockSide, setStep, close, reset } = useBugReporter();
|
|
@@ -1893,7 +2242,7 @@ function BugReporterShell({ CustomForm, launcherPosition, launcherText, themeMod
|
|
|
1893
2242
|
close();
|
|
1894
2243
|
};
|
|
1895
2244
|
const modalTitle = state.step === "success" ? "Report submitted" : "Report a bug";
|
|
1896
|
-
return /* @__PURE__ */
|
|
2245
|
+
return /* @__PURE__ */ React__namespace.createElement(React__namespace.Fragment, null, /* @__PURE__ */ React__namespace.createElement(LauncherButton, { position: launcherPosition, text: launcherText, themeMode, buttonColor }), /* @__PURE__ */ React__namespace.createElement(
|
|
1897
2246
|
Modal,
|
|
1898
2247
|
{
|
|
1899
2248
|
isOpen: state.isOpen,
|
|
@@ -1904,9 +2253,9 @@ function BugReporterShell({ CustomForm, launcherPosition, launcherText, themeMod
|
|
|
1904
2253
|
zIndex: config.theme.zIndex + 1,
|
|
1905
2254
|
onRequestClose: requestClose
|
|
1906
2255
|
},
|
|
1907
|
-
/* @__PURE__ */
|
|
2256
|
+
/* @__PURE__ */ React__namespace.createElement("div", { style: inlineStyles.modalHeader }, /* @__PURE__ */ React__namespace.createElement("div", { style: inlineStyles.dockControls, role: "group", "aria-label": "Dock side" }, DOCK_SIDES.map((side) => {
|
|
1908
2257
|
const isActive = state.dockSide === side;
|
|
1909
|
-
return /* @__PURE__ */
|
|
2258
|
+
return /* @__PURE__ */ React__namespace.createElement(
|
|
1910
2259
|
"button",
|
|
1911
2260
|
{
|
|
1912
2261
|
key: side,
|
|
@@ -1916,11 +2265,11 @@ function BugReporterShell({ CustomForm, launcherPosition, launcherText, themeMod
|
|
|
1916
2265
|
"aria-pressed": isActive,
|
|
1917
2266
|
"aria-label": `Dock ${side}`
|
|
1918
2267
|
},
|
|
1919
|
-
/* @__PURE__ */
|
|
2268
|
+
/* @__PURE__ */ React__namespace.createElement(DockIcon, { side })
|
|
1920
2269
|
);
|
|
1921
|
-
})), /* @__PURE__ */
|
|
1922
|
-
state.step === "describe" ? /* @__PURE__ */
|
|
1923
|
-
state.step === "review" || state.step === "submitting" ? /* @__PURE__ */
|
|
2270
|
+
})), /* @__PURE__ */ React__namespace.createElement("button", { style: inlineStyles.iconButton, type: "button", onClick: requestClose, "aria-label": "Close bug reporter" }, /* @__PURE__ */ React__namespace.createElement("svg", { viewBox: "0 0 24 24", "aria-hidden": "true", focusable: "false", style: inlineStyles.iconSvg }, /* @__PURE__ */ React__namespace.createElement("path", { d: "M6 6 18 18M18 6 6 18" })))),
|
|
2271
|
+
state.step === "describe" ? /* @__PURE__ */ React__namespace.createElement(StepDescribe, { onNext: nextFromDescribe, CustomForm }) : null,
|
|
2272
|
+
state.step === "review" || state.step === "submitting" ? /* @__PURE__ */ React__namespace.createElement(
|
|
1924
2273
|
StepReview,
|
|
1925
2274
|
{
|
|
1926
2275
|
onBack: () => {
|
|
@@ -1928,7 +2277,7 @@ function BugReporterShell({ CustomForm, launcherPosition, launcherText, themeMod
|
|
|
1928
2277
|
}
|
|
1929
2278
|
}
|
|
1930
2279
|
) : null,
|
|
1931
|
-
state.step === "success" ? /* @__PURE__ */
|
|
2280
|
+
state.step === "success" ? /* @__PURE__ */ React__namespace.createElement("div", { style: inlineStyles.step }, /* @__PURE__ */ React__namespace.createElement("h2", { style: inlineStyles.h2 }, "Thanks, report submitted"), /* @__PURE__ */ React__namespace.createElement("p", { style: inlineStyles.p }, "Your bug report has been sent successfully."), /* @__PURE__ */ React__namespace.createElement("div", { style: inlineStyles.actions }, /* @__PURE__ */ React__namespace.createElement("button", { type: "button", style: getButtonStyle("primary"), onClick: requestClose }, "Close"))) : null
|
|
1932
2281
|
));
|
|
1933
2282
|
}
|
|
1934
2283
|
function BugReporter({
|
|
@@ -1939,8 +2288,9 @@ function BugReporter({
|
|
|
1939
2288
|
themeMode = "dark",
|
|
1940
2289
|
buttonColor
|
|
1941
2290
|
}) {
|
|
1942
|
-
|
|
1943
|
-
|
|
2291
|
+
var _a, _b;
|
|
2292
|
+
const resolvedButtonColor = (_b = buttonColor != null ? buttonColor : (_a = config.theme) == null ? void 0 : _a.primaryColor) != null ? _b : "#3b82f6";
|
|
2293
|
+
return /* @__PURE__ */ React__namespace.createElement(BugReporterProvider, { config }, /* @__PURE__ */ React__namespace.createElement(
|
|
1944
2294
|
BugReporterShell,
|
|
1945
2295
|
{
|
|
1946
2296
|
CustomForm,
|
|
@@ -1952,11 +2302,8 @@ function BugReporter({
|
|
|
1952
2302
|
));
|
|
1953
2303
|
}
|
|
1954
2304
|
|
|
1955
|
-
Object.defineProperty(exports, "BugReporterError", {
|
|
1956
|
-
enumerable: true,
|
|
1957
|
-
get: function () { return chunk6TCI6T2U_cjs.BugReporterError; }
|
|
1958
|
-
});
|
|
1959
2305
|
exports.BugReporter = BugReporter;
|
|
2306
|
+
exports.BugReporterError = BugReporterError;
|
|
1960
2307
|
exports.BugReporterProvider = BugReporterProvider;
|
|
1961
2308
|
exports.useBugReporter = useBugReporter;
|
|
1962
2309
|
//# sourceMappingURL=index.cjs.map
|