@sphoro/bugcatch-web-sdk 0.14.2 → 0.14.3
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/bugcatch.es.js +531 -512
- package/dist/bugcatch.es.js.map +1 -1
- package/dist/bugcatch.umd.js +61 -48
- package/dist/bugcatch.umd.js.map +1 -1
- package/package.json +1 -1
- package/src/widget.js +28 -0
package/dist/bugcatch.es.js
CHANGED
|
@@ -3,7 +3,7 @@ var _t = (t) => {
|
|
|
3
3
|
};
|
|
4
4
|
var Kn = (t, e, n) => e.has(t) || _t("Cannot " + n);
|
|
5
5
|
var Ft = (t, e, n) => e.has(t) ? _t("Cannot add the same private member more than once") : e instanceof WeakSet ? e.add(t) : e.set(t, n);
|
|
6
|
-
var
|
|
6
|
+
var V = (t, e, n) => (Kn(t, e, "access private method"), n);
|
|
7
7
|
const rt = "[REDACTED]", Pn = /* @__PURE__ */ new Set([
|
|
8
8
|
"auth",
|
|
9
9
|
"bearer",
|
|
@@ -72,7 +72,7 @@ function Jn(t, e) {
|
|
|
72
72
|
for (const o of _n) if (n.includes(o)) return !0;
|
|
73
73
|
return Fn.has(n) ? Zn(pn(e)) : !1;
|
|
74
74
|
}
|
|
75
|
-
function
|
|
75
|
+
function yt(t) {
|
|
76
76
|
return t.split("&").map((e) => {
|
|
77
77
|
const n = e.indexOf("=");
|
|
78
78
|
if (n === -1) return e;
|
|
@@ -94,9 +94,9 @@ function fn(t) {
|
|
|
94
94
|
const n = e.indexOf("#");
|
|
95
95
|
let o = n === -1 ? e : e.slice(0, n), i = n === -1 ? "" : e.slice(n);
|
|
96
96
|
const r = o.indexOf("?");
|
|
97
|
-
if (r !== -1 && (o = o.slice(0, r + 1) +
|
|
97
|
+
if (r !== -1 && (o = o.slice(0, r + 1) + yt(o.slice(r + 1))), i.length > 1) {
|
|
98
98
|
const s = i.slice(1), l = s.indexOf("?");
|
|
99
|
-
l !== -1 ? i = `#${s.slice(0, l + 1)}${
|
|
99
|
+
l !== -1 ? i = `#${s.slice(0, l + 1)}${yt(s.slice(l + 1))}` : s.includes("=") && (i = `#${yt(s)}`);
|
|
100
100
|
}
|
|
101
101
|
return hn(o + i);
|
|
102
102
|
}
|
|
@@ -142,13 +142,13 @@ function eo(t, { levels: e = ["warn", "error", "log", "info"] } = {}) {
|
|
|
142
142
|
function to(t, { slowMs: e = 2e3 } = {}) {
|
|
143
143
|
const n = window.fetch, o = XMLHttpRequest.prototype.open, i = XMLHttpRequest.prototype.send;
|
|
144
144
|
return n && (window.fetch = async function(...s) {
|
|
145
|
-
var
|
|
146
|
-
const l = performance.now(), u = typeof s[0] == "string" ? s[0] : (
|
|
145
|
+
var y, p, b;
|
|
146
|
+
const l = performance.now(), u = typeof s[0] == "string" ? s[0] : (y = s[0]) == null ? void 0 : y.url, h = ((p = s[1]) == null ? void 0 : p.method) || (typeof s[0] == "object" ? (b = s[0]) == null ? void 0 : b.method : "GET") || "GET";
|
|
147
147
|
try {
|
|
148
|
-
const
|
|
149
|
-
return wt(t, { url: u, method:
|
|
150
|
-
} catch (
|
|
151
|
-
throw wt(t, { url: u, method:
|
|
148
|
+
const f = await n.apply(this, s);
|
|
149
|
+
return wt(t, { url: u, method: h, status: f.status, ms: Math.round(performance.now() - l), slowMs: e }), f;
|
|
150
|
+
} catch (f) {
|
|
151
|
+
throw wt(t, { url: u, method: h, status: 0, error: String((f == null ? void 0 : f.message) || f), ms: Math.round(performance.now() - l), slowMs: e }), f;
|
|
152
152
|
}
|
|
153
153
|
}), XMLHttpRequest.prototype.open = function(s, l, ...u) {
|
|
154
154
|
return this.__bc = { method: s, url: l, started: 0 }, o.call(this, s, l, ...u);
|
|
@@ -219,7 +219,7 @@ async function Yt() {
|
|
|
219
219
|
return t;
|
|
220
220
|
}
|
|
221
221
|
function gn() {
|
|
222
|
-
var e, n, o, i, r, s, l, u,
|
|
222
|
+
var e, n, o, i, r, s, l, u, h;
|
|
223
223
|
const t = window.navigator || {};
|
|
224
224
|
return {
|
|
225
225
|
userAgent: t.userAgent,
|
|
@@ -257,7 +257,7 @@ function gn() {
|
|
|
257
257
|
saveData: t.connection.saveData
|
|
258
258
|
} : null,
|
|
259
259
|
prefersColorScheme: (u = window.matchMedia) != null && u.call(window, "(prefers-color-scheme: dark)").matches ? "dark" : "light",
|
|
260
|
-
prefersReducedMotion: ((
|
|
260
|
+
prefersReducedMotion: ((h = window.matchMedia) == null ? void 0 : h.call(window, "(prefers-reduced-motion: reduce)").matches) || !1
|
|
261
261
|
};
|
|
262
262
|
}
|
|
263
263
|
function mn(t) {
|
|
@@ -331,15 +331,15 @@ async function uo({ maxMs: t = 12e4, onTick: e, onAutoStop: n } = {}) {
|
|
|
331
331
|
const o = await navigator.mediaDevices.getDisplayMedia({
|
|
332
332
|
video: { frameRate: 15 },
|
|
333
333
|
audio: !1
|
|
334
|
-
}), i = ["video/webm;codecs=vp9", "video/webm;codecs=vp8", "video/webm"].find((
|
|
335
|
-
r.ondataavailable = (
|
|
336
|
-
|
|
334
|
+
}), i = ["video/webm;codecs=vp9", "video/webm;codecs=vp8", "video/webm"].find((f) => MediaRecorder.isTypeSupported(f)) || "video/webm", r = new MediaRecorder(o, { mimeType: i, videoBitsPerSecond: 25e5 }), s = [];
|
|
335
|
+
r.ondataavailable = (f) => {
|
|
336
|
+
f.data.size && s.push(f.data);
|
|
337
337
|
}, r.start(1e3);
|
|
338
|
-
const l = Date.now(), u = setInterval(() => e == null ? void 0 : e(Math.floor((Date.now() - l) / 1e3)), 500),
|
|
339
|
-
clearInterval(u), clearTimeout(b), o.getTracks().forEach((
|
|
340
|
-
},
|
|
338
|
+
const l = Date.now(), u = setInterval(() => e == null ? void 0 : e(Math.floor((Date.now() - l) / 1e3)), 500), h = () => {
|
|
339
|
+
clearInterval(u), clearTimeout(b), o.getTracks().forEach((f) => f.stop());
|
|
340
|
+
}, y = new Promise((f) => {
|
|
341
341
|
r.onstop = () => {
|
|
342
|
-
|
|
342
|
+
h(), f(new Blob(s, { type: i }));
|
|
343
343
|
};
|
|
344
344
|
}), p = () => {
|
|
345
345
|
r.state !== "inactive" && r.stop(), n == null || n();
|
|
@@ -350,23 +350,23 @@ async function uo({ maxMs: t = 12e4, onTick: e, onAutoStop: n } = {}) {
|
|
|
350
350
|
mime: i,
|
|
351
351
|
maxMs: t,
|
|
352
352
|
async stop() {
|
|
353
|
-
return clearTimeout(b), r.state !== "inactive" && r.stop(), { blob: await
|
|
353
|
+
return clearTimeout(b), r.state !== "inactive" && r.stop(), { blob: await y, mime: i, kind: "VIDEO" };
|
|
354
354
|
},
|
|
355
355
|
cancel() {
|
|
356
|
-
|
|
356
|
+
h(), r.state !== "inactive" && r.stop();
|
|
357
357
|
}
|
|
358
358
|
};
|
|
359
359
|
}
|
|
360
360
|
async function po({ maxMs: t = 12e4, onTick: e, onAutoStop: n } = {}) {
|
|
361
|
-
const o = await navigator.mediaDevices.getUserMedia({ audio: !0 }), i = ["audio/webm;codecs=opus", "audio/webm", "audio/mp4", "audio/ogg"].find((
|
|
362
|
-
r.ondataavailable = (
|
|
363
|
-
|
|
361
|
+
const o = await navigator.mediaDevices.getUserMedia({ audio: !0 }), i = ["audio/webm;codecs=opus", "audio/webm", "audio/mp4", "audio/ogg"].find((f) => MediaRecorder.isTypeSupported(f)) || "", r = new MediaRecorder(o, i ? { mimeType: i } : void 0), s = [];
|
|
362
|
+
r.ondataavailable = (f) => {
|
|
363
|
+
f.data.size && s.push(f.data);
|
|
364
364
|
}, r.start(1e3);
|
|
365
|
-
const l = Date.now(), u = setInterval(() => e == null ? void 0 : e(Math.floor((Date.now() - l) / 1e3)), 500),
|
|
366
|
-
clearInterval(u), clearTimeout(b), o.getTracks().forEach((
|
|
367
|
-
},
|
|
365
|
+
const l = Date.now(), u = setInterval(() => e == null ? void 0 : e(Math.floor((Date.now() - l) / 1e3)), 500), h = () => {
|
|
366
|
+
clearInterval(u), clearTimeout(b), o.getTracks().forEach((f) => f.stop());
|
|
367
|
+
}, y = new Promise((f) => {
|
|
368
368
|
r.onstop = () => {
|
|
369
|
-
|
|
369
|
+
h(), f(new Blob(s, { type: r.mimeType || i }));
|
|
370
370
|
};
|
|
371
371
|
}), b = setTimeout(() => {
|
|
372
372
|
r.state !== "inactive" && r.stop(), n == null || n();
|
|
@@ -376,11 +376,11 @@ async function po({ maxMs: t = 12e4, onTick: e, onAutoStop: n } = {}) {
|
|
|
376
376
|
maxMs: t,
|
|
377
377
|
async stop() {
|
|
378
378
|
clearTimeout(b), r.state !== "inactive" && r.stop();
|
|
379
|
-
const
|
|
380
|
-
return { blob:
|
|
379
|
+
const f = await y;
|
|
380
|
+
return { blob: f, mime: f.type || r.mimeType || i, kind: "AUDIO" };
|
|
381
381
|
},
|
|
382
382
|
cancel() {
|
|
383
|
-
|
|
383
|
+
h(), r.state !== "inactive" && r.stop();
|
|
384
384
|
}
|
|
385
385
|
};
|
|
386
386
|
}
|
|
@@ -437,23 +437,23 @@ async function nt(t, e) {
|
|
|
437
437
|
r.oncomplete = () => o(l.result), r.onerror = () => i(r.error), r.onabort = () => i(r.error || new Error("Draft was not saved."));
|
|
438
438
|
});
|
|
439
439
|
}
|
|
440
|
-
async function
|
|
440
|
+
async function yo(t) {
|
|
441
441
|
const e = await nt(t);
|
|
442
442
|
return e && Date.now() - e.savedAt > go ? (await nt(t, null), null) : e || null;
|
|
443
443
|
}
|
|
444
|
-
const
|
|
445
|
-
function
|
|
444
|
+
const wo = "bugcatch.session.", $t = (t) => `${wo}${t}`, Tt = /* @__PURE__ */ new Map();
|
|
445
|
+
function he(t) {
|
|
446
446
|
var e;
|
|
447
447
|
if (!t) return null;
|
|
448
448
|
try {
|
|
449
|
-
const n = (e = window.localStorage) == null ? void 0 : e.getItem(
|
|
449
|
+
const n = (e = window.localStorage) == null ? void 0 : e.getItem($t(t));
|
|
450
450
|
if (n) {
|
|
451
451
|
const o = JSON.parse(n);
|
|
452
452
|
if (o != null && o.token) return o;
|
|
453
453
|
}
|
|
454
454
|
} catch {
|
|
455
455
|
}
|
|
456
|
-
return
|
|
456
|
+
return Tt.get(t) || null;
|
|
457
457
|
}
|
|
458
458
|
function vo(t, e) {
|
|
459
459
|
var o;
|
|
@@ -463,18 +463,18 @@ function vo(t, e) {
|
|
|
463
463
|
email: e.email || null,
|
|
464
464
|
name: e.name || null
|
|
465
465
|
};
|
|
466
|
-
|
|
466
|
+
Tt.set(t, n);
|
|
467
467
|
try {
|
|
468
|
-
(o = window.localStorage) == null || o.setItem(
|
|
468
|
+
(o = window.localStorage) == null || o.setItem($t(t), JSON.stringify(n));
|
|
469
469
|
} catch {
|
|
470
470
|
}
|
|
471
471
|
}
|
|
472
|
-
function
|
|
472
|
+
function kt(t) {
|
|
473
473
|
var e;
|
|
474
474
|
if (t) {
|
|
475
|
-
|
|
475
|
+
Tt.delete(t);
|
|
476
476
|
try {
|
|
477
|
-
(e = window.localStorage) == null || e.removeItem(
|
|
477
|
+
(e = window.localStorage) == null || e.removeItem($t(t));
|
|
478
478
|
} catch {
|
|
479
479
|
}
|
|
480
480
|
}
|
|
@@ -489,7 +489,7 @@ function it({ apiKey: t, token: e }) {
|
|
|
489
489
|
...e ? { "X-BugCatch-Session": e } : {}
|
|
490
490
|
};
|
|
491
491
|
}
|
|
492
|
-
async function
|
|
492
|
+
async function yn(t) {
|
|
493
493
|
try {
|
|
494
494
|
const e = await t.json(), n = Array.isArray(e.message) ? e.message.join(", ") : e.message;
|
|
495
495
|
if (n) return n;
|
|
@@ -521,7 +521,7 @@ async function ko({ apiBase: t, apiKey: e, projectId: n, email: o, name: i }) {
|
|
|
521
521
|
headers: it({ apiKey: e }),
|
|
522
522
|
body: JSON.stringify({ projectId: n, email: o, ...i ? { name: i } : {} })
|
|
523
523
|
});
|
|
524
|
-
if (!r.ok) throw new Error(await
|
|
524
|
+
if (!r.ok) throw new Error(await yn(r));
|
|
525
525
|
return r.json();
|
|
526
526
|
}
|
|
527
527
|
async function So({ apiBase: t, apiKey: e, projectId: n, email: o, code: i }) {
|
|
@@ -530,12 +530,12 @@ async function So({ apiBase: t, apiKey: e, projectId: n, email: o, code: i }) {
|
|
|
530
530
|
headers: it({ apiKey: e }),
|
|
531
531
|
body: JSON.stringify({ projectId: n, email: o, code: i })
|
|
532
532
|
});
|
|
533
|
-
if (!r.ok) throw new Error(await
|
|
533
|
+
if (!r.ok) throw new Error(await yn(r));
|
|
534
534
|
const s = await r.json(), l = { token: s.sessionToken, email: s.email, name: s.name };
|
|
535
535
|
return vo(n, l), l;
|
|
536
536
|
}
|
|
537
537
|
async function Co({ apiBase: t, apiKey: e, projectId: n, token: o }) {
|
|
538
|
-
if (
|
|
538
|
+
if (kt(n), !o) return { signedOut: !0 };
|
|
539
539
|
try {
|
|
540
540
|
await fetch(`${t}/ingest/logout`, {
|
|
541
541
|
method: "POST",
|
|
@@ -546,30 +546,30 @@ async function Co({ apiBase: t, apiKey: e, projectId: n, token: o }) {
|
|
|
546
546
|
}
|
|
547
547
|
return { signedOut: !0 };
|
|
548
548
|
}
|
|
549
|
-
const
|
|
549
|
+
const It = "bugcatch.watch", Xt = [2e3, 5e3, 15e3, 3e4, 6e4], Eo = 5e3;
|
|
550
550
|
function se() {
|
|
551
551
|
var t;
|
|
552
552
|
try {
|
|
553
|
-
return ((t = window.localStorage) == null ? void 0 : t.getItem(
|
|
553
|
+
return ((t = window.localStorage) == null ? void 0 : t.getItem(It)) || null;
|
|
554
554
|
} catch {
|
|
555
555
|
return null;
|
|
556
556
|
}
|
|
557
557
|
}
|
|
558
|
-
function
|
|
558
|
+
function St(t) {
|
|
559
559
|
var e;
|
|
560
560
|
if (t)
|
|
561
561
|
try {
|
|
562
|
-
(e = window.localStorage) == null || e.setItem(
|
|
562
|
+
(e = window.localStorage) == null || e.setItem(It, t);
|
|
563
563
|
} catch {
|
|
564
564
|
}
|
|
565
565
|
}
|
|
566
566
|
function Ee() {
|
|
567
567
|
var t;
|
|
568
568
|
try {
|
|
569
|
-
(t = window.localStorage) == null || t.removeItem(
|
|
569
|
+
(t = window.localStorage) == null || t.removeItem(It);
|
|
570
570
|
} catch {
|
|
571
571
|
}
|
|
572
|
-
|
|
572
|
+
wn();
|
|
573
573
|
}
|
|
574
574
|
const ot = "bugcatch.unread";
|
|
575
575
|
function $o(t) {
|
|
@@ -603,7 +603,7 @@ function Mo(t) {
|
|
|
603
603
|
const e = Ne().filter((n) => n.bugId !== t);
|
|
604
604
|
return st(e), e;
|
|
605
605
|
}
|
|
606
|
-
function
|
|
606
|
+
function wn() {
|
|
607
607
|
return st([]), [];
|
|
608
608
|
}
|
|
609
609
|
function Lo(t, e) {
|
|
@@ -811,13 +811,13 @@ function Ho({ apiBase: t, onUpdate: e }) {
|
|
|
811
811
|
if (l.status === 401)
|
|
812
812
|
throw n = !1, Ee(), new Error("subscription no longer valid");
|
|
813
813
|
if (!l.ok || !l.body) throw new Error(`stream failed (${l.status})`);
|
|
814
|
-
const u = Date.now(),
|
|
814
|
+
const u = Date.now(), h = l.body.getReader(), y = new TextDecoder();
|
|
815
815
|
let p = "";
|
|
816
816
|
try {
|
|
817
817
|
for (; ; ) {
|
|
818
|
-
const { value: b, done:
|
|
819
|
-
if (
|
|
820
|
-
p +=
|
|
818
|
+
const { value: b, done: f } = await h.read();
|
|
819
|
+
if (f) break;
|
|
820
|
+
p += y.decode(b, { stream: !0 }), p = Lo(p, (k) => {
|
|
821
821
|
if (k.type !== "ping")
|
|
822
822
|
try {
|
|
823
823
|
e(k);
|
|
@@ -890,10 +890,10 @@ function Ko({
|
|
|
890
890
|
onReadAll: o = null,
|
|
891
891
|
onCall: i = null
|
|
892
892
|
} = {}) {
|
|
893
|
-
const [r, s] = String(e).split("-"), l = r === "top", u = s === "left",
|
|
894
|
-
let
|
|
893
|
+
const [r, s] = String(e).split("-"), l = r === "top", u = s === "left", h = /* @__PURE__ */ new Map();
|
|
894
|
+
let y = null, p = null;
|
|
895
895
|
function b() {
|
|
896
|
-
return
|
|
896
|
+
return y != null && y.isConnected || (y = document.createElement("div"), y.setAttribute("data-bugcatch", "updates"), y.style.cssText = [
|
|
897
897
|
"position:fixed",
|
|
898
898
|
`${l ? "top" : "bottom"}:${20 + Vo()}px`,
|
|
899
899
|
`${u ? "left" : "right"}:20px`,
|
|
@@ -908,9 +908,9 @@ function Ko({
|
|
|
908
908
|
"width:min(320px,calc(100vw - 40px))",
|
|
909
909
|
// The gaps between cards belong to the page underneath.
|
|
910
910
|
"pointer-events:none"
|
|
911
|
-
].join(";"), document.body.appendChild(
|
|
911
|
+
].join(";"), document.body.appendChild(y)), y;
|
|
912
912
|
}
|
|
913
|
-
function
|
|
913
|
+
function f(S) {
|
|
914
914
|
if (!S._bcShown) {
|
|
915
915
|
S.remove();
|
|
916
916
|
return;
|
|
@@ -931,7 +931,7 @@ function Ko({
|
|
|
931
931
|
].join(";"), T;
|
|
932
932
|
}
|
|
933
933
|
function A(S) {
|
|
934
|
-
var
|
|
934
|
+
var D;
|
|
935
935
|
const E = document.createElement("div");
|
|
936
936
|
E.setAttribute("role", "status"), E.style.cssText = [
|
|
937
937
|
"box-sizing:border-box",
|
|
@@ -954,12 +954,12 @@ function Ko({
|
|
|
954
954
|
L.style.cssText = (S == null ? void 0 : S.kind) === "reply" ? "color:#a4abba;display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden" : "color:#a4abba", L.textContent = No(S);
|
|
955
955
|
const Y = document.createElement("div");
|
|
956
956
|
Y.style.cssText = "display:flex;align-items:center;gap:8px;margin-top:10px;flex-wrap:wrap";
|
|
957
|
-
const
|
|
958
|
-
|
|
959
|
-
const
|
|
960
|
-
if (
|
|
957
|
+
const q = document.createElement("span");
|
|
958
|
+
q.style.cssText = "color:#7b8394;font-size:11px;margin-right:auto", q.textContent = Uo(S == null ? void 0 : S.at);
|
|
959
|
+
const Q = k("Mark as read", !1);
|
|
960
|
+
if (Q.setAttribute("aria-label", `Mark as read: ${Gt(S)}`), Q.addEventListener("click", () => n == null ? void 0 : n(S.id)), Y.append(q, Q), (D = S == null ? void 0 : S.call) != null && D.offered && typeof i == "function") {
|
|
961
961
|
const $ = k("Talk it through", !0);
|
|
962
|
-
$.addEventListener("click", () => i(S)), Y.insertBefore($,
|
|
962
|
+
$.addEventListener("click", () => i(S)), Y.insertBefore($, Q);
|
|
963
963
|
}
|
|
964
964
|
return E.append(T, L, Y), E;
|
|
965
965
|
}
|
|
@@ -995,29 +995,29 @@ function Ko({
|
|
|
995
995
|
render(S) {
|
|
996
996
|
const E = Array.isArray(S) ? S : [];
|
|
997
997
|
if (!E.length) {
|
|
998
|
-
for (const $ of
|
|
999
|
-
|
|
998
|
+
for (const $ of h.values()) f($);
|
|
999
|
+
h.clear(), p == null || p.remove(), p = null, y == null || y.remove(), y = null;
|
|
1000
1000
|
return;
|
|
1001
1001
|
}
|
|
1002
1002
|
const T = E.slice(-3), L = new Set(T.map(($) => $.id)), Y = b();
|
|
1003
|
-
for (const [$, ae] of
|
|
1004
|
-
L.has($) || (
|
|
1005
|
-
const
|
|
1003
|
+
for (const [$, ae] of h)
|
|
1004
|
+
L.has($) || (f(ae), h.delete($));
|
|
1005
|
+
const q = [];
|
|
1006
1006
|
for (const $ of T) {
|
|
1007
|
-
if (
|
|
1007
|
+
if (h.has($.id)) continue;
|
|
1008
1008
|
const ae = A($);
|
|
1009
|
-
|
|
1009
|
+
h.set($.id, ae), q.push(ae);
|
|
1010
1010
|
}
|
|
1011
|
-
const
|
|
1012
|
-
for (const $ of
|
|
1013
|
-
const
|
|
1014
|
-
|
|
1015
|
-
for (const $ of
|
|
1011
|
+
const Q = l ? [...T].reverse() : T;
|
|
1012
|
+
for (const $ of Q) Y.appendChild(h.get($.id));
|
|
1013
|
+
const D = E.length - T.length;
|
|
1014
|
+
D > 0 ? (p == null || p.remove(), p = oe(D), l ? Y.appendChild(p) : Y.insertBefore(p, Y.firstChild)) : (p == null || p.remove(), p = null), requestAnimationFrame(() => {
|
|
1015
|
+
for (const $ of q)
|
|
1016
1016
|
$.isConnected && ($._bcShown = !0, $.style.opacity = "1", $.style.transform = "translateY(0)");
|
|
1017
1017
|
});
|
|
1018
1018
|
},
|
|
1019
1019
|
destroy() {
|
|
1020
|
-
|
|
1020
|
+
h.clear(), p = null, y == null || y.remove(), y = null;
|
|
1021
1021
|
}
|
|
1022
1022
|
};
|
|
1023
1023
|
}
|
|
@@ -1025,7 +1025,7 @@ async function Po({ apiBase: t, apiKey: e, projectId: n, sessionToken: o }) {
|
|
|
1025
1025
|
try {
|
|
1026
1026
|
const i = await fetch(
|
|
1027
1027
|
`${t}/ingest/known-issues?projectId=${encodeURIComponent(n)}`,
|
|
1028
|
-
{ headers:
|
|
1028
|
+
{ headers: Mt(e, o) }
|
|
1029
1029
|
);
|
|
1030
1030
|
if (!i.ok) return [];
|
|
1031
1031
|
const r = await i.json();
|
|
@@ -1036,7 +1036,7 @@ async function Po({ apiBase: t, apiKey: e, projectId: n, sessionToken: o }) {
|
|
|
1036
1036
|
}
|
|
1037
1037
|
async function _o({ apiBase: t, apiKey: e, projectId: n, q: o, sessionToken: i, signal: r }) {
|
|
1038
1038
|
try {
|
|
1039
|
-
const s = `${t}/ingest/known-issues/match?projectId=${encodeURIComponent(n)}&q=${encodeURIComponent(o)}`, l = await fetch(s, { headers:
|
|
1039
|
+
const s = `${t}/ingest/known-issues/match?projectId=${encodeURIComponent(n)}&q=${encodeURIComponent(o)}`, l = await fetch(s, { headers: Mt(e, i), signal: r });
|
|
1040
1040
|
if (!l.ok) return [];
|
|
1041
1041
|
const u = await l.json();
|
|
1042
1042
|
return Array.isArray(u == null ? void 0 : u.issues) ? u.issues : [];
|
|
@@ -1055,19 +1055,19 @@ async function Fo({
|
|
|
1055
1055
|
logs: l,
|
|
1056
1056
|
sessionToken: u
|
|
1057
1057
|
}) {
|
|
1058
|
-
const
|
|
1058
|
+
const h = await fetch(
|
|
1059
1059
|
`${t}/ingest/known-issues/${encodeURIComponent(o)}/join`,
|
|
1060
1060
|
{
|
|
1061
1061
|
method: "POST",
|
|
1062
|
-
headers:
|
|
1062
|
+
headers: Mt(e, u),
|
|
1063
1063
|
body: JSON.stringify({ projectId: n, reporterEmail: i, reporterName: r, metadata: s, logs: l })
|
|
1064
1064
|
}
|
|
1065
1065
|
);
|
|
1066
|
-
if (!
|
|
1067
|
-
const
|
|
1068
|
-
return
|
|
1066
|
+
if (!h.ok) throw new Error(await Wo(h));
|
|
1067
|
+
const y = await h.json();
|
|
1068
|
+
return y != null && y.watchToken && St(y.watchToken), y;
|
|
1069
1069
|
}
|
|
1070
|
-
function
|
|
1070
|
+
function Mt(t, e) {
|
|
1071
1071
|
return {
|
|
1072
1072
|
"Content-Type": "application/json",
|
|
1073
1073
|
"X-BugCatch-Key": t,
|
|
@@ -1112,22 +1112,22 @@ function Jo(t, e) {
|
|
|
1112
1112
|
for (const i of e || []) {
|
|
1113
1113
|
const r = typeof i == "string" ? i.slice(0, Xo) : "";
|
|
1114
1114
|
if (!r) continue;
|
|
1115
|
-
const s = [], l = (u,
|
|
1115
|
+
const s = [], l = (u, h) => s.some(([y, p]) => u < p && h > y);
|
|
1116
1116
|
for (const u of t || []) {
|
|
1117
1117
|
if (!u || u.scan === !1) continue;
|
|
1118
|
-
const
|
|
1119
|
-
if (!
|
|
1120
|
-
let
|
|
1121
|
-
for (
|
|
1122
|
-
if (
|
|
1123
|
-
|
|
1118
|
+
const h = Sn(u.pattern);
|
|
1119
|
+
if (!h) continue;
|
|
1120
|
+
let y, p = 0;
|
|
1121
|
+
for (h.lastIndex = 0; (y = h.exec(r)) !== null && !(++p > kn); ) {
|
|
1122
|
+
if (y[0] === "") {
|
|
1123
|
+
h.lastIndex += 1;
|
|
1124
1124
|
continue;
|
|
1125
1125
|
}
|
|
1126
|
-
const b = Cn(
|
|
1126
|
+
const b = Cn(y);
|
|
1127
1127
|
if (b && !l(b.start, b.end)) {
|
|
1128
1128
|
s.push([b.start, b.end]);
|
|
1129
|
-
const
|
|
1130
|
-
o.has(
|
|
1129
|
+
const f = `${u.key}:${b.value.toLowerCase()}`;
|
|
1130
|
+
o.has(f) || (o.add(f), n.push({ key: u.key, label: u.label, value: b.value }));
|
|
1131
1131
|
}
|
|
1132
1132
|
}
|
|
1133
1133
|
}
|
|
@@ -1177,7 +1177,7 @@ const en = {
|
|
|
1177
1177
|
{ value: "MEDIUM", label: "Medium" },
|
|
1178
1178
|
{ value: "HIGH", label: "High" },
|
|
1179
1179
|
{ value: "CRITICAL", label: "Critical" }
|
|
1180
|
-
],
|
|
1180
|
+
], j = {
|
|
1181
1181
|
camera: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M3 8.5A1.5 1.5 0 0 1 4.5 7h2.2a1 1 0 0 0 .83-.45l.94-1.4A1 1 0 0 1 9.3 4.7h5.4a1 1 0 0 1 .83.45l.94 1.4a1 1 0 0 0 .83.45h2.2A1.5 1.5 0 0 1 21 8.5v9A1.5 1.5 0 0 1 19.5 19h-15A1.5 1.5 0 0 1 3 17.5z"/><circle cx="12" cy="13" r="3.4"/></svg>',
|
|
1182
1182
|
video: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="6" width="12.5" height="12" rx="2.2"/><path d="M15.5 10.8l4.2-2.6a.6.6 0 0 1 .92.5v6.6a.6.6 0 0 1-.92.5l-4.2-2.6z"/></svg>',
|
|
1183
1183
|
paperclip: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M20 11.5l-7.6 7.6a4.6 4.6 0 0 1-6.5-6.5l8-8a3.2 3.2 0 0 1 4.5 4.5l-8 8a1.8 1.8 0 0 1-2.5-2.5l7.1-7.1"/></svg>',
|
|
@@ -1195,9 +1195,9 @@ const en = {
|
|
|
1195
1195
|
moon: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M20 13.4A8.2 8.2 0 1 1 10.6 4a6.6 6.6 0 0 0 9.4 9.4z"/></svg>',
|
|
1196
1196
|
auto: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><rect x="2.8" y="4.4" width="18.4" height="12.6" rx="2.2"/><path d="M8.6 20.2h6.8"/><path d="M12 4.4v12.6"/><path d="M12 7.2a3.6 3.6 0 0 1 0 7.2z" fill="currentColor" stroke="none"/></svg>'
|
|
1197
1197
|
}, ta = '<svg class="bc-brand" viewBox="0 0 254 60" fill="none" role="img" aria-label="sphoro BugCatch"><g fill="currentColor"><path transform="translate(0.00 40.00) scale(0.04000 -0.04000)" d="M276.00 -14.00Q179.00 -14.00 117.00 28.00Q55.00 70.00 42.00 148.00L158.00 178.00Q165.00 143.00 181.50 123.00Q198.00 103.00 222.50 94.50Q247.00 86.00 276.00 86.00Q320.00 86.00 341.00 101.50Q362.00 117.00 362.00 140.00Q362.00 163.00 342.00 175.50Q322.00 188.00 278.00 196.00L250.00 201.00Q198.00 211.00 155.00 228.50Q112.00 246.00 86.00 277.00Q60.00 308.00 60.00 357.00Q60.00 431.00 114.00 470.50Q168.00 510.00 256.00 510.00Q339.00 510.00 394.00 473.00Q449.00 436.00 466.00 376.00L349.00 340.00Q341.00 378.00 316.50 394.00Q292.00 410.00 256.00 410.00Q220.00 410.00 201.00 397.50Q182.00 385.00 182.00 363.00Q182.00 339.00 202.00 327.50Q222.00 316.00 256.00 310.00L284.00 305.00Q340.00 295.00 385.50 278.50Q431.00 262.00 457.50 231.50Q484.00 201.00 484.00 149.00Q484.00 71.00 427.50 28.50Q371.00 -14.00 276.00 -14.00Z"/><path transform="translate(19.56 40.00) scale(0.04000 -0.04000)" d="M70.00 -200.00V496.00H194.00V436.00H212.00Q229.00 465.00 265.00 487.50Q301.00 510.00 368.00 510.00Q428.00 510.00 479.00 480.50Q530.00 451.00 561.00 394.00Q592.00 337.00 592.00 256.00V240.00Q592.00 159.00 561.00 102.00Q530.00 45.00 479.00 15.50Q428.00 -14.00 368.00 -14.00Q323.00 -14.00 292.50 -3.50Q262.00 7.00 243.50 23.50Q225.00 40.00 214.00 57.00H196.00V-200.00ZM330.00 96.00Q389.00 96.00 427.50 133.50Q466.00 171.00 466.00 243.00V253.00Q466.00 325.00 427.00 362.50Q388.00 400.00 330.00 400.00Q272.00 400.00 233.00 362.50Q194.00 325.00 194.00 253.00V243.00Q194.00 171.00 233.00 133.50Q272.00 96.00 330.00 96.00Z"/><path transform="translate(43.68 40.00) scale(0.04000 -0.04000)" d="M70.00 0.00V700.00H196.00V435.00H214.00Q222.00 451.00 239.00 467.00Q256.00 483.00 284.50 493.50Q313.00 504.00 357.00 504.00Q415.00 504.00 458.50 477.50Q502.00 451.00 526.00 404.50Q550.00 358.00 550.00 296.00V0.00H424.00V286.00Q424.00 342.00 396.50 370.00Q369.00 398.00 318.00 398.00Q260.00 398.00 228.00 359.50Q196.00 321.00 196.00 252.00V0.00Z"/><path transform="translate(66.92 40.00) scale(0.04000 -0.04000)" d="M306.00 -14.00Q232.00 -14.00 173.00 16.00Q114.00 46.00 80.00 103.00Q46.00 160.00 46.00 240.00V256.00Q46.00 336.00 80.00 393.00Q114.00 450.00 173.00 480.00Q232.00 510.00 306.00 510.00Q380.00 510.00 439.00 480.00Q498.00 450.00 532.00 393.00Q566.00 336.00 566.00 256.00V240.00Q566.00 160.00 532.00 103.00Q498.00 46.00 439.00 16.00Q380.00 -14.00 306.00 -14.00ZM306.00 98.00Q364.00 98.00 402.00 135.50Q440.00 173.00 440.00 243.00V253.00Q440.00 323.00 402.50 360.50Q365.00 398.00 306.00 398.00Q248.00 398.00 210.00 360.50Q172.00 323.00 172.00 253.00V243.00Q172.00 173.00 210.00 135.50Q248.00 98.00 306.00 98.00Z"/><path transform="translate(90.00 40.00) scale(0.04000 -0.04000)" d="M70.00 0.00V496.00H194.00V440.00H212.00Q223.00 470.00 248.50 484.00Q274.00 498.00 308.00 498.00H368.00V386.00H306.00Q258.00 386.00 227.00 360.50Q196.00 335.00 196.00 282.00V0.00Z"/><path transform="translate(104.44 40.00) scale(0.04000 -0.04000)" d="M306.00 -14.00Q232.00 -14.00 173.00 16.00Q114.00 46.00 80.00 103.00Q46.00 160.00 46.00 240.00V256.00Q46.00 336.00 80.00 393.00Q114.00 450.00 173.00 480.00Q232.00 510.00 306.00 510.00Q380.00 510.00 439.00 480.00Q498.00 450.00 532.00 393.00Q566.00 336.00 566.00 256.00V240.00Q566.00 160.00 532.00 103.00Q498.00 46.00 439.00 16.00Q380.00 -14.00 306.00 -14.00ZM306.00 98.00Q364.00 98.00 402.00 135.50Q440.00 173.00 440.00 243.00V253.00Q440.00 323.00 402.50 360.50Q365.00 398.00 306.00 398.00Q248.00 398.00 210.00 360.50Q172.00 323.00 172.00 253.00V243.00Q172.00 173.00 210.00 135.50Q248.00 98.00 306.00 98.00Z"/></g><rect x="139.52" y="16" width="1.6" height="26" rx="0.8" fill="var(--bc-brand-mark, #5647ee)" opacity="0.4"/><g fill="var(--bc-brand-mark, #5647ee)"><path transform="translate(154.52 35.00) scale(0.01400 -0.01400)" d="M46.35 0.00V105.85H139.75V594.15H46.35V700.00H404.08Q467.38 700.00 514.79 678.41Q562.20 656.83 588.70 617.33Q615.20 577.83 615.20 523.35V513.70Q615.20 465.52 597.03 434.76Q578.85 404.00 553.91 387.24Q528.98 370.48 506.28 363.30V346.35Q528.98 340.35 555.24 323.50Q581.50 306.65 600.00 275.48Q618.50 244.30 618.50 194.48V184.48Q618.50 126.65 591.41 85.24Q564.33 43.83 516.83 21.91Q469.33 0.00 406.85 0.00ZM259.85 109.15H392.60Q441.20 109.15 469.80 132.60Q498.40 156.05 498.40 198.55V208.20Q498.40 250.70 470.21 274.15Q442.02 297.60 392.60 297.60H259.85ZM259.85 406.75H391.65Q437.55 406.75 466.32 430.11Q495.10 453.48 495.10 493.80V503.80Q495.10 544.95 466.74 567.90Q438.37 590.85 391.65 590.85H259.85Z"/><path transform="translate(167.00 35.00) scale(0.01400 -0.01400)" d="M335.30 -14.00Q251.22 -14.00 190.60 16.63Q129.97 47.25 97.56 104.96Q65.15 162.68 65.15 243.03V700.00H185.25V239.73Q185.25 170.48 224.03 131.99Q262.80 93.50 335.30 93.50Q407.80 93.50 446.57 131.99Q485.35 170.48 485.35 239.73V700.00H605.45V243.03Q605.45 162.68 573.13 104.96Q540.80 47.25 480.09 16.63Q419.38 -14.00 335.30 -14.00Z"/><path transform="translate(179.60 35.00) scale(0.01400 -0.01400)" d="M311.85 -14.00Q238.45 -14.00 179.69 18.50Q120.92 51.00 86.69 113.67Q52.45 176.35 52.45 266.87V433.13Q52.45 569.00 128.01 641.50Q203.57 714.00 332.35 714.00Q460.13 714.00 529.23 645.59Q598.33 577.17 598.33 460.87V456.70H479.87V464.52Q479.87 504.67 463.76 536.86Q447.65 569.05 414.99 587.77Q382.32 606.50 332.35 606.50Q257.63 606.50 215.09 560.70Q172.55 514.90 172.55 435.13V264.87Q172.55 185.93 215.09 138.89Q257.63 91.85 334.00 91.85Q410.02 91.85 445.12 132.83Q480.22 173.80 480.22 237.92V249.67H302.85V351.88H598.33V0.00H487.52V69.10H470.57Q462.70 50.87 446.06 31.44Q429.42 12.00 397.64 -1.00Q365.85 -14.00 311.85 -14.00Z"/><path transform="translate(192.05 35.00) scale(0.01400 -0.01400)" d="M332.35 -14.00Q203.57 -14.00 128.01 58.50Q52.45 131.00 52.45 266.87V433.13Q52.45 569.00 128.01 641.50Q203.57 714.00 332.35 714.00Q460.13 714.00 529.58 643.85Q599.03 573.70 599.03 451.57V445.75H480.57V455.22Q480.57 521.42 444.15 563.96Q407.72 606.50 332.35 606.50Q257.63 606.50 215.09 560.70Q172.55 514.90 172.55 435.13V264.87Q172.55 185.93 215.09 139.71Q257.63 93.50 332.35 93.50Q407.72 93.50 444.15 136.45Q480.57 179.40 480.57 244.78V262.25H599.03V248.43Q599.03 126.30 529.58 56.15Q460.13 -14.00 332.35 -14.00Z"/><path transform="translate(204.25 35.00) scale(0.01400 -0.01400)" d="M19.75 0.00 211.62 700.00H421.33L613.20 0.00H489.27L447.42 159.60H185.53L143.68 0.00ZM214.25 270.40H418.70L324.95 624.87H308.00Z"/><path transform="translate(216.31 35.00) scale(0.01400 -0.01400)" d="M233.95 0.00V590.85H24.70V700.00H563.30V590.85H354.05V0.00Z"/><path transform="translate(227.75 35.00) scale(0.01400 -0.01400)" d="M332.35 -14.00Q203.57 -14.00 128.01 58.50Q52.45 131.00 52.45 266.87V433.13Q52.45 569.00 128.01 641.50Q203.57 714.00 332.35 714.00Q460.13 714.00 529.58 643.85Q599.03 573.70 599.03 451.57V445.75H480.57V455.22Q480.57 521.42 444.15 563.96Q407.72 606.50 332.35 606.50Q257.63 606.50 215.09 560.70Q172.55 514.90 172.55 435.13V264.87Q172.55 185.93 215.09 139.71Q257.63 93.50 332.35 93.50Q407.72 93.50 444.15 136.45Q480.57 179.40 480.57 244.78V262.25H599.03V248.43Q599.03 126.30 529.58 56.15Q460.13 -14.00 332.35 -14.00Z"/><path transform="translate(239.95 35.00) scale(0.01400 -0.01400)" d="M69.50 0.00V700.00H189.60V405.58H466.40V700.00H586.50V0.00H466.40V296.42H189.60V0.00Z"/></g></svg>', En = [
|
|
1198
|
-
{ value: "light", label: "Light", icon:
|
|
1199
|
-
{ value: "dark", label: "Dark", icon:
|
|
1200
|
-
{ value: "auto", label: "System default", icon:
|
|
1198
|
+
{ value: "light", label: "Light", icon: j.sun },
|
|
1199
|
+
{ value: "dark", label: "Dark", icon: j.moon },
|
|
1200
|
+
{ value: "auto", label: "System default", icon: j.auto }
|
|
1201
1201
|
], $n = "bugcatch:theme";
|
|
1202
1202
|
function na() {
|
|
1203
1203
|
try {
|
|
@@ -1747,6 +1747,15 @@ button.primary .spinner { border-color: rgba(255,255,255,.4); border-top-color:
|
|
|
1747
1747
|
.att .file .nm { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
1748
1748
|
.att .file .sz { flex: none; color: var(--bc-faint); font-size: 11px; }
|
|
1749
1749
|
|
|
1750
|
+
/* Quick answers under the confirm question — only on the latest message. */
|
|
1751
|
+
.msg-row .quick { display: none; gap: 6px; flex-wrap: wrap; margin-top: 6px; }
|
|
1752
|
+
.msg-row:last-child .quick { display: flex; }
|
|
1753
|
+
.quick button {
|
|
1754
|
+
font: inherit; font-size: 13px; padding: 6px 12px; border-radius: 999px; cursor: pointer;
|
|
1755
|
+
border: 1px solid var(--bc-accent); background: transparent; color: var(--bc-accent);
|
|
1756
|
+
}
|
|
1757
|
+
.quick button:hover { background: color-mix(in srgb, var(--bc-accent) 12%, transparent); }
|
|
1758
|
+
|
|
1750
1759
|
/* ---------- the composer ---------- */
|
|
1751
1760
|
.composer {
|
|
1752
1761
|
position: sticky; bottom: 0; margin-top: auto;
|
|
@@ -1993,31 +2002,31 @@ function ra(t) {
|
|
|
1993
2002
|
const r = en[t.config.widgetPosition] ? t.config.widgetPosition : "bottom-right", s = document.createElement("div");
|
|
1994
2003
|
s.className = `dock ${r.includes("right") ? "at-right" : "at-left"}` + (r.startsWith("top") ? " at-top" : ""), s.style.cssText = en[r];
|
|
1995
2004
|
const l = document.createElement("div");
|
|
1996
|
-
l.className = "themer", l.setAttribute("role", "group"), l.setAttribute("aria-label", "Report widget theme"), l.innerHTML = En.map((
|
|
1997
|
-
const p =
|
|
2005
|
+
l.className = "themer", l.setAttribute("role", "group"), l.setAttribute("aria-label", "Report widget theme"), l.innerHTML = En.map((y) => `<button type="button" data-theme="${y.value}" title="${y.label}" aria-label="${y.label}" aria-pressed="${y.value === n}">${y.icon}</button>`).join(""), l.addEventListener("click", (y) => {
|
|
2006
|
+
const p = y.target.closest("button[data-theme]");
|
|
1998
2007
|
!p || p.dataset.theme === n || (n = p.dataset.theme, e.className = nn(n), oa(n), l.querySelectorAll("button").forEach((b) => {
|
|
1999
2008
|
b.setAttribute("aria-pressed", String(b.dataset.theme === n));
|
|
2000
2009
|
}));
|
|
2001
2010
|
});
|
|
2002
2011
|
const u = document.createElement("button");
|
|
2003
|
-
u.className = "launcher", u.type = "button", u.innerHTML = `${
|
|
2004
|
-
let
|
|
2012
|
+
u.className = "launcher", u.type = "button", u.innerHTML = `${j.bug}<span>Report a bug</span>`, u.setAttribute("aria-haspopup", "dialog"), u.setAttribute("aria-expanded", "false");
|
|
2013
|
+
let h = null;
|
|
2005
2014
|
return u.addEventListener("click", () => {
|
|
2006
|
-
if (
|
|
2007
|
-
|
|
2015
|
+
if (h) {
|
|
2016
|
+
h.close();
|
|
2008
2017
|
return;
|
|
2009
2018
|
}
|
|
2010
|
-
s.classList.add("over"), u.setAttribute("aria-expanded", "true"),
|
|
2019
|
+
s.classList.add("over"), u.setAttribute("aria-expanded", "true"), h = sa({
|
|
2011
2020
|
root: o,
|
|
2012
2021
|
host: e,
|
|
2013
2022
|
dock: s,
|
|
2014
2023
|
client: t,
|
|
2015
2024
|
onClose: () => {
|
|
2016
|
-
|
|
2025
|
+
h = null, s.classList.remove("over"), u.setAttribute("aria-expanded", "false");
|
|
2017
2026
|
}
|
|
2018
2027
|
});
|
|
2019
2028
|
}), s.append(l, u), o.appendChild(s), document.body.appendChild(e), () => {
|
|
2020
|
-
|
|
2029
|
+
h == null || h.destroy(), e.remove();
|
|
2021
2030
|
};
|
|
2022
2031
|
}
|
|
2023
2032
|
function ia(t) {
|
|
@@ -2027,19 +2036,19 @@ function nn(t) {
|
|
|
2027
2036
|
return t === "dark" ? "bc-dark" : t === "light" ? "bc-light" : "bc-auto";
|
|
2028
2037
|
}
|
|
2029
2038
|
function sa({ root: t, host: e, dock: n, client: o, onClose: i }) {
|
|
2030
|
-
var
|
|
2031
|
-
const r = o.config, s = r.attachments !== !1, l = s && co(), u = s && so(),
|
|
2032
|
-
let
|
|
2033
|
-
const
|
|
2034
|
-
|
|
2039
|
+
var qt, Dt, Nt, Ut, Vt, Kt;
|
|
2040
|
+
const r = o.config, s = r.attachments !== !1, l = s && co(), u = s && so(), h = [];
|
|
2041
|
+
let y = "MEDIUM", p = null, b = !1;
|
|
2042
|
+
const f = document.createElement("div");
|
|
2043
|
+
f.className = `scrim ${n.classList.contains("at-left") ? "at-left" : "at-right"} ${n.classList.contains("at-top") ? "at-top" : "at-bottom"}`, f.style.setProperty("--bc-dock-h", `${Math.round(n.getBoundingClientRect().height)}px`), f.innerHTML = `
|
|
2035
2044
|
<div class="panel" role="dialog" aria-modal="true" aria-labelledby="bc-h">
|
|
2036
2045
|
<div class="head">
|
|
2037
|
-
<div class="mark">${
|
|
2046
|
+
<div class="mark">${j.bug}</div>
|
|
2038
2047
|
<div class="titles">
|
|
2039
2048
|
<h2 id="bc-h">Report a bug</h2>
|
|
2040
2049
|
<p>We'll attach what the page was doing, so you don't have to explain it.</p>
|
|
2041
2050
|
</div>
|
|
2042
|
-
<button class="icon-btn" type="button" data-act="close" aria-label="Close">${
|
|
2051
|
+
<button class="icon-btn" type="button" data-act="close" aria-label="Close">${j.close}</button>
|
|
2043
2052
|
</div>
|
|
2044
2053
|
<div class="body">
|
|
2045
2054
|
<div class="slot"></div>
|
|
@@ -2063,7 +2072,7 @@ function sa({ root: t, host: e, dock: n, client: o, onClose: i }) {
|
|
|
2063
2072
|
<label id="bc-prio-l">Severity</label>
|
|
2064
2073
|
<div class="seg" role="group" aria-labelledby="bc-prio-l">
|
|
2065
2074
|
${tn.map((a) => `
|
|
2066
|
-
<button type="button" data-prio="${a.value}" aria-pressed="${a.value ===
|
|
2075
|
+
<button type="button" data-prio="${a.value}" aria-pressed="${a.value === y}">${a.label}</button>
|
|
2067
2076
|
`).join("")}
|
|
2068
2077
|
</div>
|
|
2069
2078
|
</div>
|
|
@@ -2071,9 +2080,9 @@ function sa({ root: t, host: e, dock: n, client: o, onClose: i }) {
|
|
|
2071
2080
|
<div class="field">
|
|
2072
2081
|
<label>Attach <span style="font-weight:450;color:var(--bc-faint)">(optional)</span></label>
|
|
2073
2082
|
<div class="tools">
|
|
2074
|
-
${l ? `<button class="tool" type="button" data-act="shot">${
|
|
2075
|
-
${u ? `<button class="tool" type="button" data-act="rec">${
|
|
2076
|
-
<button class="tool" type="button" data-act="file">${
|
|
2083
|
+
${l ? `<button class="tool" type="button" data-act="shot">${j.camera}Screenshot</button>` : ""}
|
|
2084
|
+
${u ? `<button class="tool" type="button" data-act="rec">${j.video}Record</button>` : ""}
|
|
2085
|
+
<button class="tool" type="button" data-act="file">${j.paperclip}File</button>
|
|
2077
2086
|
</div>
|
|
2078
2087
|
<div class="thumbs"></div>
|
|
2079
2088
|
<input type="file" accept="${et.join(",")}" multiple hidden />
|
|
@@ -2094,39 +2103,39 @@ function sa({ root: t, host: e, dock: n, client: o, onClose: i }) {
|
|
|
2094
2103
|
<button class="primary" type="button" data-act="send">Send report</button>
|
|
2095
2104
|
</div>
|
|
2096
2105
|
</div>`;
|
|
2097
|
-
const k = (a) =>
|
|
2098
|
-
ee.setAttribute("role", "status"), ee.className = "note",
|
|
2099
|
-
const ze = bo(r, (
|
|
2100
|
-
let be = r.drafts === !1, Ue = !1,
|
|
2106
|
+
const k = (a) => f.querySelector(a), A = k("#bc-title"), oe = k(".slot"), S = k(".thumbs"), E = f.querySelector("input[type=file]"), T = k('[data-act="send"]'), L = k('[data-act="call"]'), Y = k(".note"), q = k(".compose"), Q = k(".whoami"), D = k(".refs"), $ = k(".known"), ae = k('[data-act="history"]'), ee = document.createElement("div");
|
|
2107
|
+
ee.setAttribute("role", "status"), ee.className = "note", q.prepend(ee);
|
|
2108
|
+
const ze = bo(r, (qt = he(r.projectId)) == null ? void 0 : qt.email);
|
|
2109
|
+
let be = r.drafts === !1, Ue = !1, ye = Promise.resolve(), N;
|
|
2101
2110
|
function te() {
|
|
2102
|
-
if (clearTimeout(
|
|
2103
|
-
const a = A.value || k("#bc-desc").value ||
|
|
2111
|
+
if (clearTimeout(N), !be || Ue || r.drafts === !1) return ye;
|
|
2112
|
+
const a = A.value || k("#bc-desc").value || h.length ? {
|
|
2104
2113
|
title: A.value,
|
|
2105
2114
|
description: k("#bc-desc").value,
|
|
2106
|
-
priority:
|
|
2107
|
-
items:
|
|
2115
|
+
priority: y,
|
|
2116
|
+
items: h.map(({ blob: c, mime: d, kind: g }) => ({ blob: c, mime: d, kind: g }))
|
|
2108
2117
|
} : null;
|
|
2109
|
-
return
|
|
2118
|
+
return ye = ye.catch(() => {
|
|
2110
2119
|
}).then(() => nt(ze, a)).then(() => {
|
|
2111
2120
|
ee.textContent = a ? "Draft saved on this device" : "";
|
|
2112
2121
|
}).catch(() => {
|
|
2113
2122
|
ee.textContent = "Draft could not be saved. Keep this tab open.";
|
|
2114
|
-
}),
|
|
2123
|
+
}), ye;
|
|
2115
2124
|
}
|
|
2116
2125
|
function $e() {
|
|
2117
|
-
clearTimeout(
|
|
2126
|
+
clearTimeout(N), N = setTimeout(te, 250);
|
|
2118
2127
|
}
|
|
2119
|
-
|
|
2128
|
+
q.addEventListener("input", $e), q.addEventListener("change", $e);
|
|
2120
2129
|
const Ve = () => {
|
|
2121
2130
|
te();
|
|
2122
2131
|
};
|
|
2123
2132
|
window.addEventListener("pagehide", Ve);
|
|
2124
2133
|
function Oe() {
|
|
2125
|
-
|
|
2134
|
+
h.filter((a) => a.status === "failed").forEach(Le);
|
|
2126
2135
|
}
|
|
2127
|
-
window.addEventListener("online", Oe), r.drafts !== !1 && (
|
|
2136
|
+
window.addEventListener("online", Oe), r.drafts !== !1 && (q.inert = !0, yo(ze).then((a) => {
|
|
2128
2137
|
Ie || !a || (ee.innerHTML = 'Unfinished report on this device. <button type="button" data-resume>Resume report</button> <button type="button" data-discard>Discard</button>', ee.querySelector("[data-resume]").onclick = () => {
|
|
2129
|
-
A.value = a.title || "", k("#bc-desc").value = a.description || "",
|
|
2138
|
+
A.value = a.title || "", k("#bc-desc").value = a.description || "", y = tn.some((c) => c.value === a.priority) ? a.priority : "MEDIUM", f.querySelectorAll("[data-prio]").forEach((c) => c.setAttribute("aria-pressed", String(c.dataset.prio === y)));
|
|
2130
2139
|
for (const c of (a.items || []).slice(0, r.maxAttachments ?? 5)) ve(c);
|
|
2131
2140
|
be = !0, te();
|
|
2132
2141
|
}, ee.querySelector("[data-discard]").onclick = () => {
|
|
@@ -2135,21 +2144,21 @@ function sa({ root: t, host: e, dock: n, client: o, onClose: i }) {
|
|
|
2135
2144
|
}).catch(() => {
|
|
2136
2145
|
ee.textContent = "Draft storage is unavailable. Keep this tab open.";
|
|
2137
2146
|
}).finally(() => {
|
|
2138
|
-
|
|
2147
|
+
q.inert = !1, ee.querySelector("[data-resume]") || (be = !0);
|
|
2139
2148
|
}));
|
|
2140
|
-
const
|
|
2149
|
+
const fe = document.activeElement, Te = document.documentElement.style, ct = Te.overflow;
|
|
2141
2150
|
Te.overflow = "hidden";
|
|
2142
|
-
let Ie = !1,
|
|
2151
|
+
let Ie = !1, we = null;
|
|
2143
2152
|
function He() {
|
|
2144
2153
|
var a;
|
|
2145
|
-
Ie || (te(), Ie = !0, clearTimeout(
|
|
2154
|
+
Ie || (te(), Ie = !0, clearTimeout(N), window.removeEventListener("pagehide", Ve), window.removeEventListener("online", Oe), p == null || p.cancel(), we == null || we(), h.forEach((c) => c.previewUrl && URL.revokeObjectURL(c.previewUrl)), Te.overflow = ct, document.removeEventListener("keydown", Me, !0), f.remove(), (a = t.querySelector(".recbar")) == null || a.remove(), n.hidden = !1, e.style.opacity = "", i == null || i());
|
|
2146
2155
|
}
|
|
2147
2156
|
function re() {
|
|
2148
2157
|
var a;
|
|
2149
2158
|
if (!Ie) {
|
|
2150
|
-
|
|
2159
|
+
f.classList.add("closing"), setTimeout(He, 160);
|
|
2151
2160
|
try {
|
|
2152
|
-
(a =
|
|
2161
|
+
(a = fe == null ? void 0 : fe.focus) == null || a.call(fe);
|
|
2153
2162
|
} catch {
|
|
2154
2163
|
}
|
|
2155
2164
|
}
|
|
@@ -2164,18 +2173,18 @@ function sa({ root: t, host: e, dock: n, client: o, onClose: i }) {
|
|
|
2164
2173
|
return;
|
|
2165
2174
|
}
|
|
2166
2175
|
if (a.key !== "Tab" || p) return;
|
|
2167
|
-
const c = [...
|
|
2176
|
+
const c = [...f.querySelectorAll(
|
|
2168
2177
|
"button:not(:disabled), input:not([hidden]), textarea, select, [href]"
|
|
2169
2178
|
)].filter((v) => v.offsetParent !== null || v === document.activeElement);
|
|
2170
2179
|
if (!c.length) return;
|
|
2171
|
-
const d = c[0],
|
|
2172
|
-
a.shiftKey && C === d ? (a.preventDefault(),
|
|
2180
|
+
const d = c[0], g = c[c.length - 1], C = f.getRootNode().activeElement;
|
|
2181
|
+
a.shiftKey && C === d ? (a.preventDefault(), g.focus()) : !a.shiftKey && C === g && (a.preventDefault(), d.focus());
|
|
2173
2182
|
}
|
|
2174
|
-
document.addEventListener("keydown", Me, !0),
|
|
2175
|
-
a.target ===
|
|
2176
|
-
}), k('[data-act="close"]').addEventListener("click", re), k('[data-act="cancel"]').addEventListener("click", re),
|
|
2183
|
+
document.addEventListener("keydown", Me, !0), f.addEventListener("click", (a) => {
|
|
2184
|
+
a.target === f && !b && re();
|
|
2185
|
+
}), k('[data-act="close"]').addEventListener("click", re), k('[data-act="cancel"]').addEventListener("click", re), f.querySelectorAll("[data-prio]").forEach((a) => {
|
|
2177
2186
|
a.addEventListener("click", () => {
|
|
2178
|
-
|
|
2187
|
+
y = a.dataset.prio, $e(), f.querySelectorAll("[data-prio]").forEach((c) => {
|
|
2179
2188
|
c.setAttribute("aria-pressed", String(c === a));
|
|
2180
2189
|
});
|
|
2181
2190
|
});
|
|
@@ -2184,32 +2193,32 @@ function sa({ root: t, host: e, dock: n, client: o, onClose: i }) {
|
|
|
2184
2193
|
oe.innerHTML = a ? `<div class="msg ${c}">${x(a)}</div>` : "";
|
|
2185
2194
|
}
|
|
2186
2195
|
function ce() {
|
|
2187
|
-
const a =
|
|
2188
|
-
T.disabled = b || a ||
|
|
2189
|
-
c.disabled = b ||
|
|
2196
|
+
const a = h.some((c) => c.status === "uploading");
|
|
2197
|
+
T.disabled = b || a || h.some((c) => c.status === "failed"), Y.textContent = a ? "Waiting for the upload to finish…" : h.some((c) => c.status === "failed") ? "Retry or remove failed attachments before sending." : "", f.querySelectorAll(".tool").forEach((c) => {
|
|
2198
|
+
c.disabled = b || h.length >= (r.maxAttachments ?? 5);
|
|
2190
2199
|
});
|
|
2191
2200
|
}
|
|
2192
2201
|
function Ke(a) {
|
|
2193
2202
|
var v;
|
|
2194
|
-
const c = a.el, d = a.kind === "VIDEO" ? "Video" : "Shot",
|
|
2203
|
+
const c = a.el, d = a.kind === "VIDEO" ? "Video" : "Shot", g = a.kind === "VIDEO" ? `<video src="${a.previewUrl}" muted playsinline preload="metadata"></video>` : `<img src="${a.previewUrl}" alt="" />`;
|
|
2195
2204
|
let C = "";
|
|
2196
|
-
a.status === "uploading" ? C = `<div class="veil"><div class="spinner"></div><div class="bar"><i style="width:${Math.round(a.progress * 100)}%"></i></div></div>` : a.status === "failed" && (C = `<div class="veil err"><button type="button" data-act="retry" aria-label="Retry upload">${
|
|
2197
|
-
${
|
|
2205
|
+
a.status === "uploading" ? C = `<div class="veil"><div class="spinner"></div><div class="bar"><i style="width:${Math.round(a.progress * 100)}%"></i></div></div>` : a.status === "failed" && (C = `<div class="veil err"><button type="button" data-act="retry" aria-label="Retry upload">${j.retry}</button>Failed</div>`), c.innerHTML = `
|
|
2206
|
+
${g}
|
|
2198
2207
|
<span class="kind">${d} · ${je(a.size)}</span>
|
|
2199
|
-
<button class="drop" type="button" data-act="drop" aria-label="Remove ${d.toLowerCase()}">${
|
|
2208
|
+
<button class="drop" type="button" data-act="drop" aria-label="Remove ${d.toLowerCase()}">${j.close}</button>
|
|
2200
2209
|
${C}`, c.querySelector('[data-act="drop"]').addEventListener("click", () => lt(a)), (v = c.querySelector('[data-act="retry"]')) == null || v.addEventListener("click", () => Le(a));
|
|
2201
2210
|
}
|
|
2202
2211
|
function lt(a) {
|
|
2203
|
-
const c =
|
|
2204
|
-
c >= 0 &&
|
|
2212
|
+
const c = h.indexOf(a);
|
|
2213
|
+
c >= 0 && h.splice(c, 1), a.previewUrl && URL.revokeObjectURL(a.previewUrl), a.el.remove(), te(), ce();
|
|
2205
2214
|
}
|
|
2206
2215
|
async function Le(a) {
|
|
2207
2216
|
a.status = "uploading", a.progress = 0, Ke(a), ce();
|
|
2208
2217
|
try {
|
|
2209
|
-
const { storageKey: c, mime: d } = await o.uploadAttachment(a.blob, a.mime, (
|
|
2210
|
-
a.progress =
|
|
2218
|
+
const { storageKey: c, mime: d } = await o.uploadAttachment(a.blob, a.mime, (g) => {
|
|
2219
|
+
a.progress = g;
|
|
2211
2220
|
const C = a.el.querySelector(".bar i");
|
|
2212
|
-
C && (C.style.width = `${Math.round(
|
|
2221
|
+
C && (C.style.width = `${Math.round(g * 100)}%`);
|
|
2213
2222
|
});
|
|
2214
2223
|
a.storageKey = c, a.mime = d, a.status = "ready";
|
|
2215
2224
|
} catch (c) {
|
|
@@ -2218,9 +2227,9 @@ function sa({ root: t, host: e, dock: n, client: o, onClose: i }) {
|
|
|
2218
2227
|
Ke(a), ce();
|
|
2219
2228
|
}
|
|
2220
2229
|
function ve({ blob: a, mime: c, kind: d }) {
|
|
2221
|
-
const
|
|
2222
|
-
if (a.size >
|
|
2223
|
-
z(`That file is ${je(a.size)} — the limit is ${je(
|
|
2230
|
+
const g = r.maxAttachmentBytes ?? 26214400;
|
|
2231
|
+
if (a.size > g) {
|
|
2232
|
+
z(`That file is ${je(a.size)} — the limit is ${je(g)}.`);
|
|
2224
2233
|
return;
|
|
2225
2234
|
}
|
|
2226
2235
|
const C = tt(c || a.type, et);
|
|
@@ -2239,7 +2248,7 @@ function sa({ root: t, host: e, dock: n, client: o, onClose: i }) {
|
|
|
2239
2248
|
storageKey: null,
|
|
2240
2249
|
el: document.createElement("div")
|
|
2241
2250
|
};
|
|
2242
|
-
v.el.className = "thumb",
|
|
2251
|
+
v.el.className = "thumb", h.push(v), S.appendChild(v.el), z(""), te(), Le(v);
|
|
2243
2252
|
}
|
|
2244
2253
|
async function dt(a) {
|
|
2245
2254
|
e.style.opacity = "0", e.style.pointerEvents = "none", await new Promise((c) => requestAnimationFrame(() => requestAnimationFrame(c)));
|
|
@@ -2249,15 +2258,15 @@ function sa({ root: t, host: e, dock: n, client: o, onClose: i }) {
|
|
|
2249
2258
|
e.style.opacity = "", e.style.pointerEvents = "";
|
|
2250
2259
|
}
|
|
2251
2260
|
}
|
|
2252
|
-
(
|
|
2261
|
+
(Dt = f.querySelector('[data-act="shot"]')) == null || Dt.addEventListener("click", async () => {
|
|
2253
2262
|
try {
|
|
2254
2263
|
const a = await dt(lo);
|
|
2255
2264
|
ve(a);
|
|
2256
2265
|
} catch (a) {
|
|
2257
2266
|
(a == null ? void 0 : a.name) !== "NotAllowedError" && z(`Screenshot failed: ${a.message}`);
|
|
2258
2267
|
}
|
|
2259
|
-
}), (
|
|
2260
|
-
const a = (r.maxAttachments ?? 5) -
|
|
2268
|
+
}), (Nt = f.querySelector('[data-act="file"]')) == null || Nt.addEventListener("click", () => E.click()), E == null || E.addEventListener("change", () => {
|
|
2269
|
+
const a = (r.maxAttachments ?? 5) - h.length;
|
|
2261
2270
|
[...E.files].slice(0, Math.max(a, 0)).forEach((c) => {
|
|
2262
2271
|
ve({
|
|
2263
2272
|
blob: c,
|
|
@@ -2265,7 +2274,7 @@ function sa({ root: t, host: e, dock: n, client: o, onClose: i }) {
|
|
|
2265
2274
|
kind: c.type.startsWith("video/") ? "VIDEO" : "SCREENSHOT"
|
|
2266
2275
|
});
|
|
2267
2276
|
}), E.value = "";
|
|
2268
|
-
}), (
|
|
2277
|
+
}), (Ut = f.querySelector('[data-act="rec"]')) == null || Ut.addEventListener("click", async () => {
|
|
2269
2278
|
const a = r.maxRecordingMs ?? 12e4;
|
|
2270
2279
|
let c;
|
|
2271
2280
|
try {
|
|
@@ -2282,7 +2291,7 @@ function sa({ root: t, host: e, dock: n, client: o, onClose: i }) {
|
|
|
2282
2291
|
(d == null ? void 0 : d.name) !== "NotAllowedError" && z(`Recording failed: ${d.message}`);
|
|
2283
2292
|
return;
|
|
2284
2293
|
}
|
|
2285
|
-
|
|
2294
|
+
f.style.display = "none", n.hidden = !0, c = document.createElement("div"), c.className = "recbar", c.innerHTML = `
|
|
2286
2295
|
<span class="dot"></span>
|
|
2287
2296
|
<span class="time">0:00</span>
|
|
2288
2297
|
<span class="hint">Recording — up to ${We(Math.round(a / 1e3))}</span>
|
|
@@ -2293,20 +2302,20 @@ function sa({ root: t, host: e, dock: n, client: o, onClose: i }) {
|
|
|
2293
2302
|
var d;
|
|
2294
2303
|
const c = p;
|
|
2295
2304
|
if (c) {
|
|
2296
|
-
if (p = null, (d = t.querySelector(".recbar")) == null || d.remove(),
|
|
2305
|
+
if (p = null, (d = t.querySelector(".recbar")) == null || d.remove(), f.style.display = "", n.hidden = !1, !a) {
|
|
2297
2306
|
c.cancel(), A.focus();
|
|
2298
2307
|
return;
|
|
2299
2308
|
}
|
|
2300
2309
|
try {
|
|
2301
|
-
const
|
|
2302
|
-
|
|
2303
|
-
} catch (
|
|
2304
|
-
z(`Recording failed: ${
|
|
2310
|
+
const g = await c.stop();
|
|
2311
|
+
g.blob.size ? ve(g) : z("That recording came back empty — nothing was captured.");
|
|
2312
|
+
} catch (g) {
|
|
2313
|
+
z(`Recording failed: ${g.message}`);
|
|
2305
2314
|
}
|
|
2306
2315
|
A.focus();
|
|
2307
2316
|
}
|
|
2308
2317
|
}
|
|
2309
|
-
let m = { policy: "off", fields: [] },
|
|
2318
|
+
let m = { policy: "off", fields: [] }, w = null, I = "", K = "", P = !1, xe = !1;
|
|
2310
2319
|
o.referenceFields().then((a) => {
|
|
2311
2320
|
m = a;
|
|
2312
2321
|
}).catch(() => {
|
|
@@ -2315,16 +2324,16 @@ function sa({ root: t, host: e, dock: n, client: o, onClose: i }) {
|
|
|
2315
2324
|
return m.policy === "off" || !m.fields.length ? [] : Jo(m.fields, [A.value, k("#bc-desc").value]);
|
|
2316
2325
|
}
|
|
2317
2326
|
function ke() {
|
|
2318
|
-
return !
|
|
2327
|
+
return !w || !I.trim() ? [] : [{ key: w, value: I.trim().slice(0, 120) }];
|
|
2319
2328
|
}
|
|
2320
|
-
function
|
|
2321
|
-
var
|
|
2322
|
-
if (!
|
|
2323
|
-
|
|
2329
|
+
function pe() {
|
|
2330
|
+
var g, C;
|
|
2331
|
+
if (!w) {
|
|
2332
|
+
D.hidden = !0, D.innerHTML = "";
|
|
2324
2333
|
return;
|
|
2325
2334
|
}
|
|
2326
|
-
const a = m.fields.find((v) => v.key ===
|
|
2327
|
-
|
|
2335
|
+
const a = m.fields.find((v) => v.key === w) || m.fields[0], c = m.policy !== "required";
|
|
2336
|
+
D.hidden = !1, D.innerHTML = `
|
|
2328
2337
|
<p class="why">${x(
|
|
2329
2338
|
c ? "One more thing, so we can find your record — this helps us answer faster." : "We need one of these to look this up."
|
|
2330
2339
|
)}</p>
|
|
@@ -2342,22 +2351,22 @@ function sa({ root: t, host: e, dock: n, client: o, onClose: i }) {
|
|
|
2342
2351
|
aria-label="${x(a.label)}" />
|
|
2343
2352
|
</div>
|
|
2344
2353
|
${a.hint ? `<p class="hint">${x(a.hint)}</p>` : ""}
|
|
2345
|
-
${
|
|
2354
|
+
${K ? `<p class="after err">${x(K)}</p>` : ""}
|
|
2346
2355
|
${c ? `<button type="button" class="link" data-act="ref-skip">I don't have this</button>` : ""}`;
|
|
2347
|
-
const d =
|
|
2356
|
+
const d = D.querySelector(".ref-value");
|
|
2348
2357
|
d.addEventListener("input", () => {
|
|
2349
|
-
I = d.value,
|
|
2358
|
+
I = d.value, K = "", xe = !1;
|
|
2350
2359
|
}), d.addEventListener("keydown", (v) => {
|
|
2351
2360
|
v.key === "Enter" && (v.preventDefault(), T.click());
|
|
2352
|
-
}), (
|
|
2353
|
-
var
|
|
2354
|
-
|
|
2355
|
-
}), (C =
|
|
2356
|
-
|
|
2361
|
+
}), (g = D.querySelector(".ref-kind")) == null || g.addEventListener("change", (v) => {
|
|
2362
|
+
var _;
|
|
2363
|
+
w = v.target.value, K = "", pe(), (_ = D.querySelector(".ref-value")) == null || _.focus();
|
|
2364
|
+
}), (C = D.querySelector('[data-act="ref-skip"]')) == null || C.addEventListener("click", () => {
|
|
2365
|
+
P = !0, w = null, I = "", K = "", xe = !1, pe(), z("");
|
|
2357
2366
|
}), d.focus();
|
|
2358
2367
|
}
|
|
2359
2368
|
function jn() {
|
|
2360
|
-
return m.policy === "off" || !m.fields.length || Pe().length || ke().length ? !1 : !
|
|
2369
|
+
return m.policy === "off" || !m.fields.length || Pe().length || ke().length ? !1 : !P || m.policy === "required";
|
|
2361
2370
|
}
|
|
2362
2371
|
T.addEventListener("click", async () => {
|
|
2363
2372
|
const a = A.value;
|
|
@@ -2366,13 +2375,13 @@ function sa({ root: t, host: e, dock: n, client: o, onClose: i }) {
|
|
|
2366
2375
|
return;
|
|
2367
2376
|
}
|
|
2368
2377
|
if (jn()) {
|
|
2369
|
-
|
|
2378
|
+
w = w || m.fields[0].key, pe(), z("");
|
|
2370
2379
|
return;
|
|
2371
2380
|
}
|
|
2372
|
-
if (
|
|
2373
|
-
const d = m.fields.find((
|
|
2381
|
+
if (w && I.trim()) {
|
|
2382
|
+
const d = m.fields.find((g) => g.key === w);
|
|
2374
2383
|
if (!xe && d && !Go(d, I)) {
|
|
2375
|
-
|
|
2384
|
+
K = `That does not look like a ${d.label.toLowerCase()}. Press Send again to use it anyway.`, xe = !0, pe();
|
|
2376
2385
|
return;
|
|
2377
2386
|
}
|
|
2378
2387
|
}
|
|
@@ -2383,38 +2392,38 @@ function sa({ root: t, host: e, dock: n, client: o, onClose: i }) {
|
|
|
2383
2392
|
const d = await o.report({
|
|
2384
2393
|
title: a,
|
|
2385
2394
|
description: k("#bc-desc").value,
|
|
2386
|
-
priority:
|
|
2395
|
+
priority: y,
|
|
2387
2396
|
references: ke(),
|
|
2388
|
-
attachments:
|
|
2397
|
+
attachments: h.filter((g) => g.status === "ready").map((g) => ({ type: g.kind, storageKey: g.storageKey, mime: g.mime }))
|
|
2389
2398
|
});
|
|
2390
2399
|
if (d != null && d.cancelled) {
|
|
2391
2400
|
b = !1, T.innerHTML = c, ce();
|
|
2392
2401
|
return;
|
|
2393
2402
|
}
|
|
2394
|
-
Ue = !0, clearTimeout(
|
|
2395
|
-
}),
|
|
2403
|
+
Ue = !0, clearTimeout(N), await ye, r.drafts !== !1 && await nt(ze, null).catch(() => {
|
|
2404
|
+
}), jt(d);
|
|
2396
2405
|
} catch (d) {
|
|
2397
2406
|
b = !1, T.innerHTML = c, z(d.message.replace("[BugCatch] ", "")), ce(), X.mode !== "off" && ft().catch(() => {
|
|
2398
2407
|
});
|
|
2399
2408
|
}
|
|
2400
|
-
}), (
|
|
2409
|
+
}), (Vt = f.querySelector('[data-act="history"]')) == null || Vt.addEventListener("click", zt);
|
|
2401
2410
|
let Ae = [], _e = "", ut = null, qe = null;
|
|
2402
|
-
function
|
|
2411
|
+
function Lt() {
|
|
2403
2412
|
r.knownIssues !== !1 && o.knownIssues().then((a) => {
|
|
2404
2413
|
Ae = a, De();
|
|
2405
2414
|
}).catch(() => {
|
|
2406
2415
|
});
|
|
2407
2416
|
}
|
|
2408
|
-
let
|
|
2417
|
+
let Bt = null;
|
|
2409
2418
|
function zn(a) {
|
|
2410
2419
|
if (r.knownIssues === !1) return;
|
|
2411
|
-
clearTimeout(
|
|
2420
|
+
clearTimeout(Bt), qe == null || qe.abort();
|
|
2412
2421
|
const c = (a || "").trim();
|
|
2413
2422
|
if (c.length < 3) {
|
|
2414
|
-
|
|
2423
|
+
Lt();
|
|
2415
2424
|
return;
|
|
2416
2425
|
}
|
|
2417
|
-
|
|
2426
|
+
Bt = setTimeout(() => {
|
|
2418
2427
|
qe = new AbortController(), o.matchKnownIssues(c, { signal: qe.signal }).then((d) => {
|
|
2419
2428
|
d.length && (Ae = d, De());
|
|
2420
2429
|
}).catch(() => {
|
|
@@ -2451,56 +2460,56 @@ function sa({ root: t, host: e, dock: n, client: o, onClose: i }) {
|
|
|
2451
2460
|
return `${c} · reported ${at(a.since)}${d}`;
|
|
2452
2461
|
}
|
|
2453
2462
|
$.addEventListener("click", async (a) => {
|
|
2454
|
-
var v,
|
|
2463
|
+
var v, _, O, F, G;
|
|
2455
2464
|
const c = a.target.closest("[data-join]"), d = a.target.closest("[data-join-confirm]");
|
|
2456
2465
|
if (!c && !d) return;
|
|
2457
|
-
const
|
|
2466
|
+
const g = (d || c).getAttribute(d ? "data-join-confirm" : "data-join");
|
|
2458
2467
|
_e = "";
|
|
2459
|
-
const C = ((
|
|
2468
|
+
const C = ((_ = (v = $.querySelector(".join-email")) == null ? void 0 : v.value) == null ? void 0 : _.trim()) || ((O = o.signedInAs()) == null ? void 0 : O.email) || ((F = o.config.user) == null ? void 0 : F.email);
|
|
2460
2469
|
if (!C) {
|
|
2461
|
-
ut =
|
|
2470
|
+
ut = g, De(), (G = $.querySelector(".join-email")) == null || G.focus();
|
|
2462
2471
|
return;
|
|
2463
2472
|
}
|
|
2464
2473
|
try {
|
|
2465
|
-
const de = await o.meToo(
|
|
2466
|
-
ut = null, Ae = Ae.map((
|
|
2474
|
+
const de = await o.meToo(g, { email: C });
|
|
2475
|
+
ut = null, Ae = Ae.map((U) => U.id === g ? { ...U, joined: !0, affectedCount: de.affectedCount ?? U.affectedCount } : U), De();
|
|
2467
2476
|
} catch (de) {
|
|
2468
2477
|
_e = de.message.replace("[BugCatch] ", ""), De();
|
|
2469
2478
|
}
|
|
2470
|
-
}),
|
|
2471
|
-
let
|
|
2472
|
-
function
|
|
2479
|
+
}), Lt(), A.addEventListener("input", () => zn(A.value));
|
|
2480
|
+
let At = !1;
|
|
2481
|
+
function Rt() {
|
|
2473
2482
|
o.callKind().then((a) => {
|
|
2474
|
-
a && (
|
|
2483
|
+
a && (At = !0, L.hidden = pt());
|
|
2475
2484
|
}).catch(() => {
|
|
2476
2485
|
});
|
|
2477
2486
|
}
|
|
2478
|
-
|
|
2479
|
-
let X = { mode: o.lastLoginMode || "off", signedIn: null }, Z = "idle", Re = ((
|
|
2487
|
+
Rt();
|
|
2488
|
+
let X = { mode: o.lastLoginMode || "off", signedIn: null }, Z = "idle", Re = ((Kt = o.config.user) == null ? void 0 : Kt.email) || "", Qe = "", J = !1, le = "";
|
|
2480
2489
|
const pt = () => X.mode === "required" && !X.signedIn;
|
|
2481
2490
|
function Hn() {
|
|
2482
2491
|
const a = pt();
|
|
2483
|
-
|
|
2492
|
+
q.hidden = a, T.hidden = a, ae && (ae.hidden = a), a ? L.hidden = !0 : At && (L.hidden = !1);
|
|
2484
2493
|
}
|
|
2485
2494
|
function qn() {
|
|
2486
2495
|
var c;
|
|
2487
2496
|
if (X.mode === "off") {
|
|
2488
|
-
|
|
2497
|
+
Q.hidden = !0, Q.innerHTML = "";
|
|
2489
2498
|
return;
|
|
2490
2499
|
}
|
|
2491
|
-
|
|
2500
|
+
Q.hidden = !1, Q.classList.toggle("asking", Z !== "idle");
|
|
2492
2501
|
const a = le ? `<div class="after err">${x(le)}</div>` : "";
|
|
2493
2502
|
if (Z === "idle") {
|
|
2494
2503
|
if (X.signedIn) {
|
|
2495
|
-
|
|
2504
|
+
Q.innerHTML = `<span class="who">Signed in as <strong>${x(X.signedIn.email)}</strong></span><button type="button" class="link" data-act="signout">Sign out</button>`;
|
|
2496
2505
|
return;
|
|
2497
2506
|
}
|
|
2498
2507
|
const d = (c = o.config.user) == null ? void 0 : c.email;
|
|
2499
|
-
|
|
2508
|
+
Q.innerHTML = `<span class="who">${X.mode === "required" ? "Sign in to report a bug here." : d ? `Reporting as <strong>${x(d)}</strong>.` : "Reporting anonymously — sign in and we can tell you what happens next."}</span><button type="button" class="link" data-act="signin">Sign in</button>`;
|
|
2500
2509
|
return;
|
|
2501
2510
|
}
|
|
2502
2511
|
if (Z === "email") {
|
|
2503
|
-
|
|
2512
|
+
Q.innerHTML = `
|
|
2504
2513
|
<p class="why">Sign in with any email address — we'll send you a code.
|
|
2505
2514
|
It's how you hear back about this report${X.mode === "required" ? ", and this project asks for it" : ""}.</p>
|
|
2506
2515
|
<div class="row">
|
|
@@ -2515,7 +2524,7 @@ function sa({ root: t, host: e, dock: n, client: o, onClose: i }) {
|
|
|
2515
2524
|
${X.mode === "optional" ? '<div class="after"><button type="button" class="link" data-act="skip">Not now</button></div>' : ""}`;
|
|
2516
2525
|
return;
|
|
2517
2526
|
}
|
|
2518
|
-
|
|
2527
|
+
Q.innerHTML = `
|
|
2519
2528
|
<p class="why">We sent a code to <strong>${x(Re)}</strong>. It expires in ten minutes.</p>
|
|
2520
2529
|
<div class="row">
|
|
2521
2530
|
<input type="text" class="code" data-fld="code" value="${x(Qe)}"
|
|
@@ -2534,14 +2543,14 @@ function sa({ root: t, host: e, dock: n, client: o, onClose: i }) {
|
|
|
2534
2543
|
function ie({ focus: a = !1 } = {}) {
|
|
2535
2544
|
var d;
|
|
2536
2545
|
if (qn(), Hn(), !a || J) return;
|
|
2537
|
-
const c =
|
|
2546
|
+
const c = Q.querySelector("[data-fld]");
|
|
2538
2547
|
c && (c.focus(), (d = c.setSelectionRange) == null || d.call(c, c.value.length, c.value.length));
|
|
2539
2548
|
}
|
|
2540
|
-
|
|
2549
|
+
Q.addEventListener("input", (a) => {
|
|
2541
2550
|
const c = a.target.closest("[data-fld]");
|
|
2542
2551
|
c && (c.dataset.fld === "email" ? Re = c.value : Qe = c.value);
|
|
2543
|
-
}),
|
|
2544
|
-
a.key !== "Enter" || !a.target.closest("[data-fld]") || (a.preventDefault(), Z === "email" ? ht() :
|
|
2552
|
+
}), Q.addEventListener("keydown", (a) => {
|
|
2553
|
+
a.key !== "Enter" || !a.target.closest("[data-fld]") || (a.preventDefault(), Z === "email" ? ht() : Qt());
|
|
2545
2554
|
});
|
|
2546
2555
|
async function ht({ resent: a = !1 } = {}) {
|
|
2547
2556
|
const c = Re.trim();
|
|
@@ -2558,7 +2567,7 @@ function sa({ root: t, host: e, dock: n, client: o, onClose: i }) {
|
|
|
2558
2567
|
J = !1, ie({ focus: !0 });
|
|
2559
2568
|
}
|
|
2560
2569
|
}
|
|
2561
|
-
async function
|
|
2570
|
+
async function Qt() {
|
|
2562
2571
|
const a = Qe.trim();
|
|
2563
2572
|
if (!a) {
|
|
2564
2573
|
le = "Enter the code we emailed you.", ie({ focus: !0 });
|
|
@@ -2567,14 +2576,14 @@ function sa({ root: t, host: e, dock: n, client: o, onClose: i }) {
|
|
|
2567
2576
|
J = !0, le = "", ie();
|
|
2568
2577
|
try {
|
|
2569
2578
|
const c = await o.confirmSignIn(Re.trim(), a);
|
|
2570
|
-
X.signedIn = c, Z = "idle", Qe = "", z(""),
|
|
2579
|
+
X.signedIn = c, Z = "idle", Qe = "", z(""), Rt();
|
|
2571
2580
|
} catch (c) {
|
|
2572
2581
|
le = c.message;
|
|
2573
2582
|
} finally {
|
|
2574
2583
|
J = !1, ie({ focus: Z !== "idle" });
|
|
2575
2584
|
}
|
|
2576
2585
|
}
|
|
2577
|
-
|
|
2586
|
+
Q.addEventListener("click", async (a) => {
|
|
2578
2587
|
const c = a.target.closest("button[data-act]");
|
|
2579
2588
|
if (!c) return;
|
|
2580
2589
|
const d = c.dataset.act;
|
|
@@ -2599,7 +2608,7 @@ function sa({ root: t, host: e, dock: n, client: o, onClose: i }) {
|
|
|
2599
2608
|
return;
|
|
2600
2609
|
}
|
|
2601
2610
|
if (d === "confirm") {
|
|
2602
|
-
|
|
2611
|
+
Qt();
|
|
2603
2612
|
return;
|
|
2604
2613
|
}
|
|
2605
2614
|
if (d === "signout") {
|
|
@@ -2622,12 +2631,12 @@ function sa({ root: t, host: e, dock: n, client: o, onClose: i }) {
|
|
|
2622
2631
|
const a = await o.startCall();
|
|
2623
2632
|
Dn(a);
|
|
2624
2633
|
} catch (a) {
|
|
2625
|
-
b = !1, L.disabled = !1, L.textContent = "Talk to the team", ce(), a.filed ?
|
|
2634
|
+
b = !1, L.disabled = !1, L.textContent = "Talk to the team", ce(), a.filed ? jt(a.filed, { callFailed: a.reason || "The call could not be started." }) : (z(a.message.replace("[BugCatch] ", "")), X.mode !== "off" && ft().catch(() => {
|
|
2626
2635
|
}));
|
|
2627
2636
|
}
|
|
2628
2637
|
});
|
|
2629
2638
|
function Dn(a) {
|
|
2630
|
-
const c =
|
|
2639
|
+
const c = f.querySelector(".panel"), d = a != null && a.bugId ? String(a.bugId).slice(0, 8) : null;
|
|
2631
2640
|
c.innerHTML = `
|
|
2632
2641
|
<div class="call">
|
|
2633
2642
|
<div class="call-head">
|
|
@@ -2642,15 +2651,15 @@ function sa({ root: t, host: e, dock: n, client: o, onClose: i }) {
|
|
|
2642
2651
|
<button class="primary" type="button" data-act="hangup">Cancel</button>
|
|
2643
2652
|
</div>
|
|
2644
2653
|
</div>`;
|
|
2645
|
-
const
|
|
2654
|
+
const g = c.querySelector(".call-state"), C = c.querySelector(".call-dot"), v = {
|
|
2646
2655
|
ringing: "Ringing the team…",
|
|
2647
2656
|
connecting: "Someone answered — connecting…",
|
|
2648
2657
|
connected: "Connected",
|
|
2649
2658
|
missed: "Nobody was free",
|
|
2650
2659
|
ended: "Call ended",
|
|
2651
2660
|
failed: "The call dropped"
|
|
2652
|
-
},
|
|
2653
|
-
if (
|
|
2661
|
+
}, _ = ["ended", "failed", "missed"], O = o.on("call", ({ state: F }) => {
|
|
2662
|
+
if (g.textContent = v[F] || F, C.classList.toggle("off", _.includes(F)), _.includes(F) && (c.querySelector('[data-act="hangup"]').textContent = "Close", F === "missed")) {
|
|
2654
2663
|
const G = c.querySelector(".call-note");
|
|
2655
2664
|
G && (G.textContent = "Nobody was free to pick up just now. Your report is filed and the team will reply in the chat.");
|
|
2656
2665
|
}
|
|
@@ -2659,28 +2668,28 @@ function sa({ root: t, host: e, dock: n, client: o, onClose: i }) {
|
|
|
2659
2668
|
O(), o.endCall(), re();
|
|
2660
2669
|
});
|
|
2661
2670
|
}
|
|
2662
|
-
function
|
|
2671
|
+
function jt(a, { callFailed: c = null } = {}) {
|
|
2663
2672
|
var v;
|
|
2664
|
-
const d = a != null && a.id ? String(a.id).slice(0, 8) : null,
|
|
2665
|
-
|
|
2673
|
+
const d = a != null && a.id ? String(a.id).slice(0, 8) : null, g = (v = a == null ? void 0 : a.estimate) != null && v.label ? String(a.estimate.label) : null, C = c ? `<p class="eta">${x(c)} Your report is filed, and the team will reply in the chat.</p>` : "";
|
|
2674
|
+
f.querySelector(".panel").innerHTML = `
|
|
2666
2675
|
<div class="done">
|
|
2667
|
-
<div class="tick">${
|
|
2676
|
+
<div class="tick">${j.check}</div>
|
|
2668
2677
|
<h3>Thanks — that's on its way.</h3>
|
|
2669
2678
|
<p>${d ? `Filed as <code>${x(d)}</code>.` : "The team has what they need to reproduce it."}</p>
|
|
2670
2679
|
${C}
|
|
2671
|
-
${
|
|
2672
|
-
</div>`, setTimeout(re, C ? 6e3 :
|
|
2680
|
+
${g ? `<p class="eta">Reports like this usually take <strong>${x(g)}</strong>. We'll let you know when it moves.</p>` : ""}
|
|
2681
|
+
</div>`, setTimeout(re, C ? 6e3 : g ? 4e3 : 2e3);
|
|
2673
2682
|
}
|
|
2674
|
-
async function
|
|
2675
|
-
const a =
|
|
2683
|
+
async function zt() {
|
|
2684
|
+
const a = f.querySelector(".panel");
|
|
2676
2685
|
a.innerHTML = `
|
|
2677
2686
|
<div class="head">
|
|
2678
|
-
<div class="mark">${
|
|
2687
|
+
<div class="mark">${j.bug}</div>
|
|
2679
2688
|
<div class="titles">
|
|
2680
2689
|
<h2>Your reports</h2>
|
|
2681
2690
|
<p>Everything you've reported, and where each one got to.</p>
|
|
2682
2691
|
</div>
|
|
2683
|
-
<button class="icon-btn" type="button" data-act="close" aria-label="Close">${
|
|
2692
|
+
<button class="icon-btn" type="button" data-act="close" aria-label="Close">${j.close}</button>
|
|
2684
2693
|
</div>
|
|
2685
2694
|
<div class="history"><div class="empty">Loading…</div></div>`, a.querySelector('[data-act="close"]').addEventListener("click", re);
|
|
2686
2695
|
let c = [];
|
|
@@ -2692,67 +2701,67 @@ function sa({ root: t, host: e, dock: n, client: o, onClose: i }) {
|
|
|
2692
2701
|
}
|
|
2693
2702
|
const d = a.querySelector(".history");
|
|
2694
2703
|
if (d) {
|
|
2695
|
-
d.innerHTML = c.length ? c.map((
|
|
2696
|
-
<button class="row" type="button" data-report="${x(
|
|
2704
|
+
d.innerHTML = c.length ? c.map((g) => `
|
|
2705
|
+
<button class="row" type="button" data-report="${x(g.id)}">
|
|
2697
2706
|
<span class="who">
|
|
2698
|
-
<span class="ttl">${x(
|
|
2699
|
-
<span class="sub">${x(
|
|
2707
|
+
<span class="ttl">${x(g.title)}</span>
|
|
2708
|
+
<span class="sub">${x(g.reference)} · ${x(at(g.createdAt))}</span>
|
|
2700
2709
|
</span>
|
|
2701
|
-
<span class="pill ${x(String(
|
|
2710
|
+
<span class="pill ${x(String(g.status).toLowerCase())}">${x(xt(g.status))}</span>
|
|
2702
2711
|
</button>`).join("") : `<div class="empty">You haven't reported anything yet.</div>`;
|
|
2703
|
-
for (const
|
|
2704
|
-
|
|
2712
|
+
for (const g of d.querySelectorAll("[data-report]"))
|
|
2713
|
+
g.addEventListener("click", () => Ot(g.dataset.report));
|
|
2705
2714
|
}
|
|
2706
2715
|
}
|
|
2707
|
-
async function
|
|
2716
|
+
async function Ot(a) {
|
|
2708
2717
|
var v;
|
|
2709
|
-
const c =
|
|
2718
|
+
const c = f.querySelector(".panel");
|
|
2710
2719
|
c.innerHTML = `
|
|
2711
2720
|
<div class="head">
|
|
2712
|
-
<button class="icon-btn back" type="button" data-act="back" aria-label="Back to your reports">${
|
|
2721
|
+
<button class="icon-btn back" type="button" data-act="back" aria-label="Back to your reports">${j.back}</button>
|
|
2713
2722
|
<div class="titles">
|
|
2714
2723
|
<h2>Your report</h2>
|
|
2715
2724
|
<p>Everything that has happened, and a way to answer.</p>
|
|
2716
2725
|
</div>
|
|
2717
|
-
<button class="icon-btn" type="button" data-act="close" aria-label="Close">${
|
|
2726
|
+
<button class="icon-btn" type="button" data-act="close" aria-label="Close">${j.close}</button>
|
|
2718
2727
|
</div>
|
|
2719
|
-
<div class="history"><div class="empty">Loading…</div></div>`, c.querySelector('[data-act="close"]').addEventListener("click", re), c.querySelector('[data-act="back"]').addEventListener("click",
|
|
2728
|
+
<div class="history"><div class="empty">Loading…</div></div>`, c.querySelector('[data-act="close"]').addEventListener("click", re), c.querySelector('[data-act="back"]').addEventListener("click", zt);
|
|
2720
2729
|
let d = null;
|
|
2721
2730
|
try {
|
|
2722
2731
|
d = await o.myReport(a);
|
|
2723
2732
|
} catch {
|
|
2724
2733
|
d = null;
|
|
2725
2734
|
}
|
|
2726
|
-
const
|
|
2727
|
-
if (!
|
|
2735
|
+
const g = c.querySelector(".history");
|
|
2736
|
+
if (!g || !c.querySelector('[data-act="back"]')) return;
|
|
2728
2737
|
if (!d) {
|
|
2729
|
-
|
|
2738
|
+
g.innerHTML = `<div class="empty">Couldn't load that report just now.</div>`;
|
|
2730
2739
|
return;
|
|
2731
2740
|
}
|
|
2732
|
-
|
|
2741
|
+
ge = a, o.markReportRead(a), g.classList.add("chatting"), g.innerHTML = `
|
|
2733
2742
|
<div class="report-head">
|
|
2734
2743
|
<span class="ttl">${x(d.title)}</span>
|
|
2735
2744
|
<span class="sub">${x(d.reference)} · ${x(d.project || "")}</span>
|
|
2736
|
-
<span class="pill ${x(String(d.status).toLowerCase())}">${x(
|
|
2745
|
+
<span class="pill ${x(String(d.status).toLowerCase())}">${x(xt(d.status))}</span>
|
|
2737
2746
|
${(v = d.estimate) != null && v.label ? `<span class="eta-line">Usually takes ${x(String(d.estimate.label))}</span>` : ""}
|
|
2738
2747
|
</div>
|
|
2739
2748
|
<div class="thread">${on(d.timeline)}</div>`;
|
|
2740
|
-
const C =
|
|
2741
|
-
|
|
2749
|
+
const C = g.querySelector(".thread");
|
|
2750
|
+
vt(C), Ht(g, d), d.canReply && Nn(g, C, a);
|
|
2742
2751
|
}
|
|
2743
|
-
function
|
|
2744
|
-
var
|
|
2745
|
-
if ((
|
|
2752
|
+
function Ht(a, c) {
|
|
2753
|
+
var g, C;
|
|
2754
|
+
if ((g = a.querySelector(".fix-verification")) == null || g.remove(), !c.resolvedAt || !["RESOLVED", "CLOSED"].includes(c.status)) return;
|
|
2746
2755
|
const d = document.createElement("div");
|
|
2747
2756
|
d.className = "fix-verification", c.verification ? d.textContent = c.verification === "CONFIRMED" ? "You confirmed that this fix works." : "Your feedback was recorded." : (d.innerHTML = '<p>Does the fix work for you?</p><textarea maxlength="4000" aria-label="Fix feedback" placeholder="What happens when you try again? (optional)"></textarea><button type="button" data-result="CONFIRMED">It works now</button> <button type="button" data-result="STILL_HAPPENING">Still happening</button><p class="feedback-status" role="status"></p>', d.querySelectorAll("[data-result]").forEach((v) => {
|
|
2748
2757
|
v.onclick = async () => {
|
|
2749
|
-
d.querySelectorAll("button").forEach((
|
|
2750
|
-
|
|
2758
|
+
d.querySelectorAll("button").forEach((_) => {
|
|
2759
|
+
_.disabled = !0;
|
|
2751
2760
|
});
|
|
2752
2761
|
try {
|
|
2753
|
-
await o.verifyFix(c.id, { result: v.dataset.result, resolvedAt: c.resolvedAt, note: d.querySelector("textarea").value }), await
|
|
2754
|
-
} catch (
|
|
2755
|
-
d.querySelector(".feedback-status").textContent =
|
|
2762
|
+
await o.verifyFix(c.id, { result: v.dataset.result, resolvedAt: c.resolvedAt, note: d.querySelector("textarea").value }), await Ot(c.id);
|
|
2763
|
+
} catch (_) {
|
|
2764
|
+
d.querySelector(".feedback-status").textContent = _.message, d.querySelectorAll("button").forEach((O) => {
|
|
2756
2765
|
O.disabled = !1;
|
|
2757
2766
|
});
|
|
2758
2767
|
}
|
|
@@ -2760,84 +2769,84 @@ function sa({ root: t, host: e, dock: n, client: o, onClose: i }) {
|
|
|
2760
2769
|
})), (C = a.querySelector(".report-head")) == null || C.after(d);
|
|
2761
2770
|
}
|
|
2762
2771
|
async function gt(a) {
|
|
2763
|
-
const c =
|
|
2764
|
-
if (!d ||
|
|
2765
|
-
let
|
|
2772
|
+
const c = f.querySelector(".history.chatting"), d = c == null ? void 0 : c.querySelector(".thread");
|
|
2773
|
+
if (!d || ge !== a) return;
|
|
2774
|
+
let g = null;
|
|
2766
2775
|
try {
|
|
2767
|
-
|
|
2776
|
+
g = await o.myReport(a);
|
|
2768
2777
|
} catch {
|
|
2769
2778
|
}
|
|
2770
|
-
if (!
|
|
2771
|
-
|
|
2779
|
+
if (!g || ge !== a) return;
|
|
2780
|
+
Ht(c, g);
|
|
2772
2781
|
const C = da(d);
|
|
2773
|
-
d.innerHTML = on(
|
|
2782
|
+
d.innerHTML = on(g.timeline), C && vt(d);
|
|
2774
2783
|
const v = c.querySelector(".report-head .pill");
|
|
2775
|
-
v && (v.className = `pill ${String(
|
|
2784
|
+
v && (v.className = `pill ${String(g.status).toLowerCase()}`, v.textContent = xt(g.status));
|
|
2776
2785
|
}
|
|
2777
2786
|
function Nn(a, c, d) {
|
|
2778
|
-
const
|
|
2779
|
-
|
|
2787
|
+
const g = document.createElement("div");
|
|
2788
|
+
g.className = "composer", g.innerHTML = `
|
|
2780
2789
|
<div class="staged" hidden></div>
|
|
2781
2790
|
<div class="row">
|
|
2782
2791
|
<div class="tools">
|
|
2783
|
-
<button class="tool" type="button" data-act="attach" title="Attach a file" aria-label="Attach a file">${
|
|
2784
|
-
<button class="tool" type="button" data-act="voice" title="Record a voice note" aria-label="Record a voice note">${
|
|
2785
|
-
<button class="tool" type="button" data-act="livecall" title="Call the team" aria-label="Call the team" hidden>${
|
|
2792
|
+
<button class="tool" type="button" data-act="attach" title="Attach a file" aria-label="Attach a file">${j.paperclip}</button>
|
|
2793
|
+
<button class="tool" type="button" data-act="voice" title="Record a voice note" aria-label="Record a voice note">${j.mic}</button>
|
|
2794
|
+
<button class="tool" type="button" data-act="livecall" title="Call the team" aria-label="Call the team" hidden>${j.phone}</button>
|
|
2786
2795
|
</div>
|
|
2787
2796
|
<textarea rows="1" placeholder="Write a reply…" aria-label="Write a reply"></textarea>
|
|
2788
|
-
<button class="send" type="button" data-act="send" title="Send" aria-label="Send" disabled>${
|
|
2797
|
+
<button class="send" type="button" data-act="send" title="Send" aria-label="Send" disabled>${j.send}</button>
|
|
2789
2798
|
</div>
|
|
2790
2799
|
<div class="note" hidden></div>
|
|
2791
|
-
<input type="file" hidden multiple accept="${bn.join(",")}">`, a.appendChild(
|
|
2792
|
-
const C =
|
|
2793
|
-
let Se = null,
|
|
2794
|
-
function ne(M,
|
|
2795
|
-
de.hidden = !M, de.className = `note ${
|
|
2800
|
+
<input type="file" hidden multiple accept="${bn.join(",")}">`, a.appendChild(g);
|
|
2801
|
+
const C = g.querySelector(".staged"), v = g.querySelector("textarea"), _ = g.querySelector('[data-act="send"]'), O = g.querySelector('[data-act="voice"]'), F = g.querySelector('[data-act="livecall"]'), G = g.querySelector("input[type=file]"), de = g.querySelector(".note"), U = [];
|
|
2802
|
+
let Se = null, W = !1;
|
|
2803
|
+
function ne(M, R = "") {
|
|
2804
|
+
de.hidden = !M, de.className = `note ${R}`, de.textContent = M || "";
|
|
2796
2805
|
}
|
|
2797
2806
|
function Ce() {
|
|
2798
|
-
const M =
|
|
2799
|
-
|
|
2800
|
-
<span class="chip ${
|
|
2801
|
-
<span class="nm">${x(
|
|
2802
|
-
<span class="sz">${
|
|
2803
|
-
<button type="button" data-drop="${
|
|
2807
|
+
const M = U.filter((R) => R.storageKey);
|
|
2808
|
+
_.disabled = W || !v.value.trim() && !M.length, C.hidden = !U.length, C.innerHTML = U.map((R, ue) => `
|
|
2809
|
+
<span class="chip ${R.storageKey ? "" : "uploading"}">
|
|
2810
|
+
<span class="nm">${x(R.name)}</span>
|
|
2811
|
+
<span class="sz">${R.storageKey ? je(R.size) : "sending…"}</span>
|
|
2812
|
+
<button type="button" data-drop="${ue}" aria-label="Remove ${x(R.name)}">${j.close}</button>
|
|
2804
2813
|
</span>`).join("");
|
|
2805
|
-
for (const
|
|
2806
|
-
|
|
2807
|
-
|
|
2814
|
+
for (const R of C.querySelectorAll("[data-drop]"))
|
|
2815
|
+
R.addEventListener("click", () => {
|
|
2816
|
+
U.splice(Number(R.dataset.drop), 1), Ce();
|
|
2808
2817
|
});
|
|
2809
2818
|
}
|
|
2810
|
-
async function
|
|
2811
|
-
const
|
|
2812
|
-
|
|
2819
|
+
async function Pt(M, R, ue) {
|
|
2820
|
+
const H = { name: ue, size: M.size, storageKey: null };
|
|
2821
|
+
U.push(H), Ce();
|
|
2813
2822
|
try {
|
|
2814
|
-
const { storageKey:
|
|
2815
|
-
|
|
2816
|
-
} catch (
|
|
2817
|
-
|
|
2823
|
+
const { storageKey: bt, mime: Vn } = await o.uploadAttachment(M, R);
|
|
2824
|
+
H.storageKey = bt, H.mime = Vn;
|
|
2825
|
+
} catch (bt) {
|
|
2826
|
+
U.splice(U.indexOf(H), 1), ne(bt.message || "That file could not be sent.", "err");
|
|
2818
2827
|
}
|
|
2819
2828
|
Ce();
|
|
2820
2829
|
}
|
|
2821
2830
|
v.addEventListener("input", () => {
|
|
2822
2831
|
v.style.height = "auto", v.style.height = `${Math.min(v.scrollHeight, 120)}px`, Ce();
|
|
2823
2832
|
}), v.addEventListener("keydown", (M) => {
|
|
2824
|
-
M.key === "Enter" && !M.shiftKey && !M.isComposing && (M.preventDefault(),
|
|
2825
|
-
}),
|
|
2833
|
+
M.key === "Enter" && !M.shiftKey && !M.isComposing && (M.preventDefault(), mt());
|
|
2834
|
+
}), g.querySelector('[data-act="attach"]').addEventListener("click", () => G.click()), G.addEventListener("change", () => {
|
|
2826
2835
|
ne("");
|
|
2827
2836
|
for (const M of G.files) {
|
|
2828
2837
|
if (M.size > o.config.maxAttachmentBytes) {
|
|
2829
2838
|
ne(`${M.name} is larger than ${je(o.config.maxAttachmentBytes)}.`, "err");
|
|
2830
2839
|
continue;
|
|
2831
2840
|
}
|
|
2832
|
-
|
|
2841
|
+
Pt(M, M.type, M.name);
|
|
2833
2842
|
}
|
|
2834
2843
|
G.value = "";
|
|
2835
2844
|
}), io() || (O.disabled = !0, O.title = "This browser cannot record audio"), O.addEventListener("click", async () => {
|
|
2836
2845
|
if (Se) {
|
|
2837
2846
|
const M = Se;
|
|
2838
|
-
Se = null, O.classList.remove("recording"), O.innerHTML =
|
|
2839
|
-
const { blob:
|
|
2840
|
-
|
|
2847
|
+
Se = null, O.classList.remove("recording"), O.innerHTML = j.mic, ne("");
|
|
2848
|
+
const { blob: R, mime: ue } = await M.stop();
|
|
2849
|
+
R.size && Pt(R, ue, "Voice note");
|
|
2841
2850
|
return;
|
|
2842
2851
|
}
|
|
2843
2852
|
try {
|
|
@@ -2845,90 +2854,94 @@ function sa({ root: t, host: e, dock: n, client: o, onClose: i }) {
|
|
|
2845
2854
|
maxMs: o.config.maxRecordingMs,
|
|
2846
2855
|
onTick: (M) => ne(`Recording — ${We(M)}. Tap the mic to stop.`),
|
|
2847
2856
|
onAutoStop: () => O.click()
|
|
2848
|
-
}), O.classList.add("recording"), O.innerHTML =
|
|
2857
|
+
}), O.classList.add("recording"), O.innerHTML = j.stopSquare;
|
|
2849
2858
|
} catch {
|
|
2850
2859
|
Se = null, ne("The microphone is not available — check the browser permission.", "err");
|
|
2851
2860
|
}
|
|
2852
2861
|
}), o.canCallTeam(d).then((M) => {
|
|
2853
|
-
M && (
|
|
2862
|
+
M && (F.hidden = !1);
|
|
2854
2863
|
}).catch(() => {
|
|
2855
|
-
}),
|
|
2856
|
-
|
|
2864
|
+
}), F.addEventListener("click", async () => {
|
|
2865
|
+
F.disabled = !0, ne("");
|
|
2857
2866
|
try {
|
|
2858
2867
|
const M = await o.startLiveCall(d);
|
|
2859
2868
|
Un(a, c, M);
|
|
2860
2869
|
} catch (M) {
|
|
2861
2870
|
ne(M.message.replace("[BugCatch] ", ""), "err");
|
|
2862
2871
|
} finally {
|
|
2863
|
-
|
|
2872
|
+
F.disabled = !1;
|
|
2864
2873
|
}
|
|
2865
|
-
}),
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2874
|
+
}), _.addEventListener("click", mt), c.addEventListener("click", (M) => {
|
|
2875
|
+
var ue, H;
|
|
2876
|
+
const R = (H = (ue = M.target).closest) == null ? void 0 : H.call(ue, "[data-quick]");
|
|
2877
|
+
!R || W || (v.value = R.dataset.quick, mt());
|
|
2878
|
+
});
|
|
2879
|
+
async function mt() {
|
|
2880
|
+
var ue;
|
|
2881
|
+
const M = v.value.trim(), R = U.filter((H) => H.storageKey);
|
|
2882
|
+
if (!(W || !M && !R.length)) {
|
|
2883
|
+
W = !0, Ce(), ne(""), c.insertAdjacentHTML("beforeend", Tn({
|
|
2871
2884
|
from: "reporter",
|
|
2872
2885
|
body: M,
|
|
2873
2886
|
at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2874
|
-
attachments:
|
|
2875
|
-
}, "pending")),
|
|
2887
|
+
attachments: R.map((H) => ({ type: "FILE", name: H.name, size: H.size }))
|
|
2888
|
+
}, "pending")), vt(c);
|
|
2876
2889
|
try {
|
|
2877
2890
|
await vn({
|
|
2878
2891
|
apiBase: o.config.apiBase,
|
|
2879
2892
|
bugId: d,
|
|
2880
2893
|
body: M,
|
|
2881
|
-
attachments:
|
|
2882
|
-
storageKey:
|
|
2883
|
-
mime:
|
|
2884
|
-
name:
|
|
2885
|
-
size:
|
|
2894
|
+
attachments: R.map((H) => ({
|
|
2895
|
+
storageKey: H.storageKey,
|
|
2896
|
+
mime: H.mime,
|
|
2897
|
+
name: H.name,
|
|
2898
|
+
size: H.size
|
|
2886
2899
|
}))
|
|
2887
|
-
}), v.value = "", v.style.height = "auto",
|
|
2888
|
-
} catch (
|
|
2889
|
-
(
|
|
2900
|
+
}), v.value = "", v.style.height = "auto", U.length = 0, await gt(d);
|
|
2901
|
+
} catch (H) {
|
|
2902
|
+
(ue = c.querySelector(".msg-row.pending")) == null || ue.classList.replace("pending", "failed"), ne(H.message || "That could not be sent — try again.", "err");
|
|
2890
2903
|
} finally {
|
|
2891
|
-
|
|
2904
|
+
W = !1, Ce();
|
|
2892
2905
|
}
|
|
2893
2906
|
}
|
|
2894
2907
|
}
|
|
2895
2908
|
Ce();
|
|
2896
2909
|
}
|
|
2897
2910
|
function Un(a, c, d) {
|
|
2898
|
-
const
|
|
2899
|
-
|
|
2911
|
+
const g = document.createElement("div");
|
|
2912
|
+
g.className = "livecall", g.innerHTML = `
|
|
2900
2913
|
<span class="call-dot" aria-hidden="true"></span>
|
|
2901
2914
|
<span class="who" role="status" aria-live="polite">Calling the team…</span>
|
|
2902
2915
|
<span class="secs" hidden></span>
|
|
2903
2916
|
<button class="act" type="button" data-act="mute" hidden>Mute</button>
|
|
2904
|
-
<button class="act danger" type="button" data-act="hangup">Cancel</button>`, a.insertBefore(
|
|
2905
|
-
const C =
|
|
2917
|
+
<button class="act danger" type="button" data-act="hangup">Cancel</button>`, a.insertBefore(g, c);
|
|
2918
|
+
const C = g.querySelector(".who"), v = g.querySelector(".secs"), _ = g.querySelector(".call-dot"), O = g.querySelector('[data-act="mute"]'), F = g.querySelector('[data-act="hangup"]');
|
|
2906
2919
|
let G = null;
|
|
2907
2920
|
const de = () => {
|
|
2908
2921
|
G && (clearInterval(G), G = null);
|
|
2909
|
-
},
|
|
2910
|
-
de(),
|
|
2911
|
-
}, Se = o.on("call", ({ state:
|
|
2912
|
-
if (
|
|
2922
|
+
}, U = (W) => {
|
|
2923
|
+
de(), _.classList.add("off"), g.classList.add("over"), C.textContent = W, v.hidden = !0, O.hidden = !0, F.textContent = "Dismiss", F.classList.remove("danger");
|
|
2924
|
+
}, Se = o.on("call", ({ state: W }) => {
|
|
2925
|
+
if (W === "ringing" && (C.textContent = "Calling the team…"), W === "connecting" && (C.textContent = "Someone answered — connecting…"), W === "connected") {
|
|
2913
2926
|
C.textContent = "You're on a call with the team", O.hidden = !1, v.hidden = !1;
|
|
2914
2927
|
const ne = Date.now();
|
|
2915
2928
|
de(), G = setInterval(() => {
|
|
2916
2929
|
v.textContent = We(Math.floor((Date.now() - ne) / 1e3));
|
|
2917
2930
|
}, 1e3), v.textContent = "0s";
|
|
2918
2931
|
}
|
|
2919
|
-
|
|
2932
|
+
W === "missed" && U("Nobody was free. Send a message instead and the team will pick it up."), W === "ended" && U("Call ended."), W === "failed" && U("The call dropped.");
|
|
2920
2933
|
});
|
|
2921
2934
|
O.addEventListener("click", () => {
|
|
2922
|
-
const
|
|
2923
|
-
O.textContent =
|
|
2924
|
-
}),
|
|
2925
|
-
Se(), de(), o.endCall(),
|
|
2935
|
+
const W = d.setMuted(!d.isMuted());
|
|
2936
|
+
O.textContent = W ? "Unmute" : "Mute", C.textContent = W ? "You're muted" : "You're on a call with the team";
|
|
2937
|
+
}), F.addEventListener("click", () => {
|
|
2938
|
+
Se(), de(), o.endCall(), g.remove(), gt(ge);
|
|
2926
2939
|
});
|
|
2927
2940
|
}
|
|
2928
|
-
let
|
|
2929
|
-
return
|
|
2930
|
-
!
|
|
2931
|
-
}), t.appendChild(
|
|
2941
|
+
let ge = null;
|
|
2942
|
+
return we = o.on("update", (a) => {
|
|
2943
|
+
!ge || (a == null ? void 0 : a.bugId) !== ge || (o.markReportRead(ge), gt(ge));
|
|
2944
|
+
}), t.appendChild(f), ce(), A.focus(), { destroy: He, close: re };
|
|
2932
2945
|
}
|
|
2933
2946
|
function on(t) {
|
|
2934
2947
|
const e = t || [];
|
|
@@ -2954,10 +2967,16 @@ function ca(t) {
|
|
|
2954
2967
|
function Tn(t, e = "") {
|
|
2955
2968
|
const n = t.from === "reporter", o = t.body || "", i = t.attachments || [], r = !n && !!t.automated, s = o ? `<span class="msg-text">${x(o)}</span>` : "", l = i.length ? `<div class="att">${i.map(la).join("")}</div>` : "";
|
|
2956
2969
|
let u = "";
|
|
2957
|
-
|
|
2970
|
+
r ? u = '<span class="msg-who auto">Automatic reply</span>' : !n && t.author && (u = `<span class="msg-who">${x(t.author)}</span>`);
|
|
2971
|
+
const h = r && /reply "yes" or "no"/i.test(o) ? `<div class="quick" role="group" aria-label="Answer">
|
|
2972
|
+
<button type="button" data-quick="Yes, this is the problem">Yes, that's it</button>
|
|
2973
|
+
<button type="button" data-quick="No, that is not the problem">No, it's something else</button>
|
|
2974
|
+
</div>` : "";
|
|
2975
|
+
return `
|
|
2958
2976
|
<div class="msg-row ${n ? "mine" : "theirs"} ${r ? "auto" : ""} ${e}">
|
|
2959
2977
|
${u}
|
|
2960
2978
|
<div class="bubble ${o ? "" : "silent"}">${s}${l}</div>
|
|
2979
|
+
${h}
|
|
2961
2980
|
<span class="msg-when">${x(at(t.at))}</span>
|
|
2962
2981
|
</div>`;
|
|
2963
2982
|
}
|
|
@@ -2974,10 +2993,10 @@ function la(t) {
|
|
|
2974
2993
|
function da(t) {
|
|
2975
2994
|
return t.scrollHeight - t.scrollTop - t.clientHeight < 40;
|
|
2976
2995
|
}
|
|
2977
|
-
function
|
|
2996
|
+
function vt(t) {
|
|
2978
2997
|
t.scrollTop = t.scrollHeight;
|
|
2979
2998
|
}
|
|
2980
|
-
function
|
|
2999
|
+
function xt(t) {
|
|
2981
3000
|
return {
|
|
2982
3001
|
OPEN: "Open",
|
|
2983
3002
|
IN_PROGRESS: "In progress",
|
|
@@ -3019,7 +3038,7 @@ function ha(t, e, n) {
|
|
|
3019
3038
|
for (let r = 0; r < i.length; r++) {
|
|
3020
3039
|
const s = Math.floor(r * o), l = Math.min(Math.floor((r + 1) * o), t.length);
|
|
3021
3040
|
let u = 0;
|
|
3022
|
-
for (let
|
|
3041
|
+
for (let h = s; h < l; h++) u += t[h];
|
|
3023
3042
|
i[r] = l > s ? u / (l - s) : 0;
|
|
3024
3043
|
}
|
|
3025
3044
|
return i;
|
|
@@ -3043,8 +3062,8 @@ const ma = 512;
|
|
|
3043
3062
|
function ba(t, e, n, o = In) {
|
|
3044
3063
|
const i = t.createMediaStreamSource(e), r = t.createScriptProcessor(ma, 1, 1);
|
|
3045
3064
|
r.onaudioprocess = (l) => {
|
|
3046
|
-
const u = l.inputBuffer.getChannelData(0),
|
|
3047
|
-
n(ga(
|
|
3065
|
+
const u = l.inputBuffer.getChannelData(0), h = t.sampleRate === o ? u : ha(u, t.sampleRate, o);
|
|
3066
|
+
n(ga(h));
|
|
3048
3067
|
}, i.connect(r);
|
|
3049
3068
|
const s = t.createGain();
|
|
3050
3069
|
return s.gain.value = 0, r.connect(s), s.connect(t.destination), {
|
|
@@ -3065,8 +3084,8 @@ function ba(t, e, n, o = In) {
|
|
|
3065
3084
|
}
|
|
3066
3085
|
};
|
|
3067
3086
|
}
|
|
3068
|
-
const
|
|
3069
|
-
function
|
|
3087
|
+
const ya = "voiceai.realtime.v1", wa = [{ urls: "stun:stun.l.google.com:19302" }];
|
|
3088
|
+
function Ct() {
|
|
3070
3089
|
return navigator.mediaDevices.getUserMedia({
|
|
3071
3090
|
audio: {
|
|
3072
3091
|
// Both ends are on speakers as often as not. Without cancellation each
|
|
@@ -3079,7 +3098,7 @@ function St() {
|
|
|
3079
3098
|
}
|
|
3080
3099
|
});
|
|
3081
3100
|
}
|
|
3082
|
-
function
|
|
3101
|
+
function Et() {
|
|
3083
3102
|
var t;
|
|
3084
3103
|
return typeof window < "u" && typeof window.RTCPeerConnection == "function" && !!((t = navigator.mediaDevices) != null && t.getUserMedia);
|
|
3085
3104
|
}
|
|
@@ -3091,9 +3110,9 @@ async function rn({
|
|
|
3091
3110
|
onAudioBlocked: i,
|
|
3092
3111
|
onMicrophone: r
|
|
3093
3112
|
}) {
|
|
3094
|
-
const s = (m,
|
|
3113
|
+
const s = (m, w) => {
|
|
3095
3114
|
try {
|
|
3096
|
-
o == null || o(m,
|
|
3115
|
+
o == null || o(m, w);
|
|
3097
3116
|
} catch {
|
|
3098
3117
|
}
|
|
3099
3118
|
}, l = (m) => {
|
|
@@ -3107,74 +3126,74 @@ async function rn({
|
|
|
3107
3126
|
} catch {
|
|
3108
3127
|
}
|
|
3109
3128
|
};
|
|
3110
|
-
if (!
|
|
3129
|
+
if (!Et()) {
|
|
3111
3130
|
const m = new Error("[BugCatch] this browser cannot make live calls.");
|
|
3112
3131
|
throw s("failed", { reason: "unsupported" }), m;
|
|
3113
3132
|
}
|
|
3114
|
-
let
|
|
3115
|
-
if (!
|
|
3133
|
+
let h = e;
|
|
3134
|
+
if (!h)
|
|
3116
3135
|
try {
|
|
3117
|
-
|
|
3136
|
+
h = await Ct();
|
|
3118
3137
|
} catch (m) {
|
|
3119
3138
|
throw s("failed", { reason: "microphone", error: String((m == null ? void 0 : m.name) || m) }), m;
|
|
3120
3139
|
}
|
|
3121
|
-
let
|
|
3140
|
+
let y;
|
|
3122
3141
|
try {
|
|
3123
|
-
|
|
3142
|
+
y = await va(t);
|
|
3124
3143
|
} catch (m) {
|
|
3125
|
-
throw cn(
|
|
3144
|
+
throw cn(h), s("failed", { reason: "connect" }), m;
|
|
3126
3145
|
}
|
|
3127
|
-
let p = null, b = null,
|
|
3146
|
+
let p = null, b = null, f = !1, k = null, A = null, oe = null, S = !1, E = null, T = null, L = !1;
|
|
3128
3147
|
const Y = [];
|
|
3129
|
-
let
|
|
3130
|
-
const ze = 2e3, be = 5e3, Ue = 3e4,
|
|
3131
|
-
if (!
|
|
3132
|
-
|
|
3148
|
+
let q = !1, Q = !1, D = !1, $ = null, ae = null, ee = 0;
|
|
3149
|
+
const ze = 2e3, be = 5e3, Ue = 3e4, ye = 4, N = (m, w) => {
|
|
3150
|
+
if (!f) {
|
|
3151
|
+
f = !0, k && (clearTimeout(k), k = null), re(), T == null || T(), T = null, Ve(), E == null || E(), E = null;
|
|
3133
3152
|
try {
|
|
3134
3153
|
p == null || p.close();
|
|
3135
3154
|
} catch {
|
|
3136
3155
|
}
|
|
3137
|
-
cn(
|
|
3156
|
+
cn(h), b && (b.srcObject = null, b.remove(), b = null);
|
|
3138
3157
|
try {
|
|
3139
|
-
|
|
3158
|
+
y.readyState === WebSocket.OPEN && y.close(1e3, "call over");
|
|
3140
3159
|
} catch {
|
|
3141
3160
|
}
|
|
3142
|
-
s(m,
|
|
3161
|
+
s(m, w);
|
|
3143
3162
|
}
|
|
3144
3163
|
}, te = (m) => {
|
|
3145
|
-
|
|
3164
|
+
y.readyState === WebSocket.OPEN && y.send(JSON.stringify(m));
|
|
3146
3165
|
}, $e = async () => {
|
|
3147
|
-
if (L || oe ||
|
|
3166
|
+
if (L || oe || f || !A || !A.audio && !A.transcript) return;
|
|
3148
3167
|
L = !0;
|
|
3149
3168
|
const m = A.encoding || "mulaw";
|
|
3150
3169
|
if (m !== "mulaw") {
|
|
3151
3170
|
sn(`this call is kept as ${m}, which this SDK cannot produce.`);
|
|
3152
3171
|
return;
|
|
3153
3172
|
}
|
|
3154
|
-
const
|
|
3173
|
+
const w = Number(A.sample_rate) || 8e3;
|
|
3155
3174
|
try {
|
|
3156
|
-
const I = ua(
|
|
3157
|
-
if (await pa(I),
|
|
3175
|
+
const I = ua(w);
|
|
3176
|
+
if (await pa(I), f) {
|
|
3158
3177
|
try {
|
|
3159
3178
|
I.close();
|
|
3160
3179
|
} catch {
|
|
3161
3180
|
}
|
|
3162
3181
|
return;
|
|
3163
3182
|
}
|
|
3164
|
-
const
|
|
3165
|
-
|
|
3166
|
-
},
|
|
3167
|
-
oe = { context: I, tap:
|
|
3183
|
+
const K = ba(I, h, (P) => {
|
|
3184
|
+
y.readyState === WebSocket.OPEN && y.send(P);
|
|
3185
|
+
}, w);
|
|
3186
|
+
oe = { context: I, tap: K };
|
|
3168
3187
|
} catch (I) {
|
|
3169
3188
|
sn(`could not send the copy this call is keeping: ${String((I == null ? void 0 : I.message) || I)}`);
|
|
3170
3189
|
}
|
|
3171
3190
|
};
|
|
3172
3191
|
function Ve() {
|
|
3173
3192
|
if (L = !1, !oe) return;
|
|
3174
|
-
const { context: m, tap:
|
|
3193
|
+
const { context: m, tap: w } = oe;
|
|
3175
3194
|
oe = null;
|
|
3176
3195
|
try {
|
|
3177
|
-
|
|
3196
|
+
w.stop();
|
|
3178
3197
|
} catch {
|
|
3179
3198
|
}
|
|
3180
3199
|
try {
|
|
@@ -3183,34 +3202,34 @@ async function rn({
|
|
|
3183
3202
|
}
|
|
3184
3203
|
}
|
|
3185
3204
|
function Oe() {
|
|
3186
|
-
var
|
|
3187
|
-
if (!b ||
|
|
3205
|
+
var w;
|
|
3206
|
+
if (!b || f) return;
|
|
3188
3207
|
let m;
|
|
3189
3208
|
try {
|
|
3190
|
-
m = (
|
|
3209
|
+
m = (w = b.play) == null ? void 0 : w.call(b);
|
|
3191
3210
|
} catch {
|
|
3192
3211
|
Te();
|
|
3193
3212
|
return;
|
|
3194
3213
|
}
|
|
3195
3214
|
if (!m || typeof m.then != "function") {
|
|
3196
|
-
|
|
3215
|
+
fe();
|
|
3197
3216
|
return;
|
|
3198
3217
|
}
|
|
3199
|
-
m.then(
|
|
3218
|
+
m.then(fe, Te);
|
|
3200
3219
|
}
|
|
3201
|
-
function
|
|
3220
|
+
function fe() {
|
|
3202
3221
|
E == null || E(), E = null, S && (S = !1, l(!1));
|
|
3203
3222
|
}
|
|
3204
3223
|
function Te() {
|
|
3205
|
-
|
|
3224
|
+
f || (S || (S = !0, l(!0)), ct());
|
|
3206
3225
|
}
|
|
3207
3226
|
function ct() {
|
|
3208
3227
|
if (E || typeof window > "u" || typeof window.addEventListener != "function") return;
|
|
3209
|
-
const m = () => Oe(),
|
|
3210
|
-
for (const I of
|
|
3228
|
+
const m = () => Oe(), w = ["pointerdown", "keydown", "touchstart"];
|
|
3229
|
+
for (const I of w)
|
|
3211
3230
|
window.addEventListener(I, m, { capture: !0, passive: !0 });
|
|
3212
3231
|
E = () => {
|
|
3213
|
-
for (const I of
|
|
3232
|
+
for (const I of w)
|
|
3214
3233
|
try {
|
|
3215
3234
|
window.removeEventListener(I, m, { capture: !0 });
|
|
3216
3235
|
} catch {
|
|
@@ -3218,55 +3237,55 @@ async function rn({
|
|
|
3218
3237
|
};
|
|
3219
3238
|
}
|
|
3220
3239
|
const Ie = (m) => {
|
|
3221
|
-
p = new RTCPeerConnection({ iceServers: m != null && m.length ? m :
|
|
3222
|
-
for (const
|
|
3223
|
-
T = ce(), p.onicecandidate = (
|
|
3224
|
-
|
|
3225
|
-
}, p.ontrack = (
|
|
3226
|
-
var
|
|
3227
|
-
const [I] =
|
|
3228
|
-
I && (b || (b = document.createElement("audio"), b.autoplay = !0, b.playsInline = !0, (
|
|
3229
|
-
}, p.onconnectionstatechange =
|
|
3240
|
+
p = new RTCPeerConnection({ iceServers: m != null && m.length ? m : wa });
|
|
3241
|
+
for (const w of h.getAudioTracks()) p.addTrack(w, h);
|
|
3242
|
+
T = ce(), p.onicecandidate = (w) => {
|
|
3243
|
+
w.candidate && te({ type: "signal", signal: { kind: "candidate", payload: w.candidate.toJSON() } });
|
|
3244
|
+
}, p.ontrack = (w) => {
|
|
3245
|
+
var K;
|
|
3246
|
+
const [I] = w.streams;
|
|
3247
|
+
I && (b || (b = document.createElement("audio"), b.autoplay = !0, b.playsInline = !0, (K = b.setAttribute) == null || K.call(b, "playsinline", ""), b.style.cssText = "position:fixed;width:0;height:0;opacity:0;pointer-events:none", document.body.appendChild(b)), b.srcObject = I, Oe());
|
|
3248
|
+
}, p.onconnectionstatechange = we, p.oniceconnectionstatechange = we;
|
|
3230
3249
|
};
|
|
3231
|
-
function
|
|
3232
|
-
if (!p ||
|
|
3250
|
+
function we() {
|
|
3251
|
+
if (!p || f) return;
|
|
3233
3252
|
const m = p.connectionState || p.iceConnectionState;
|
|
3234
3253
|
if (m === "connected" || m === "completed") {
|
|
3235
|
-
|
|
3254
|
+
Q = !0, ee = 0, re(), D = !1, s("connected");
|
|
3236
3255
|
return;
|
|
3237
3256
|
}
|
|
3238
3257
|
if (m === "disconnected") {
|
|
3239
|
-
if (!
|
|
3258
|
+
if (!Q) return;
|
|
3240
3259
|
He(ze);
|
|
3241
3260
|
return;
|
|
3242
3261
|
}
|
|
3243
3262
|
if (m === "failed") {
|
|
3244
|
-
if (!
|
|
3245
|
-
|
|
3263
|
+
if (!Q) {
|
|
3264
|
+
N("failed", { reason: "ice" });
|
|
3246
3265
|
return;
|
|
3247
3266
|
}
|
|
3248
3267
|
He(0);
|
|
3249
3268
|
}
|
|
3250
3269
|
}
|
|
3251
3270
|
function He(m) {
|
|
3252
|
-
|
|
3271
|
+
f || (D || (D = !0, s("reconnecting"), ae = setTimeout(() => N("failed", { reason: "network" }), Ue)), !$ && ($ = setTimeout(Me, m)));
|
|
3253
3272
|
}
|
|
3254
3273
|
function re() {
|
|
3255
3274
|
$ && (clearTimeout($), $ = null), ae && (clearTimeout(ae), ae = null);
|
|
3256
3275
|
}
|
|
3257
3276
|
async function Me() {
|
|
3258
|
-
if ($ = null,
|
|
3277
|
+
if ($ = null, f || !p) return;
|
|
3259
3278
|
const m = p.connectionState || p.iceConnectionState;
|
|
3260
3279
|
if (!(m === "connected" || m === "completed")) {
|
|
3261
|
-
if (!
|
|
3280
|
+
if (!q) {
|
|
3262
3281
|
te({ type: "signal", signal: { kind: "restart", payload: {} } }), $ = setTimeout(Me, be);
|
|
3263
3282
|
return;
|
|
3264
3283
|
}
|
|
3265
|
-
ee >=
|
|
3284
|
+
ee >= ye || (ee += 1, await z(), $ = setTimeout(Me, be));
|
|
3266
3285
|
}
|
|
3267
3286
|
}
|
|
3268
3287
|
async function z() {
|
|
3269
|
-
if (!(
|
|
3288
|
+
if (!(f || !p))
|
|
3270
3289
|
try {
|
|
3271
3290
|
const m = await p.createOffer({ iceRestart: !0 });
|
|
3272
3291
|
await p.setLocalDescription(m), te({ type: "signal", signal: { kind: "offer", payload: p.localDescription.toJSON() } });
|
|
@@ -3274,25 +3293,25 @@ async function rn({
|
|
|
3274
3293
|
}
|
|
3275
3294
|
}
|
|
3276
3295
|
function ce() {
|
|
3277
|
-
let
|
|
3278
|
-
const
|
|
3279
|
-
if (
|
|
3296
|
+
let w = null, I = !1;
|
|
3297
|
+
const K = (P) => {
|
|
3298
|
+
if (w && (clearTimeout(w), w = null), P) {
|
|
3280
3299
|
if (!I) return;
|
|
3281
3300
|
I = !1, u(!0);
|
|
3282
3301
|
return;
|
|
3283
3302
|
}
|
|
3284
|
-
I || (
|
|
3285
|
-
|
|
3303
|
+
I || (w = setTimeout(() => {
|
|
3304
|
+
w = null, !f && (I = !0, u(!1));
|
|
3286
3305
|
}, 600));
|
|
3287
3306
|
};
|
|
3288
|
-
for (const
|
|
3289
|
-
|
|
3290
|
-
|
|
3307
|
+
for (const P of h.getAudioTracks())
|
|
3308
|
+
P.onmute = () => K(!1), P.onunmute = () => K(!0), P.onended = () => {
|
|
3309
|
+
w && (clearTimeout(w), w = null), !I && (I = !0, u(!1));
|
|
3291
3310
|
};
|
|
3292
3311
|
return () => {
|
|
3293
|
-
|
|
3294
|
-
for (const
|
|
3295
|
-
|
|
3312
|
+
w && (clearTimeout(w), w = null);
|
|
3313
|
+
for (const P of h.getAudioTracks())
|
|
3314
|
+
P.onmute = null, P.onunmute = null, P.onended = null;
|
|
3296
3315
|
};
|
|
3297
3316
|
}
|
|
3298
3317
|
const Ke = async () => {
|
|
@@ -3300,15 +3319,15 @@ async function rn({
|
|
|
3300
3319
|
const m = await p.createOffer();
|
|
3301
3320
|
await p.setLocalDescription(m), te({ type: "signal", signal: { kind: "offer", payload: p.localDescription.toJSON() } });
|
|
3302
3321
|
} catch {
|
|
3303
|
-
|
|
3322
|
+
N("failed", { reason: "negotiation" });
|
|
3304
3323
|
}
|
|
3305
3324
|
}, lt = async (m) => {
|
|
3306
3325
|
try {
|
|
3307
3326
|
await p.setRemoteDescription(new RTCSessionDescription(m));
|
|
3308
|
-
const
|
|
3309
|
-
await p.setLocalDescription(
|
|
3327
|
+
const w = await p.createAnswer();
|
|
3328
|
+
await p.setLocalDescription(w), te({ type: "signal", signal: { kind: "answer", payload: p.localDescription.toJSON() } }), await Le();
|
|
3310
3329
|
} catch {
|
|
3311
|
-
|
|
3330
|
+
N("failed", { reason: "negotiation" });
|
|
3312
3331
|
}
|
|
3313
3332
|
}, Le = async () => {
|
|
3314
3333
|
for (; Y.length; ) {
|
|
@@ -3320,22 +3339,22 @@ async function rn({
|
|
|
3320
3339
|
}
|
|
3321
3340
|
};
|
|
3322
3341
|
let ve = Promise.resolve();
|
|
3323
|
-
|
|
3342
|
+
y.onmessage = (m) => {
|
|
3324
3343
|
ve = ve.then(() => dt(m)).catch(() => {
|
|
3325
3344
|
});
|
|
3326
3345
|
};
|
|
3327
3346
|
const dt = async (m) => {
|
|
3328
|
-
var I,
|
|
3347
|
+
var I, K, P, xe, Pe;
|
|
3329
3348
|
if (typeof m.data != "string") return;
|
|
3330
|
-
let
|
|
3349
|
+
let w;
|
|
3331
3350
|
try {
|
|
3332
|
-
|
|
3351
|
+
w = JSON.parse(m.data);
|
|
3333
3352
|
} catch {
|
|
3334
3353
|
return;
|
|
3335
3354
|
}
|
|
3336
|
-
switch (
|
|
3355
|
+
switch (w.type) {
|
|
3337
3356
|
case "session.created": {
|
|
3338
|
-
if (Ie((I =
|
|
3357
|
+
if (Ie((I = w.data) == null ? void 0 : I.ice_servers), A = ((K = w.data) == null ? void 0 : K.capture) || null, (P = w.data) != null && P.peer_present) {
|
|
3339
3358
|
s("connecting"), $e();
|
|
3340
3359
|
break;
|
|
3341
3360
|
}
|
|
@@ -3343,58 +3362,58 @@ async function rn({
|
|
|
3343
3362
|
break;
|
|
3344
3363
|
}
|
|
3345
3364
|
case "peer.joined": {
|
|
3346
|
-
k && (clearTimeout(k), k = null), s("connecting"),
|
|
3365
|
+
k && (clearTimeout(k), k = null), s("connecting"), q = !!((xe = w.data) != null && xe.should_offer), q && await Ke(), $e();
|
|
3347
3366
|
break;
|
|
3348
3367
|
}
|
|
3349
3368
|
case "signal": {
|
|
3350
3369
|
if (!p) break;
|
|
3351
|
-
const { kind: ke, payload:
|
|
3370
|
+
const { kind: ke, payload: pe } = w.data || {};
|
|
3352
3371
|
if (ke === "offer")
|
|
3353
|
-
await lt(
|
|
3372
|
+
await lt(pe);
|
|
3354
3373
|
else if (ke === "answer")
|
|
3355
3374
|
try {
|
|
3356
|
-
await p.setRemoteDescription(new RTCSessionDescription(
|
|
3375
|
+
await p.setRemoteDescription(new RTCSessionDescription(pe)), await Le();
|
|
3357
3376
|
} catch {
|
|
3358
|
-
|
|
3377
|
+
N("failed", { reason: "negotiation" });
|
|
3359
3378
|
}
|
|
3360
3379
|
else if (ke === "candidate")
|
|
3361
3380
|
if (p.remoteDescription)
|
|
3362
3381
|
try {
|
|
3363
|
-
await p.addIceCandidate(new RTCIceCandidate(
|
|
3382
|
+
await p.addIceCandidate(new RTCIceCandidate(pe));
|
|
3364
3383
|
} catch {
|
|
3365
3384
|
}
|
|
3366
3385
|
else
|
|
3367
|
-
Y.push(
|
|
3368
|
-
else ke === "restart" &&
|
|
3386
|
+
Y.push(pe);
|
|
3387
|
+
else ke === "restart" && q && await z();
|
|
3369
3388
|
break;
|
|
3370
3389
|
}
|
|
3371
3390
|
case "peer.left":
|
|
3372
|
-
|
|
3391
|
+
N("ended", { reason: "peer_left" });
|
|
3373
3392
|
break;
|
|
3374
3393
|
case "error":
|
|
3375
|
-
|
|
3394
|
+
N("failed", { reason: "server", detail: (Pe = w.error) == null ? void 0 : Pe.detail });
|
|
3376
3395
|
break;
|
|
3377
3396
|
case "session.ended":
|
|
3378
|
-
|
|
3397
|
+
N("ended", { reason: "server" });
|
|
3379
3398
|
break;
|
|
3380
3399
|
}
|
|
3381
3400
|
};
|
|
3382
|
-
|
|
3401
|
+
y.onclose = () => N("ended", { reason: "disconnected" }), y.onerror = () => N("failed", { reason: "socket" });
|
|
3383
3402
|
function Be() {
|
|
3384
3403
|
if (!n) return;
|
|
3385
3404
|
const m = new Date(n).getTime() - Date.now();
|
|
3386
|
-
Number.isFinite(m) && (k = setTimeout(() =>
|
|
3405
|
+
Number.isFinite(m) && (k = setTimeout(() => N("missed"), Math.max(0, m)));
|
|
3387
3406
|
}
|
|
3388
3407
|
return {
|
|
3389
3408
|
hangUp() {
|
|
3390
|
-
te({ type: "session.end" }),
|
|
3409
|
+
te({ type: "session.end" }), N("ended", { reason: "hung_up" });
|
|
3391
3410
|
},
|
|
3392
3411
|
setMuted(m) {
|
|
3393
|
-
for (const
|
|
3412
|
+
for (const w of h.getAudioTracks()) w.enabled = !m;
|
|
3394
3413
|
return m;
|
|
3395
3414
|
},
|
|
3396
3415
|
isMuted() {
|
|
3397
|
-
return
|
|
3416
|
+
return h.getAudioTracks().every((m) => !m.enabled);
|
|
3398
3417
|
}
|
|
3399
3418
|
};
|
|
3400
3419
|
}
|
|
@@ -3402,7 +3421,7 @@ function va(t) {
|
|
|
3402
3421
|
return new Promise((e, n) => {
|
|
3403
3422
|
let o;
|
|
3404
3423
|
try {
|
|
3405
|
-
o = new WebSocket(t,
|
|
3424
|
+
o = new WebSocket(t, ya);
|
|
3406
3425
|
} catch (i) {
|
|
3407
3426
|
n(i);
|
|
3408
3427
|
return;
|
|
@@ -3468,12 +3487,12 @@ function ka() {
|
|
|
3468
3487
|
};
|
|
3469
3488
|
}
|
|
3470
3489
|
let n = !1, o = null;
|
|
3471
|
-
const i = [], r = ({ at: u, seconds:
|
|
3490
|
+
const i = [], r = ({ at: u, seconds: h, hz: y }) => {
|
|
3472
3491
|
const p = e.currentTime + u, b = e.createGain();
|
|
3473
|
-
b.connect(e.destination), b.gain.setValueAtTime(0, p), b.gain.linearRampToValueAtTime(Xe.peak, p + 0.02), b.gain.setValueAtTime(Xe.peak, p +
|
|
3474
|
-
for (const
|
|
3492
|
+
b.connect(e.destination), b.gain.setValueAtTime(0, p), b.gain.linearRampToValueAtTime(Xe.peak, p + 0.02), b.gain.setValueAtTime(Xe.peak, p + h - 0.06), b.gain.linearRampToValueAtTime(0, p + h);
|
|
3493
|
+
for (const f of y) {
|
|
3475
3494
|
const k = e.createOscillator();
|
|
3476
|
-
k.type = "sine", k.frequency.value =
|
|
3495
|
+
k.type = "sine", k.frequency.value = f, k.connect(b), k.start(p), k.stop(p + h + 0.02), i.push(k);
|
|
3477
3496
|
}
|
|
3478
3497
|
}, s = () => {
|
|
3479
3498
|
if (!n)
|
|
@@ -3541,18 +3560,18 @@ function Ca({
|
|
|
3541
3560
|
"transform:translateY(8px)",
|
|
3542
3561
|
"transition:opacity .2s ease,transform .2s ease"
|
|
3543
3562
|
].join(";");
|
|
3544
|
-
const
|
|
3545
|
-
|
|
3546
|
-
const
|
|
3547
|
-
|
|
3563
|
+
const h = document.createElement("div");
|
|
3564
|
+
h.style.cssText = "font-weight:600;font-size:14px;margin-bottom:2px", h.textContent = `${t.from || "Support"} is calling`;
|
|
3565
|
+
const y = document.createElement("div");
|
|
3566
|
+
y.style.cssText = "color:#a4abba;margin-bottom:10px", y.textContent = t.project ? `About your report ${t.reference} · ${t.project}` : `About your report ${t.reference}`;
|
|
3548
3567
|
const p = document.createElement("div");
|
|
3549
3568
|
p.style.cssText = "color:#7d8598;font-size:12px;margin-bottom:10px";
|
|
3550
3569
|
const b = document.createElement("button");
|
|
3551
3570
|
b.type = "button", b.textContent = "Answer", b.style.cssText = `${ln};background:${e};color:#fff`;
|
|
3552
|
-
const
|
|
3553
|
-
|
|
3571
|
+
const f = document.createElement("button");
|
|
3572
|
+
f.type = "button", f.textContent = "Not now", f.style.cssText = `${ln};background:#2b2f3a;color:#c8cedb`;
|
|
3554
3573
|
const k = document.createElement("div");
|
|
3555
|
-
if (k.style.cssText = "display:flex;gap:8px", k.append(b,
|
|
3574
|
+
if (k.style.cssText = "display:flex;gap:8px", k.append(b, f), u.append(h, y, p), t.recorded) {
|
|
3556
3575
|
const L = document.createElement("div");
|
|
3557
3576
|
L.style.cssText = "color:#7d8598;font-size:12px;margin-bottom:10px", L.textContent = "This call will be recorded.", u.append(L);
|
|
3558
3577
|
}
|
|
@@ -3577,7 +3596,7 @@ function Ca({
|
|
|
3577
3596
|
o == null || o();
|
|
3578
3597
|
} catch {
|
|
3579
3598
|
}
|
|
3580
|
-
}),
|
|
3599
|
+
}), f.addEventListener("click", () => {
|
|
3581
3600
|
E();
|
|
3582
3601
|
try {
|
|
3583
3602
|
i == null || i();
|
|
@@ -3589,7 +3608,7 @@ function Ca({
|
|
|
3589
3608
|
}
|
|
3590
3609
|
const dn = {
|
|
3591
3610
|
name: "@sphoro/bugcatch-web-sdk",
|
|
3592
|
-
version: "0.14.
|
|
3611
|
+
version: "0.14.3"
|
|
3593
3612
|
}, Ze = {
|
|
3594
3613
|
apiBase: "http://localhost:3000",
|
|
3595
3614
|
apiKey: null,
|
|
@@ -3653,7 +3672,7 @@ class Ln {
|
|
|
3653
3672
|
return console.warn("[BugCatch] init() called twice — ignoring the second call."), this;
|
|
3654
3673
|
if (this.config = { ...Ze, ...e }, !this.config.apiKey) throw new Error("[BugCatch] apiKey is required.");
|
|
3655
3674
|
if (!this.config.projectId) throw new Error("[BugCatch] projectId is required.");
|
|
3656
|
-
return this.consoleBuffer = Fe(this.config.consoleLimit), this.networkBuffer = Fe(this.config.networkLimit), this.config.captureConsole && this.teardown.push(eo(this.consoleBuffer)), this.config.captureNetwork && this.teardown.push(to(this.networkBuffer)), this.config.captureErrors && this.teardown.push(no(this.consoleBuffer)), this.config.widget && this.teardown.push(ra(this)), this.config.updates && se() && (this.startWatching(), queueMicrotask(() =>
|
|
3675
|
+
return this.consoleBuffer = Fe(this.config.consoleLimit), this.networkBuffer = Fe(this.config.networkLimit), this.config.captureConsole && this.teardown.push(eo(this.consoleBuffer)), this.config.captureNetwork && this.teardown.push(to(this.networkBuffer)), this.config.captureErrors && this.teardown.push(no(this.consoleBuffer)), this.config.widget && this.teardown.push(ra(this)), this.config.updates && se() && (this.startWatching(), queueMicrotask(() => V(this, B, me).call(this))), this.started = !0, this;
|
|
3657
3676
|
}
|
|
3658
3677
|
/**
|
|
3659
3678
|
* Open the update stream. Idempotent — init() and a first report both reach
|
|
@@ -3665,22 +3684,22 @@ class Ln {
|
|
|
3665
3684
|
apiBase: this.config.apiBase,
|
|
3666
3685
|
onUpdate: (n) => {
|
|
3667
3686
|
if (n != null && n.incomingCall) {
|
|
3668
|
-
|
|
3687
|
+
V(this, B, Rn).call(this, n);
|
|
3669
3688
|
return;
|
|
3670
3689
|
}
|
|
3671
3690
|
if (n != null && n.callWithdrawn) {
|
|
3672
|
-
|
|
3691
|
+
V(this, B, Ge).call(this, n.callWithdrawn.callId);
|
|
3673
3692
|
return;
|
|
3674
3693
|
}
|
|
3675
3694
|
const o = To(n);
|
|
3676
|
-
typeof this.config.onUpdate == "function" && this.config.onUpdate(o), this.emit("update", o),
|
|
3695
|
+
typeof this.config.onUpdate == "function" && this.config.onUpdate(o), this.emit("update", o), V(this, B, me).call(this);
|
|
3677
3696
|
}
|
|
3678
3697
|
}), this.teardown.push(() => {
|
|
3679
3698
|
var n;
|
|
3680
3699
|
return (n = this.stopWatching) == null ? void 0 : n.call(this);
|
|
3681
|
-
}), this.teardown.push(() =>
|
|
3700
|
+
}), this.teardown.push(() => V(this, B, Ge).call(this));
|
|
3682
3701
|
const e = (n) => {
|
|
3683
|
-
(n.key === ot || n.key === null) &&
|
|
3702
|
+
(n.key === ot || n.key === null) && V(this, B, me).call(this);
|
|
3684
3703
|
};
|
|
3685
3704
|
return window.addEventListener("storage", e), this.teardown.push(() => window.removeEventListener("storage", e)), this;
|
|
3686
3705
|
}
|
|
@@ -3737,7 +3756,7 @@ class Ln {
|
|
|
3737
3756
|
* knows when its reader has seen one, so it has to say.
|
|
3738
3757
|
*/
|
|
3739
3758
|
markUpdateRead(e) {
|
|
3740
|
-
return Io(e),
|
|
3759
|
+
return Io(e), V(this, B, me).call(this), this;
|
|
3741
3760
|
}
|
|
3742
3761
|
/**
|
|
3743
3762
|
* Mark everything about one report read.
|
|
@@ -3746,11 +3765,11 @@ class Ln {
|
|
|
3746
3765
|
* the thread opens; an integration with its own report view should too.
|
|
3747
3766
|
*/
|
|
3748
3767
|
markReportRead(e) {
|
|
3749
|
-
return Mo(e),
|
|
3768
|
+
return Mo(e), V(this, B, me).call(this), this;
|
|
3750
3769
|
}
|
|
3751
3770
|
/** Mark everything read. The "clear all" behind your own notification list. */
|
|
3752
3771
|
markUpdatesRead() {
|
|
3753
|
-
return
|
|
3772
|
+
return wn(), V(this, B, me).call(this), this;
|
|
3754
3773
|
}
|
|
3755
3774
|
/**
|
|
3756
3775
|
* One report in full, with its timeline — every step from filing to now.
|
|
@@ -3761,7 +3780,7 @@ class Ln {
|
|
|
3761
3780
|
* Resolves to null when this browser cannot prove it filed that report.
|
|
3762
3781
|
*/
|
|
3763
3782
|
async verifyFix(e, { result: n, resolvedAt: o, note: i }) {
|
|
3764
|
-
const r = n === "STILL_HAPPENING" ? await
|
|
3783
|
+
const r = n === "STILL_HAPPENING" ? await V(this, B, Je).call(this, {}) : {};
|
|
3765
3784
|
return Yo({ apiBase: this.config.apiBase, bugId: e, result: n, resolvedAt: o, note: i, metadata: r.metadata, logs: r.logs });
|
|
3766
3785
|
}
|
|
3767
3786
|
myReport(e) {
|
|
@@ -3898,7 +3917,7 @@ class Ln {
|
|
|
3898
3917
|
try {
|
|
3899
3918
|
if (!await this.callKind())
|
|
3900
3919
|
throw new Error((n = this.config.user) != null && n.email ? "[BugCatch] calling is not available on this project." : "[BugCatch] a call needs to know who is calling — call identify() with an email first.");
|
|
3901
|
-
return await
|
|
3920
|
+
return await V(this, B, An).call(this, e);
|
|
3902
3921
|
} finally {
|
|
3903
3922
|
this.callStarting = !1;
|
|
3904
3923
|
}
|
|
@@ -3956,7 +3975,7 @@ class Ln {
|
|
|
3956
3975
|
*/
|
|
3957
3976
|
forgetReports() {
|
|
3958
3977
|
var e;
|
|
3959
|
-
return (e = this.stopWatching) == null || e.call(this), this.stopWatching = null, this.endCall(), Ee(),
|
|
3978
|
+
return (e = this.stopWatching) == null || e.call(this), this.stopWatching = null, this.endCall(), Ee(), V(this, B, me).call(this), this;
|
|
3960
3979
|
}
|
|
3961
3980
|
/**
|
|
3962
3981
|
* Attach the signed-in user so reports say who hit the bug.
|
|
@@ -4009,7 +4028,7 @@ class Ln {
|
|
|
4009
4028
|
storageKey: b.storageKey,
|
|
4010
4029
|
mime: tt(b.mime, et)
|
|
4011
4030
|
}));
|
|
4012
|
-
let u = await
|
|
4031
|
+
let u = await V(this, B, Je).call(this, {
|
|
4013
4032
|
title: e.trim(),
|
|
4014
4033
|
description: n,
|
|
4015
4034
|
priority: o,
|
|
@@ -4022,7 +4041,7 @@ class Ln {
|
|
|
4022
4041
|
if (b === !1) return { cancelled: !0 };
|
|
4023
4042
|
b && typeof b == "object" && (u = b);
|
|
4024
4043
|
}
|
|
4025
|
-
const
|
|
4044
|
+
const h = he(this.config.projectId), y = await fetch(`${this.config.apiBase}/ingest/bugs`, {
|
|
4026
4045
|
method: "POST",
|
|
4027
4046
|
headers: {
|
|
4028
4047
|
"Content-Type": "application/json",
|
|
@@ -4031,21 +4050,21 @@ class Ln {
|
|
|
4031
4050
|
// address from here rather than from the payload when it is — on a
|
|
4032
4051
|
// project that requires sign-in, letting the page name a different
|
|
4033
4052
|
// reporter would undo the requirement.
|
|
4034
|
-
...
|
|
4053
|
+
...h != null && h.token ? { "X-BugCatch-Session": h.token } : {}
|
|
4035
4054
|
},
|
|
4036
4055
|
body: JSON.stringify(u)
|
|
4037
4056
|
});
|
|
4038
|
-
if (
|
|
4057
|
+
if (y.status === 401 && h && kt(this.config.projectId), !y.ok) {
|
|
4039
4058
|
let b = "";
|
|
4040
4059
|
try {
|
|
4041
|
-
const
|
|
4042
|
-
b = Array.isArray(
|
|
4060
|
+
const f = await y.json();
|
|
4061
|
+
b = Array.isArray(f.message) ? f.message.join(", ") : f.message || "";
|
|
4043
4062
|
} catch {
|
|
4044
4063
|
}
|
|
4045
|
-
throw new Error(`[BugCatch] report failed (HTTP ${
|
|
4064
|
+
throw new Error(`[BugCatch] report failed (HTTP ${y.status})${b ? ": " + b : ""}`);
|
|
4046
4065
|
}
|
|
4047
|
-
const p = await
|
|
4048
|
-
return p.watchToken && (
|
|
4066
|
+
const p = await y.json();
|
|
4067
|
+
return p.watchToken && (St(p.watchToken), this.config.updates && this.startWatching()), p;
|
|
4049
4068
|
}
|
|
4050
4069
|
/**
|
|
4051
4070
|
* What this project asks of the person reporting, and who this browser is
|
|
@@ -4068,7 +4087,7 @@ class Ln {
|
|
|
4068
4087
|
apiBase: this.config.apiBase,
|
|
4069
4088
|
apiKey: this.config.apiKey,
|
|
4070
4089
|
projectId: this.config.projectId,
|
|
4071
|
-
token: (e =
|
|
4090
|
+
token: (e = he(this.config.projectId)) == null ? void 0 : e.token
|
|
4072
4091
|
});
|
|
4073
4092
|
}
|
|
4074
4093
|
/**
|
|
@@ -4103,7 +4122,7 @@ class Ln {
|
|
|
4103
4122
|
* the server. Use loginState() where that matters.
|
|
4104
4123
|
*/
|
|
4105
4124
|
signedInAs() {
|
|
4106
|
-
const e =
|
|
4125
|
+
const e = he(this.config.projectId);
|
|
4107
4126
|
return e ? { email: e.email, name: e.name } : null;
|
|
4108
4127
|
}
|
|
4109
4128
|
/**
|
|
@@ -4155,7 +4174,7 @@ class Ln {
|
|
|
4155
4174
|
*/
|
|
4156
4175
|
async signOut() {
|
|
4157
4176
|
var o;
|
|
4158
|
-
const e =
|
|
4177
|
+
const e = he(this.config.projectId), n = await Co({
|
|
4159
4178
|
apiBase: this.config.apiBase,
|
|
4160
4179
|
apiKey: this.config.apiKey,
|
|
4161
4180
|
projectId: this.config.projectId,
|
|
@@ -4178,7 +4197,7 @@ class Ln {
|
|
|
4178
4197
|
apiBase: this.config.apiBase,
|
|
4179
4198
|
apiKey: this.config.apiKey,
|
|
4180
4199
|
projectId: this.config.projectId,
|
|
4181
|
-
sessionToken: (e =
|
|
4200
|
+
sessionToken: (e = he(this.config.projectId)) == null ? void 0 : e.token
|
|
4182
4201
|
});
|
|
4183
4202
|
}
|
|
4184
4203
|
/**
|
|
@@ -4194,7 +4213,7 @@ class Ln {
|
|
|
4194
4213
|
apiKey: this.config.apiKey,
|
|
4195
4214
|
projectId: this.config.projectId,
|
|
4196
4215
|
q: e || "",
|
|
4197
|
-
sessionToken: (o =
|
|
4216
|
+
sessionToken: (o = he(this.config.projectId)) == null ? void 0 : o.token,
|
|
4198
4217
|
signal: n
|
|
4199
4218
|
});
|
|
4200
4219
|
}
|
|
@@ -4213,7 +4232,7 @@ class Ln {
|
|
|
4213
4232
|
*/
|
|
4214
4233
|
async meToo(e, { email: n, name: o } = {}) {
|
|
4215
4234
|
var s, l;
|
|
4216
|
-
const i =
|
|
4235
|
+
const i = he(this.config.projectId), r = await Yt();
|
|
4217
4236
|
return Fo({
|
|
4218
4237
|
apiBase: this.config.apiBase,
|
|
4219
4238
|
apiKey: this.config.apiKey,
|
|
@@ -4316,28 +4335,28 @@ me = function() {
|
|
|
4316
4335
|
...s.length ? { references: s } : {}
|
|
4317
4336
|
};
|
|
4318
4337
|
}, Bn = async function() {
|
|
4319
|
-
const e =
|
|
4338
|
+
const e = he(this.config.projectId);
|
|
4320
4339
|
let n;
|
|
4321
4340
|
try {
|
|
4322
4341
|
n = await Qo({
|
|
4323
4342
|
apiBase: this.config.apiBase,
|
|
4324
4343
|
apiKey: this.config.apiKey,
|
|
4325
4344
|
token: e == null ? void 0 : e.token,
|
|
4326
|
-
payload: await
|
|
4345
|
+
payload: await V(this, B, Je).call(this, {})
|
|
4327
4346
|
});
|
|
4328
4347
|
} catch (o) {
|
|
4329
|
-
throw o.status === 401 && e &&
|
|
4348
|
+
throw o.status === 401 && e && kt(this.config.projectId), o;
|
|
4330
4349
|
}
|
|
4331
|
-
return n.watchToken && (
|
|
4350
|
+
return n.watchToken && (St(n.watchToken), this.config.updates && this.startWatching()), n;
|
|
4332
4351
|
}, An = async function(e) {
|
|
4333
|
-
if (!
|
|
4352
|
+
if (!Et())
|
|
4334
4353
|
throw new Error("[BugCatch] this browser cannot make live calls.");
|
|
4335
|
-
const n = await
|
|
4354
|
+
const n = await Ct();
|
|
4336
4355
|
let o, i = null;
|
|
4337
4356
|
try {
|
|
4338
4357
|
if (e)
|
|
4339
4358
|
o = await jo({ apiBase: this.config.apiBase, bugId: e });
|
|
4340
|
-
else if (i = await
|
|
4359
|
+
else if (i = await V(this, B, Bn).call(this), e = i.id, o = i.live_call, !(o != null && o.realtime_url)) {
|
|
4341
4360
|
const s = new Error(`[BugCatch] the report was filed, but the team could not be rung${i.call_error ? `: ${i.call_error}` : "."}`);
|
|
4342
4361
|
throw s.filed = i, s.reason = i.call_error || null, s;
|
|
4343
4362
|
}
|
|
@@ -4372,14 +4391,14 @@ me = function() {
|
|
|
4372
4391
|
Rn = function(e) {
|
|
4373
4392
|
var i;
|
|
4374
4393
|
const n = e.incomingCall;
|
|
4375
|
-
if (!this.config.voice || !
|
|
4376
|
-
|
|
4394
|
+
if (!this.config.voice || !Et() || ((i = this.ringing) == null ? void 0 : i.callId) === n.callId || this.call || this.callStarting) return;
|
|
4395
|
+
V(this, B, Ge).call(this);
|
|
4377
4396
|
const o = Ca({
|
|
4378
4397
|
call: n,
|
|
4379
4398
|
accent: this.config.accent,
|
|
4380
4399
|
position: this.config.widgetPosition,
|
|
4381
4400
|
onAnswer: () => {
|
|
4382
|
-
|
|
4401
|
+
V(this, B, Qn).call(this, e.bugId, n);
|
|
4383
4402
|
},
|
|
4384
4403
|
onDecline: () => {
|
|
4385
4404
|
this.ringing = null, Jt({
|
|
@@ -4416,7 +4435,7 @@ Ge = function(e) {
|
|
|
4416
4435
|
this.callStarting = !0;
|
|
4417
4436
|
let o;
|
|
4418
4437
|
try {
|
|
4419
|
-
o = await
|
|
4438
|
+
o = await Ct();
|
|
4420
4439
|
} catch (r) {
|
|
4421
4440
|
this.callStarting = !1, Jt({ apiBase: this.config.apiBase, bugId: e, callId: n.callId }), this.emit("incoming-call", { bugId: e, callId: n.callId, state: "failed", error: r });
|
|
4422
4441
|
return;
|