@sailfish-ai/recorder 1.10.5 → 1.10.7

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.
@@ -0,0 +1,2259 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") {
10
+ for (let key of __getOwnPropNames(from))
11
+ if (!__hasOwnProp.call(to, key) && key !== except)
12
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
13
+ }
14
+ return to;
15
+ };
16
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
17
+ // If the importer is in node compatibility mode or this is not an ESM
18
+ // file that has been converted to a CommonJS file using a Babel-
19
+ // compatible transform (i.e. "__esModule" has not been set), then set
20
+ // "default" to the CommonJS "module.exports" for node compatibility.
21
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
22
+ mod
23
+ ));
24
+ const e = require("reconnecting-websocket"), t = require("@sailfish-rrweb/types");
25
+ function readDebugFlag() {
26
+ var _a;
27
+ try {
28
+ const e2 = globalThis;
29
+ if ("boolean" == typeof e2.__SAILFISH_DEBUG__) return e2.__SAILFISH_DEBUG__;
30
+ } catch {
31
+ }
32
+ try {
33
+ const e2 = "undefined" != typeof process ? process : void 0;
34
+ if (null != ((_a = e2 == null ? void 0 : e2.env) == null ? void 0 : _a.SAILFISH_DEBUG)) {
35
+ const t2 = String(e2.env.SAILFISH_DEBUG).toLowerCase();
36
+ return "1" === t2 || "true" === t2 || "yes" === t2;
37
+ }
38
+ } catch {
39
+ }
40
+ try {
41
+ const e2 = globalThis.__SAILFISH_DEBUG_DEFINE__;
42
+ if ("boolean" == typeof e2) return e2;
43
+ } catch {
44
+ }
45
+ return false;
46
+ }
47
+ function uuidv4() {
48
+ if ("undefined" != typeof crypto && "function" == typeof crypto.randomUUID) return crypto.randomUUID();
49
+ if ("undefined" != typeof crypto && "function" == typeof crypto.getRandomValues) {
50
+ const e2 = new Uint8Array(16);
51
+ crypto.getRandomValues(e2), e2[6] = 15 & e2[6] | 64, e2[8] = 63 & e2[8] | 128;
52
+ const t2 = Array.from(e2, (e3) => e3.toString(16).padStart(2, "0")).join("");
53
+ return t2.slice(0, 8) + "-" + t2.slice(8, 12) + "-" + t2.slice(12, 16) + "-" + t2.slice(16, 20) + "-" + t2.slice(20);
54
+ }
55
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (e2) => {
56
+ const t2 = 16 * Math.random() | 0;
57
+ return ("x" === e2 ? t2 : 3 & t2 | 8).toString(16);
58
+ });
59
+ }
60
+ const n = "X-Sf3-Rid", i = 0, o = 1, s = 2, a = 3, r = 4, l = "recordingEvents";
61
+ let c = null;
62
+ function openDb$1() {
63
+ return (function hasIndexedDB$1() {
64
+ return "undefined" != typeof globalThis && !!globalThis.indexedDB;
65
+ })() ? c || (c = new Promise((e2) => {
66
+ try {
67
+ const t2 = globalThis.indexedDB.open("leapsEventDB", 1);
68
+ t2.onupgradeneeded = () => {
69
+ const e3 = t2.result;
70
+ e3.objectStoreNames.contains(l) || e3.createObjectStore(l, { keyPath: "id", autoIncrement: true });
71
+ }, t2.onsuccess = () => e2(t2.result), t2.onerror = () => e2(null), t2.onblocked = () => {
72
+ e2(null);
73
+ };
74
+ } catch {
75
+ e2(null);
76
+ }
77
+ }), c) : Promise.resolve(null);
78
+ }
79
+ function withStore$1(e2, t2) {
80
+ return openDb$1().then((n2) => n2 ? new Promise((i2) => {
81
+ try {
82
+ const o2 = n2.transaction(l, e2), s2 = o2.objectStore(l);
83
+ Promise.resolve(t2(s2)).then((e3) => {
84
+ o2.oncomplete = () => i2(e3), o2.onerror = () => i2(null);
85
+ }).catch(() => i2(null));
86
+ } catch {
87
+ i2(null);
88
+ }
89
+ }) : null);
90
+ }
91
+ async function deleteEventsByIds(e2) {
92
+ await withStore$1("readwrite", async (t2) => {
93
+ for (const n2 of e2) t2.delete(n2);
94
+ });
95
+ }
96
+ const d = "notifyMessages";
97
+ let u = null;
98
+ function openDb() {
99
+ return (function hasIndexedDB() {
100
+ return "undefined" != typeof globalThis && !!globalThis.indexedDB;
101
+ })() ? u || (u = new Promise((e2) => {
102
+ try {
103
+ const t2 = globalThis.indexedDB.open("leapsNotifyDB", 1);
104
+ t2.onupgradeneeded = () => {
105
+ const e3 = t2.result;
106
+ e3.objectStoreNames.contains(d) || e3.createObjectStore(d, { keyPath: "id", autoIncrement: true });
107
+ }, t2.onsuccess = () => e2(t2.result), t2.onerror = () => e2(null), t2.onblocked = () => e2(null);
108
+ } catch {
109
+ e2(null);
110
+ }
111
+ }), u) : Promise.resolve(null);
112
+ }
113
+ async function withStore(e2, t2) {
114
+ const n2 = await openDb();
115
+ return n2 ? new Promise((i2) => {
116
+ try {
117
+ const o2 = n2.transaction(d, e2), s2 = o2.objectStore(d);
118
+ Promise.resolve(t2(s2)).then((e3) => {
119
+ o2.oncomplete = () => i2(e3), o2.onerror = () => i2(null);
120
+ }).catch(() => i2(null));
121
+ } catch {
122
+ i2(null);
123
+ }
124
+ }) : null;
125
+ }
126
+ async function saveNotifyMessageToIDB(e2) {
127
+ await withStore("readwrite", (t2) => {
128
+ t2.add({ value: e2 });
129
+ });
130
+ }
131
+ async function deleteNotifyMessageById(e2) {
132
+ await withStore("readwrite", (t2) => {
133
+ t2.delete(e2);
134
+ });
135
+ }
136
+ const p = "undefined" != typeof globalThis && void 0 !== globalThis.window, f = "undefined" != typeof globalThis && void 0 !== globalThis.document, g = "undefined" != typeof globalThis && "localStorage" in globalThis, m = "undefined" != typeof globalThis && "sessionStorage" in globalThis, h = "sailfishSessionId", y = "__sailfish_refresh__";
137
+ let b = null;
138
+ function getOrSetSessionId() {
139
+ if (!p) return uuidv4();
140
+ if (b) return b;
141
+ const e2 = window.name.startsWith(y);
142
+ if (e2 && (window.name = window.name.substring(20)), e2) {
143
+ const e3 = window.sessionStorage.getItem(h);
144
+ if (e3) return b = e3, e3;
145
+ }
146
+ const t2 = uuidv4();
147
+ b = t2;
148
+ try {
149
+ window.sessionStorage.setItem(h, t2);
150
+ } catch (e3) {
151
+ }
152
+ return t2;
153
+ }
154
+ let S = false;
155
+ function buildBatches(e2, t2, n2) {
156
+ const i2 = {};
157
+ for (const t3 of e2) {
158
+ const e3 = t3.data.sessionId || "unknown";
159
+ i2[e3] || (i2[e3] = []), i2[e3].push(t3);
160
+ }
161
+ const o2 = [];
162
+ for (const e3 in i2) {
163
+ const s2 = i2[e3];
164
+ let a2 = [], r2 = 0;
165
+ for (const e4 of s2) {
166
+ const i3 = t2(e4);
167
+ r2 + i3 > n2 && (a2.length > 0 && (o2.push(a2), a2 = [], r2 = 0), i3 > n2) || (a2.push(e4), r2 += i3);
168
+ }
169
+ a2.length > 0 && o2.push(a2);
170
+ }
171
+ return o2;
172
+ }
173
+ function eventSize(e2) {
174
+ return JSON.stringify(e2).length;
175
+ }
176
+ function withAppUrlMetadata(e2) {
177
+ var _a;
178
+ return { ...e2 ?? {}, appUrl: (e2 == null ? void 0 : e2.appUrl) ?? ((_a = window == null ? void 0 : window.location) == null ? void 0 : _a.href) };
179
+ }
180
+ exports.nowTimestamp = Date.now, /[1-9][0-9]{12}/.test(Date.now().toString()) || (exports.nowTimestamp = () => (/* @__PURE__ */ new Date()).getTime());
181
+ const w = readDebugFlag(), v = "per_session";
182
+ let k = null, x = null, I = false, T = null, E = null, C = "", $ = "", F = false;
183
+ function _updateHrefCache() {
184
+ C = window.location.href, $ = window.location.origin + window.location.pathname;
185
+ }
186
+ function ensureHrefCache() {
187
+ if (F || "undefined" == typeof window) return;
188
+ F = true, _updateHrefCache(), window.addEventListener("popstate", _updateHrefCache), window.addEventListener("hashchange", _updateHrefCache);
189
+ const e2 = history.pushState;
190
+ history.pushState = function(...t3) {
191
+ e2.apply(this, t3), _updateHrefCache();
192
+ };
193
+ const t2 = history.replaceState;
194
+ history.replaceState = function(...e3) {
195
+ t2.apply(this, e3), _updateHrefCache();
196
+ };
197
+ }
198
+ function getCachedHref() {
199
+ return C || ("undefined" != typeof window ? window.location.href : "");
200
+ }
201
+ function getCachedHrefNoQuery() {
202
+ return $ || ("undefined" != typeof window ? window.location.origin + window.location.pathname : "");
203
+ }
204
+ const M = [];
205
+ let L = null;
206
+ function queueEventForIDB(e2) {
207
+ M.push(e2), M.length >= 50 ? _flushIDBQueue() : L || (L = setTimeout(_flushIDBQueue, 100));
208
+ }
209
+ function _flushIDBQueue() {
210
+ if (L && (clearTimeout(L), L = null), 0 === M.length) return;
211
+ !(async function saveEventsToIDB(e2) {
212
+ await withStore$1("readwrite", async (t2) => {
213
+ for (const n2 of e2) t2.add({ timestamp: Date.now(), data: n2 });
214
+ });
215
+ })(M.splice(0));
216
+ }
217
+ let A = false, R = null, D = null, _ = false;
218
+ const P = "sailfish_funcspan_global_state";
219
+ function wsSendPayload(e2) {
220
+ if (!isWebSocketOpen(x)) return false;
221
+ if (k) try {
222
+ return k.postMessage({ type: "send", payload: e2 }), true;
223
+ } catch {
224
+ return false;
225
+ }
226
+ try {
227
+ return x.send(JSON.stringify(e2)), true;
228
+ } catch {
229
+ return false;
230
+ }
231
+ }
232
+ function wsSendRaw(e2) {
233
+ if (!isWebSocketOpen(x)) return false;
234
+ if (k) try {
235
+ return k.postMessage({ type: "sendRaw", payload: e2 }), true;
236
+ } catch {
237
+ return false;
238
+ }
239
+ try {
240
+ return x.send(e2), true;
241
+ } catch {
242
+ return false;
243
+ }
244
+ }
245
+ function saveGlobalFuncSpanState(e2, t2) {
246
+ try {
247
+ if ("undefined" == typeof localStorage) return;
248
+ const n2 = { enabled: e2, expirationTimestampMs: t2, savedAt: Date.now() };
249
+ localStorage.setItem(P, JSON.stringify(n2)), w && console.log("[Sailfish] Saved funcSpan state to localStorage:", n2);
250
+ } catch (e3) {
251
+ w && console.warn("[Sailfish] Failed to save funcSpan state to localStorage:", e3);
252
+ }
253
+ }
254
+ function clearGlobalFuncSpanState() {
255
+ try {
256
+ if ("undefined" == typeof localStorage) return;
257
+ localStorage.removeItem(P), w && console.log("[Sailfish] Cleared funcSpan state from localStorage");
258
+ } catch (e2) {
259
+ w && console.warn("[Sailfish] Failed to clear funcSpan state from localStorage:", e2);
260
+ }
261
+ }
262
+ function clearStaleFuncSpanState() {
263
+ A = false, D = null, _ = false, clearGlobalFuncSpanState(), w && console.log("[Sailfish] Cleared stale function span tracking state (backend validation failed)");
264
+ }
265
+ let B = false;
266
+ function restoreFuncSpanState() {
267
+ if (B) return;
268
+ B = true;
269
+ const e2 = (function loadGlobalFuncSpanState() {
270
+ try {
271
+ if ("undefined" == typeof localStorage) return null;
272
+ const e3 = localStorage.getItem(P);
273
+ if (!e3) return null;
274
+ const t2 = JSON.parse(e3);
275
+ return w && console.log("[Sailfish] Loaded funcSpan state from localStorage:", t2), t2;
276
+ } catch (e3) {
277
+ return w && console.warn("[Sailfish] Failed to load funcSpan state from localStorage:", e3), null;
278
+ }
279
+ })();
280
+ if (e2 && e2.enabled) if (A = true, D = e2.expirationTimestampMs, _ = false, w && console.log("[Sailfish] Restored global function span tracking from localStorage:", { enabled: true, expirationTime: D }), null !== D) {
281
+ Date.now() >= D ? (A = false, D = null, clearGlobalFuncSpanState(), w && console.log("[Sailfish] Persisted tracking already expired, cleared state")) : w && console.log("[Sailfish] Function span tracking is active and valid (temporary until WebSocket confirms)");
282
+ } else w && console.log("[Sailfish] Function span tracking is active (no expiration, temporary until WebSocket confirms)");
283
+ }
284
+ function isWebSocketOpen(e2) {
285
+ return (e2 == null ? void 0 : e2.readyState) === WebSocket.OPEN;
286
+ }
287
+ async function flushNotifyQueue() {
288
+ const e2 = await (async function getAllNotifyMessages() {
289
+ return await withStore("readonly", (e3) => new Promise((t2) => {
290
+ const n2 = e3.getAll();
291
+ n2.onsuccess = () => t2(n2.result), n2.onerror = () => t2([]);
292
+ })) ?? [];
293
+ })();
294
+ if (isWebSocketOpen(x)) try {
295
+ for (const t2 of e2) {
296
+ if (!wsSendRaw(t2.value)) break;
297
+ await deleteNotifyMessageById(t2.id);
298
+ }
299
+ } catch (e3) {
300
+ }
301
+ }
302
+ async function flushBufferedEvents() {
303
+ if (isWebSocketOpen(x)) if (T) await T;
304
+ else {
305
+ T = (async () => {
306
+ var _a, _b;
307
+ const e2 = await (async function getAllIndexedEvents() {
308
+ return await withStore$1("readonly", (e3) => new Promise((t3) => {
309
+ const n2 = e3.getAll();
310
+ n2.onsuccess = () => t3(n2.result), n2.onerror = () => t3([]);
311
+ })) ?? [];
312
+ })(), t2 = {};
313
+ for (const n2 of e2) {
314
+ const e3 = ((_b = (_a = n2 == null ? void 0 : n2.data) == null ? void 0 : _a.data) == null ? void 0 : _b.sessionId) ?? "unknown-session";
315
+ t2[e3] || (t2[e3] = []), t2[e3].push(n2);
316
+ }
317
+ for (const e3 of Object.values(t2)) {
318
+ const t3 = buildBatches(e3, (e4) => eventSize(e4.data), 52428800);
319
+ for (const e4 of t3) {
320
+ if (!isWebSocketOpen(x)) break;
321
+ const t4 = e4.map((e5) => (e5.data.appUrl || (e5.data.appUrl = getCachedHref()), e5.data)), n2 = e4.map((e5) => e5.id).filter((e5) => null != e5);
322
+ try {
323
+ wsSendPayload({ type: "events", events: t4, mapUuid: window.sfMapUuid }) && await deleteEventsByIds(n2);
324
+ } catch (e5) {
325
+ }
326
+ }
327
+ }
328
+ })();
329
+ try {
330
+ await T;
331
+ } finally {
332
+ T = null;
333
+ }
334
+ }
335
+ }
336
+ function sendEvent(e2) {
337
+ e2.app_url || (e2.app_url = getCachedHref()), !I && isWebSocketOpen(x) && wsSendPayload({ type: "event", event: e2, mapUuid: window.sfMapUuid }) || queueEventForIDB(e2);
338
+ }
339
+ function handleWsOpen() {
340
+ w && (console.log("[Sailfish] WebSocket connection opened"), console.log("[Sailfish] Function span tracking state: " + (A ? "ENABLED" : "DISABLED"))), (async () => {
341
+ try {
342
+ I = true, await flushNotifyQueue(), await flushBufferedEvents();
343
+ } finally {
344
+ I = false;
345
+ }
346
+ null != E && clearInterval(E), E = window.setInterval(() => {
347
+ flushBufferedEvents();
348
+ }, 2e3);
349
+ })();
350
+ }
351
+ function handleWsClose() {
352
+ null != E && (clearInterval(E), E = null), w && console.log("[Sailfish] WebSocket closed");
353
+ }
354
+ function handleWsMessage(e2) {
355
+ try {
356
+ const t2 = JSON.parse(e2);
357
+ if ("funcSpanTrackingControl" === t2.type) if (w && console.log("[Sailfish] Received funcSpanTrackingControl message:", { enabled: t2.enabled, timeoutSeconds: t2.timeoutSeconds, expirationTimestampMs: t2.expirationTimestampMs }), null !== R && (window.clearTimeout(R), R = null), A = t2.enabled, _ = false, w && console.log("[Sailfish] Function span tracking " + (t2.enabled ? "ENABLED (GLOBAL)" : "DISABLED (GLOBAL)")), t2.enabled) {
358
+ if (t2.expirationTimestampMs) {
359
+ D = t2.expirationTimestampMs;
360
+ const e3 = Date.now(), n2 = D - e3;
361
+ w && console.log(`[Sailfish] Server expiration timestamp: ${D}, ms until expiration: ${n2}`), n2 > 0 ? (saveGlobalFuncSpanState(true, D), R = window.setTimeout(() => {
362
+ _ || (A = false, D = null, clearGlobalFuncSpanState(), w && console.log("[Sailfish] GLOBAL function span tracking auto-disabled at server expiration time"), wsSendPayload({ type: "funcSpanTrackingExpired", sessionId: getOrSetSessionId(), expiredAt: Date.now() }), w && console.log("[Sailfish] Notified backend that function span tracking expired"));
363
+ }, n2)) : (A = false, D = null, clearGlobalFuncSpanState(), w && console.log("[Sailfish] Tracking already expired, not enabling"));
364
+ } else {
365
+ const e3 = t2.timeoutSeconds || 3600;
366
+ e3 > 0 && (D = Date.now() + 1e3 * e3, saveGlobalFuncSpanState(true, D), R = window.setTimeout(() => {
367
+ _ || (A = false, D = null, clearGlobalFuncSpanState(), w && console.log(`[Sailfish] GLOBAL function span tracking auto-disabled after ${e3}s (legacy)`), wsSendPayload({ type: "funcSpanTrackingExpired", sessionId: getOrSetSessionId(), expiredAt: Date.now() }), w && console.log("[Sailfish] Notified backend that function span tracking expired (legacy timeout)"));
368
+ }, 1e3 * e3));
369
+ }
370
+ try {
371
+ const e3 = getOrSetSessionId();
372
+ wsSendPayload({ type: "funcSpanTrackingSessionReport", sessionId: e3, enabled: true, configurationType: "global" }), w && console.log(`[Sailfish] GLOBAL tracking session report sent for session: ${e3}`);
373
+ } catch (e3) {
374
+ w && console.warn("[Sailfish] Failed to send GLOBAL tracking session report:", e3);
375
+ }
376
+ } else D = null, clearGlobalFuncSpanState();
377
+ } catch (e3) {
378
+ }
379
+ }
380
+ function initializeWebSocket(t2, n2, i2, o2, s2 = false) {
381
+ ensureHrefCache();
382
+ const a2 = (function getWebSocketHost(e2) {
383
+ const t3 = new URL(e2);
384
+ return `${t3.hostname}${t3.port ? `:${t3.port}` : ""}`;
385
+ })(t2);
386
+ let r2 = `${"https:" === new URL(t2).protocol ? "wss" : "ws"}://${a2}/ws/notify/?apiKey=${n2}&sessionId=${i2}&sender=JS%2FTS&version=1.10.7`;
387
+ if (o2 && (r2 += `&envValue=${encodeURIComponent(o2)}`), k = s2 ? (function tryCreateWsWorker() {
388
+ if ("undefined" == typeof Worker) return null;
389
+ try {
390
+ const e2 = new Blob(['\nvar ws = null;\nvar wsUrl = "";\nvar reconnectTimer = null;\nvar reconnectDelay = 1000;\nvar MAX_RECONNECT_DELAY = 30000;\nvar CONNECTION_TIMEOUT = 30000;\nvar queue = [];\nvar MAX_QUEUE = 500;\n\nfunction enqueue(str) {\n if (queue.length >= MAX_QUEUE) queue.shift();\n queue.push(str);\n}\n\nfunction drain() {\n while (queue.length > 0) {\n if (!ws || ws.readyState !== 1) break;\n try { ws.send(queue.shift()); } catch (e) { break; }\n }\n}\n\nfunction connect() {\n if (ws && (ws.readyState === 0 || ws.readyState === 1)) return;\n try { ws = new WebSocket(wsUrl); } catch (e) { scheduleReconnect(); return; }\n var tid = setTimeout(function() { if (ws && ws.readyState === 0) ws.close(); }, CONNECTION_TIMEOUT);\n ws.onopen = function() {\n clearTimeout(tid);\n reconnectDelay = 1000;\n drain();\n postMessage({ type: "open" });\n };\n ws.onclose = function() {\n clearTimeout(tid);\n ws = null;\n postMessage({ type: "close" });\n scheduleReconnect();\n };\n ws.onerror = function() {};\n ws.onmessage = function(e) {\n postMessage({ type: "message", data: e.data });\n };\n}\n\nfunction scheduleReconnect() {\n if (reconnectTimer) return;\n reconnectTimer = setTimeout(function() {\n reconnectTimer = null;\n reconnectDelay = Math.min(reconnectDelay * 1.5, MAX_RECONNECT_DELAY);\n connect();\n }, reconnectDelay);\n}\n\nself.onmessage = function(e) {\n var msg = e.data;\n if (msg.type === "init") {\n wsUrl = msg.wsUrl;\n connect();\n } else if (msg.type === "send") {\n try {\n var s = JSON.stringify(msg.payload);\n if (ws && ws.readyState === 1) { ws.send(s); }\n else { enqueue(s); }\n } catch (e) {}\n } else if (msg.type === "sendRaw") {\n if (ws && ws.readyState === 1) {\n try { ws.send(msg.payload); } catch (e) { enqueue(msg.payload); }\n } else { enqueue(msg.payload); }\n } else if (msg.type === "close") {\n if (reconnectTimer) { clearTimeout(reconnectTimer); reconnectTimer = null; }\n if (ws) { ws.close(); ws = null; }\n }\n};\n'], { type: "application/javascript" }), t3 = URL.createObjectURL(e2), n3 = new Worker(t3);
391
+ return URL.revokeObjectURL(t3), n3;
392
+ } catch {
393
+ return null;
394
+ }
395
+ })() : null, k) {
396
+ const e2 = k, t3 = { readyState: WebSocket.CONNECTING, close: () => {
397
+ t3.readyState = WebSocket.CLOSED, e2.postMessage({ type: "close" }), e2.terminate(), k = null, null != E && (clearInterval(E), E = null);
398
+ } };
399
+ return x = t3, k.onmessage = (e3) => {
400
+ const n3 = e3.data;
401
+ "open" === n3.type ? (t3.readyState = WebSocket.OPEN, handleWsOpen()) : "close" === n3.type ? (t3.readyState = WebSocket.CLOSED, handleWsClose()) : "message" === n3.type && handleWsMessage(n3.data);
402
+ }, k.onerror = () => {
403
+ w && console.warn("[Sailfish] WebSocket worker error");
404
+ }, k.postMessage({ type: "init", wsUrl: r2 }), w && console.log("[Sailfish] WebSocket running in Web Worker (off main thread)"), t3;
405
+ }
406
+ w && console.log("[Sailfish] WebSocket running on main thread (Worker unavailable)");
407
+ const l2 = new e(r2, [], { connectionTimeout: 3e4 }), c2 = { get readyState() {
408
+ return l2.readyState;
409
+ }, close: () => {
410
+ l2.close(), null != E && (clearInterval(E), E = null);
411
+ } };
412
+ return x = c2, l2.addEventListener("open", () => handleWsOpen()), l2.addEventListener("close", () => handleWsClose()), l2.addEventListener("message", (e2) => handleWsMessage(e2.data)), c2;
413
+ }
414
+ function sendMessage(e2) {
415
+ "sessionId" in e2 || (e2.sessionId = getOrSetSessionId()), e2.app_url || (e2.app_url = getCachedHref()), I || !isWebSocketOpen(x) ? saveNotifyMessageToIDB(JSON.stringify(e2)) : wsSendPayload(e2) || saveNotifyMessageToIDB(JSON.stringify(e2));
416
+ }
417
+ function enableFunctionSpanTracking() {
418
+ if (w && console.log("[Sailfish] enableFunctionSpanTracking() called - Report Issue recording started (LOCAL MODE)"), A = true, _ = true, D = null, null !== R && (window.clearTimeout(R), R = null), isWebSocketOpen(x)) {
419
+ wsSendPayload({ type: "funcSpanTrackingSessionReport", sessionId: getOrSetSessionId(), enabled: true, configurationType: v });
420
+ } else w && console.warn("[Sailfish] WebSocket not open, cannot report LOCAL tracking session");
421
+ }
422
+ function disableFunctionSpanTracking() {
423
+ if (w && console.log("[Sailfish] disableFunctionSpanTracking() called - Report Issue recording stopped"), isWebSocketOpen(x)) {
424
+ wsSendPayload({ type: "funcSpanTrackingSessionReport", sessionId: getOrSetSessionId(), enabled: false, configurationType: v });
425
+ } else console.warn("[FUNCSPAN STOP] ✗ WebSocket not open, cannot notify tracking end");
426
+ _ && (A = false, _ = false, D = null, w && console.log("[Sailfish] LOCAL tracking mode disabled")), null !== R && (window.clearTimeout(R), R = null);
427
+ }
428
+ function isFunctionSpanTrackingEnabled() {
429
+ return A;
430
+ }
431
+ function initializeFunctionSpanTrackingFromApi(e2) {
432
+ e2 && !A ? (A = true, _ = false, D = null, w && console.log("[Sailfish] Function span tracking initialized as ENABLED from API check")) : !e2 && A && (A = false, _ = false, D = null, w && console.log("[Sailfish] Function span tracking initialized as DISABLED from API check"));
433
+ }
434
+ function getFuncSpanHeader() {
435
+ if (!A) return null;
436
+ if (null !== D) {
437
+ if (Date.now() >= D) return A = false, D = null, clearGlobalFuncSpanState(), w && console.log("[Sailfish] Function span tracking expired on header check - disabling now"), null;
438
+ }
439
+ return { name: "X-Sf3-FunctionSpanCaptureOverride", value: "1-1-10-10-1-1.0-1-0-0" };
440
+ }
441
+ const j = Object.freeze(Object.defineProperty({ __proto__: null, clearStaleFuncSpanState, disableFunctionSpanTracking, enableFunctionSpanTracking, ensureHrefCache, flushBufferedEvents, getCachedHref, getCachedHrefNoQuery, getFuncSpanHeader, initializeFunctionSpanTrackingFromApi, initializeWebSocket, isFunctionSpanTrackingEnabled, restoreFuncSpanState, sendEvent, sendMessage }, Symbol.toStringTag, { value: "Module" }));
442
+ let O = null, z = null;
443
+ let U = null;
444
+ const H = ["https://api.ipify.org?format=json", "https://api.ip.sb/jsonip", "https://api4.my-ip.io/ip.json"];
445
+ function fetchAndSendIp(e2) {
446
+ U !== e2 && (U = e2, (async () => {
447
+ for (const e3 of H) try {
448
+ const t2 = new AbortController(), n2 = setTimeout(() => t2.abort(), 5e3), i2 = await fetch(e3, { signal: t2.signal });
449
+ if (clearTimeout(n2), !i2.ok) continue;
450
+ const o2 = await i2.json(), s2 = o2.ip || o2.origin || null;
451
+ if (s2 && "string" == typeof s2 && s2.length <= 45) return void sendMessage({ type: "visitorIp", ip: s2, timestamp: exports.nowTimestamp() });
452
+ } catch {
453
+ }
454
+ U = null;
455
+ })().catch(() => {
456
+ U = null;
457
+ }));
458
+ }
459
+ let q = null;
460
+ async function getSourceMapModule() {
461
+ return q || (q = await import("source-map-js")), q;
462
+ }
463
+ const N = /* @__PURE__ */ new Map(), W = /(?:\(|\s|^)(https?:\/\/[^)\s]+|\/[^)\s]+|[^)\s]+)?\/?([^/]+\.js)(?:\?[^:)]*)?:(\d+):(\d+)/;
464
+ async function getConsumerFor(e2, t2) {
465
+ const n2 = (e2 || `/assets/${t2}`).split("?")[0], i2 = [`${n2}.map`, n2.replace(/\.js$/, ".js.map"), `/assets/${t2}.map`], { SourceMapConsumer: o2 } = await getSourceMapModule();
466
+ for (const e3 of i2) try {
467
+ if (N.has(e3)) return N.get(e3);
468
+ const t3 = await fetch(e3);
469
+ if (!t3.ok) continue;
470
+ const n3 = await t3.json();
471
+ if (!n3 || !n3.mappings || !n3.sources) continue;
472
+ const i3 = await new o2(n3);
473
+ return N.set(e3, i3), i3;
474
+ } catch {
475
+ }
476
+ return null;
477
+ }
478
+ async function captureError(e2, t2 = false) {
479
+ let n2, i2;
480
+ e2 instanceof Error ? (n2 = e2.message, i2 = e2.stack || "No stack trace") : "string" == typeof e2 ? (n2 = e2, i2 = "No stack trace available") : (n2 = "Unknown error occurred", i2 = "No stack trace available");
481
+ const o2 = await (async function resolveStackTrace(e3) {
482
+ if (!e3) return ["No stack trace available"];
483
+ const t3 = Array.isArray(e3) ? e3 : e3.split("\n"), n3 = [];
484
+ for (const e4 of t3) {
485
+ const t4 = e4.match(W);
486
+ if (!t4) {
487
+ n3.push(e4);
488
+ continue;
489
+ }
490
+ const [, i3, o3, s3, a3] = t4, r3 = parseInt(s3, 10), l2 = Math.max(0, parseInt(a3, 10) - 1);
491
+ if (!Number.isFinite(r3) || !Number.isFinite(l2)) {
492
+ n3.push(e4 + " [Invalid line/column]");
493
+ continue;
494
+ }
495
+ const c2 = await getConsumerFor(i3, o3);
496
+ if (!c2) {
497
+ n3.push(`${e4} [No source map found for ${o3}]`);
498
+ continue;
499
+ }
500
+ const { SourceMapConsumer: d2 } = await getSourceMapModule();
501
+ let u2 = c2.originalPositionFor({ line: r3, column: l2, bias: d2.GREATEST_LOWER_BOUND });
502
+ if (!u2.source || null == u2.line) for (let e5 = 1; e5 <= 20 && (u2 = c2.originalPositionFor({ line: r3, column: Math.max(0, l2 - e5), bias: d2.GREATEST_LOWER_BOUND }), !u2.source || null == u2.line); e5++) ;
503
+ if (u2.source && null != u2.line) {
504
+ const e5 = u2.name || "anonymous";
505
+ n3.push(`${u2.source}:${u2.line}:${u2.column ?? 0} (${e5})`);
506
+ } else n3.push(`${e4} [No mapping found in ${o3}]`);
507
+ }
508
+ return n3;
509
+ })(i2), s2 = o2.filter((e3) => !e3.includes("chunk-") && !e3.includes("react-dom")), a2 = s2.length > 0 ? s2 : o2, r2 = Date.now();
510
+ sendMessage({ type: "event", event: { type: 6, timestamp: r2, data: { payload: { message: n2, stack: i2, trace: a2, filteredStack: s2, userAgent: navigator.userAgent, url: window.location.href, timestamp: r2, level: "error" } } } });
511
+ }
512
+ const K = readDebugFlag();
513
+ const G = readDebugFlag();
514
+ function sendGraphQLRequest(e2, t2, n2, i2 = 5, o2 = 2e3, s2 = 2) {
515
+ const a2 = `${n2.backendApi}/graphql/?apiKey=${n2.apiKey}`;
516
+ return G && console.log(`Initial GraphQL request for ${e2} at ${a2}`), (function exponentialBackoff(e3, t3, n3 = 5, i3 = 2e3, o3 = 2) {
517
+ let s3 = 0;
518
+ const attemptRequest = async () => {
519
+ try {
520
+ return await e3();
521
+ } catch (e4) {
522
+ if (s3++, s3 > n3) throw e4;
523
+ const a3 = i3 * Math.pow(o3, s3 - 1);
524
+ return K && console.log(`Attempt ${s3} failed: ${t3}; Retrying in ${a3}ms...`), await new Promise((e5) => setTimeout(e5, a3)), attemptRequest();
525
+ }
526
+ };
527
+ return attemptRequest();
528
+ })(() => fetch(a2, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ operationName: e2, query: t2, variables: n2 }) }).then((e3) => {
529
+ if (G && console.log(`Received response with status: ${e3.status}`), !e3.ok) throw new Error(`GraphQL request failed with status ${e3.status}`);
530
+ return e3.json();
531
+ }), "Sending GraphQL request to Sailfish AI", i2, o2, s2);
532
+ }
533
+ function fetchCaptureSettings(e2, t2) {
534
+ return sendGraphQLRequest("GetCaptureSettingsFromApiKey", "\n query GetCaptureSettingsFromApiKey($apiKey: String!) {\n captureSettingsFromApiKey(apiKey: $apiKey) {\n recordCanvas\n recordCrossOriginIframes\n collectFonts\n inlineImages\n recordPassword\n recordRealName\n recordCreditCardInfo\n recordSsn\n recordDob\n sampling\n textEditThrottleEnabled\n }\n }\n ", { apiKey: e2, backendApi: t2 });
535
+ }
536
+ function fetchFunctionSpanTrackingEnabled(e2, t2) {
537
+ return sendGraphQLRequest("GetFunctionSpanTrackingEnabledFromApiKey", "\n query GetFunctionSpanTrackingEnabledFromApiKey($apiKey: String!) {\n isFunctionSpanTrackingEnabledFromApiKey(apiKey: $apiKey)\n }\n ", { apiKey: e2, backendApi: t2 });
538
+ }
539
+ function startRecordingSession(e2, t2, n2, i2, o2, s2, a2, r2, l2) {
540
+ return sendGraphQLRequest("StartSession", "mutation StartSession(\n $apiKey: UUID!,\n $recordingSessionId: UUID!,\n $serviceIdentifier: String!,\n $serviceVersion: String,\n $mapUuid: String,\n $gitSha: String,\n $library: String,\n $serviceAdditionalMetadata: JSON,\n $startRecordingFilePath: String,\n $startRecordingLineNumber: Int\n ) {\n startRecordingSession(\n companyApiKey: $apiKey,\n sessionId: $recordingSessionId,\n serviceIdentifier: $serviceIdentifier,\n serviceVersion: $serviceVersion,\n mapUuid: $mapUuid,\n gitSha: $gitSha,\n library: $library,\n serviceAdditionalMetadata: $serviceAdditionalMetadata,\n startRecordingFilePath: $startRecordingFilePath,\n startRecordingLineNumber: $startRecordingLineNumber\n ) {\n id\n }\n }", { apiKey: e2, recordingSessionId: t2, backendApi: n2, serviceIdentifier: i2, serviceVersion: o2, mapUuid: s2, gitSha: a2, library: r2, serviceAdditionalMetadata: l2, startRecordingFilePath: null, startRecordingLineNumber: null });
541
+ }
542
+ function sendDomainsToNotPropagateHeaderTo(e2, t2, n2) {
543
+ return sendGraphQLRequest("DomainsToNotPassHeaderTo", "mutation DomainsToNotPassHeaderTo($apiKey: String!, $domains: [String!]!) {\n domainsToNotPassHeaderTo(apiKey: $apiKey, domains: $domains)\n }", { apiKey: e2, domains: t2, backendApi: n2 });
544
+ }
545
+ function createTriageFromRecorder(e2, t2, n2, i2, o2, s2) {
546
+ return sendGraphQLRequest("CreateTriageFromRecorder", "mutation CreateTriageFromRecorder(\n $apiKey: String!,\n $recordingSessionId: String!,\n $timestampStart: String!,\n $timestampEnd: String!,\n $description: String\n ) {\n createTriageFromRecorder(\n apiKey: $apiKey,\n recordingSessionId: $recordingSessionId,\n timestampStart: $timestampStart,\n timestampEnd: $timestampEnd,\n description: $description\n ) {\n id\n }\n }\n ", { apiKey: e2, recordingSessionId: n2, timestampStart: i2, timestampEnd: o2, description: s2, backendApi: t2 });
547
+ }
548
+ function fetchEngineeringTicketPlatformIntegrations(e2, t2) {
549
+ return sendGraphQLRequest("GetEngineeringTicketPlatformIntegrationsFromApiKey", "query GetEngineeringTicketPlatformIntegrationsFromApiKey($apiKey: String!) {\n getEngineeringTicketPlatformIntegrationsFromApiKey(apiKey: $apiKey) {\n pushAutoIdentifiedIssues\n provider\n clientId\n defaultPriority\n defaultProject\n defaultTeam\n primaryCloudId\n installed\n projects\n teams\n workflowStates\n webhookState\n clouds\n labels\n sprints\n users\n fieldConfigurations\n invalidFields\n jiraReporterAccountId\n }\n }", { apiKey: e2, backendApi: t2 });
550
+ }
551
+ function createTriageAndIssueFromRecorder(e2, t2, n2, i2, o2, s2, a2, r2, l2, c2, d2, u2, p2, f2, g2) {
552
+ return sendGraphQLRequest("CreateTriageAndIssueFromRecorder", "mutation CreateTriageAndIssueFromRecorder(\n $apiKey: String!,\n $recordingSessionId: String!,\n $timestampStart: String!,\n $timestampEnd: String!,\n $description: String,\n $issueName: String,\n $issueDescription: String,\n $createEngineeringTicket: Boolean,\n $teamId: String,\n $projectId: String,\n $priority: Int,\n $labels: [String!],\n $issueType: String,\n $customFields: JSON\n ) {\n createTriageAndIssueFromRecorder(\n apiKey: $apiKey,\n recordingSessionId: $recordingSessionId,\n timestampStart: $timestampStart,\n timestampEnd: $timestampEnd,\n description: $description,\n issueName: $issueName,\n issueDescription: $issueDescription,\n createEngineeringTicket: $createEngineeringTicket,\n teamId: $teamId,\n projectId: $projectId,\n priority: $priority,\n labels: $labels,\n issueType: $issueType,\n customFields: $customFields\n ) {\n id\n title\n }\n }\n ", { apiKey: e2, recordingSessionId: n2, timestampStart: i2, timestampEnd: o2, description: s2, issueName: a2, issueDescription: r2, createEngineeringTicket: l2, teamId: c2, projectId: d2, priority: u2, labels: p2, issueType: f2, customFields: g2, backendApi: t2 });
553
+ }
554
+ const V = ["/node_modules/", "/@sailfish-ai/", "/@sailfish-rrweb/", "/dist/", "/webpack/", "/vite/", "/__vite", "/react-dom/", "/react/", "/scheduler/", "/<", "/chrome-extension://", "/extensions/"];
555
+ function shouldSkipFrame(e2) {
556
+ return V.some((t2) => e2.includes(t2));
557
+ }
558
+ function normalizeFilePath(e2) {
559
+ let t2 = e2;
560
+ if (t2.startsWith("file://") && (t2 = t2.substring(7)), t2.startsWith("webpack-internal:///") && (t2 = t2.substring(20)), t2.startsWith("webpack:///") && (t2 = t2.substring(11)), t2.startsWith("/@fs/") && (t2 = t2.substring(5)), t2.startsWith("http://") || t2.startsWith("https://")) try {
561
+ t2 = new URL(t2).pathname || t2, "/" === t2 && (t2 = "index.html");
562
+ } catch {
563
+ }
564
+ return t2;
565
+ }
566
+ function getCallerLocationFromTrace(e2, t2 = 0) {
567
+ if (!Array.isArray(e2) || 0 === e2.length) return [null, null];
568
+ const n2 = (function parseRrwebTraceFrames(e3) {
569
+ const t3 = [];
570
+ for (const n3 of e3) {
571
+ if (!n3) continue;
572
+ const e4 = n3.startsWith("at ") ? n3.slice(3) : n3;
573
+ let i2 = /^(.*?)\s+\((.+?):(\d+):(\d+)\)$/.exec(e4);
574
+ i2 ? t3.push({ functionName: i2[1] || "<anonymous>", file: i2[2], line: parseInt(i2[3], 10), column: parseInt(i2[4], 10) }) : (i2 = /^(.+?):(\d+):(\d+)$/.exec(e4), i2 && t3.push({ functionName: "<anonymous>", file: i2[1], line: parseInt(i2[2], 10), column: parseInt(i2[3], 10) }));
575
+ }
576
+ return t3;
577
+ })(e2);
578
+ for (let e3 = t2; e3 < Math.min(n2.length, t2 + 20); e3++) {
579
+ const t3 = n2[e3];
580
+ if (!(t3 == null ? void 0 : t3.file)) continue;
581
+ const i2 = normalizeFilePath(t3.file);
582
+ if (!shouldSkipFrame(i2)) return [i2, t3.line];
583
+ }
584
+ return [null, null];
585
+ }
586
+ function getCallerLocation(e2 = 0) {
587
+ const t2 = new Error().stack;
588
+ if (!t2) return [null, null];
589
+ const n2 = (function parseV8Stack(e3) {
590
+ if (!e3) return [];
591
+ const t3 = e3.split("\n").slice(1), n3 = [];
592
+ for (const e4 of t3) {
593
+ let t4 = /at\s+(.+?)\s+\((.+?):(\d+):(\d+)\)/.exec(e4);
594
+ t4 ? n3.push({ functionName: t4[1], file: t4[2], line: parseInt(t4[3], 10), column: parseInt(t4[4], 10) }) : (t4 = /at\s+(.+?):(\d+):(\d+)/.exec(e4), t4 && n3.push({ functionName: "<anonymous>", file: t4[1], line: parseInt(t4[2], 10), column: parseInt(t4[3], 10) }));
595
+ }
596
+ return n3;
597
+ })(t2), i2 = 1 + e2;
598
+ for (let e3 = i2; e3 < Math.min(n2.length, i2 + 20); e3++) {
599
+ const t3 = n2[e3];
600
+ if (!(t3 == null ? void 0 : t3.file)) continue;
601
+ const i3 = normalizeFilePath(t3.file);
602
+ if (!shouldSkipFrame(i3)) return [i3, t3.line];
603
+ }
604
+ return [null, null];
605
+ }
606
+ function suppressConsoleLogsDuringCall(e2) {
607
+ const t2 = console.log, n2 = console.warn, i2 = console.error;
608
+ console.log = () => {
609
+ }, console.warn = () => {
610
+ }, console.error = () => {
611
+ };
612
+ try {
613
+ e2();
614
+ } finally {
615
+ console.log = t2, console.warn = n2, console.error = i2;
616
+ }
617
+ }
618
+ function yieldToMain() {
619
+ var _a;
620
+ return "undefined" != typeof globalThis && ((_a = globalThis.scheduler) == null ? void 0 : _a.yield) ? globalThis.scheduler.yield() : new Promise((e2) => setTimeout(e2, 0));
621
+ }
622
+ let Q = null;
623
+ const J = "sailfishSanitize", X = "zendesk_chat", Z = "Zendesk";
624
+ function zE_safe(...e2) {
625
+ try {
626
+ if ((function hasZendesk() {
627
+ return "undefined" != typeof window && "function" == typeof window.zE;
628
+ })()) return window.zE(...e2), true;
629
+ } catch {
630
+ }
631
+ return false;
632
+ }
633
+ function maskInputFn(e2, t2) {
634
+ var _a;
635
+ if ("hidden" === t2.type) return "";
636
+ const n2 = { creditCard: /\b(?:\d[ -]*?){13,16}\b/, ssn: /\b\d{3}-\d{2}-\d{4}\b/ };
637
+ return t2.closest(".mask") ? "*".repeat(e2.length) : t2.hasAttribute("data-cc") || ((_a = t2.getAttribute("autocomplete")) == null ? void 0 : _a.startsWith("cc-")) || n2.creditCard.test(e2) ? "**** **** **** " + e2.slice(-4) : t2.hasAttribute("data-ssn") || n2.ssn.test(e2) ? "***-**-" + e2.slice(-4) : t2.hasAttribute("data-dob") ? "**/**/" + e2.slice(-4) : e2;
638
+ }
639
+ let Y = true, ee = null, te = null, ne = null, ie = null;
640
+ function invalidateUrlCache() {
641
+ Y = true;
642
+ }
643
+ const getUrlAndStoredUuids = () => (Y && (function _refreshSessionStorageCache() {
644
+ ee = sessionStorage.getItem("pageVisitUUID"), te = sessionStorage.getItem("prevPageVisitUUID"), ne = sessionStorage.getItem("tabVisibilityChanged"), ie = sessionStorage.getItem("tabVisibilityState"), Y = false;
645
+ })(), { page_visit_uuid: ee, prev_page_visit_uuid: te, href: getCachedHrefNoQuery(), tabVisibilityChanged: ne, tabVisibilityState: ie });
646
+ function initializeDomContentEvents(e2) {
647
+ document.addEventListener("readystatechange", () => {
648
+ const t2 = { type: 24, data: { source: 0, info: "" }, timestamp: Date.now(), sessionId: e2, ...getUrlAndStoredUuids() };
649
+ switch (document.readyState) {
650
+ case "loading":
651
+ t2.data.source = i;
652
+ break;
653
+ case "complete":
654
+ t2.data.source = s;
655
+ }
656
+ t2.data.info && sendEvent(t2);
657
+ }), document.addEventListener("DOMContentLoaded", () => {
658
+ sendEvent({ type: 24, data: { source: o }, timestamp: Date.now(), sessionId: e2, ...getUrlAndStoredUuids() });
659
+ }), window.addEventListener("beforeunload", () => {
660
+ sendEvent({ type: 24, data: { source: a }, timestamp: Date.now(), sessionId: e2, ...getUrlAndStoredUuids() });
661
+ }), window.addEventListener("unload", () => {
662
+ sendEvent({ type: 24, data: { source: r }, timestamp: Date.now(), sessionId: e2, ...getUrlAndStoredUuids() });
663
+ });
664
+ }
665
+ async function initializeConsolePlugin(e2, n2) {
666
+ const { getRecordConsolePlugin: i2 } = await import("@sailfish-rrweb/rrweb-plugin-console-record");
667
+ await yieldToMain();
668
+ const { name: o2, observer: s2 } = i2(e2);
669
+ s2((e3) => {
670
+ const i3 = e3, [s3, a2] = getCallerLocationFromTrace(i3 == null ? void 0 : i3.trace, 0), [r2, l2] = getCallerLocation(2), c2 = s3 ?? r2, d2 = a2 ?? l2, u2 = { ...i3, sourceFile: c2, sourceLine: d2 };
671
+ sendEvent({ type: t.EventType.Plugin, timestamp: Date.now(), data: { plugin: o2, payload: u2 }, sessionId: n2, ...getUrlAndStoredUuids() });
672
+ }, window, e2);
673
+ }
674
+ async function initializeRecording(e2, n2, i2, o2, s2, a2 = true, r2 = false, l2 = false) {
675
+ const c2 = initializeWebSocket(n2, i2, o2, s2, r2);
676
+ try {
677
+ const n3 = (function createThrottledEmit(e3, t2 = 1e3) {
678
+ if (!e3) return { emit: (e4) => sendEvent(e4), flush: () => {
679
+ } };
680
+ const n4 = /* @__PURE__ */ new Map();
681
+ let i3 = null;
682
+ return { emit: (e4) => {
683
+ var _a, _b;
684
+ const o3 = (_a = e4.data) == null ? void 0 : _a.source;
685
+ if (3 !== e4.type || 0 !== o3 && 5 !== o3) return void sendEvent(e4);
686
+ if (0 === o3) {
687
+ const t3 = e4.data, n5 = (t3 == null ? void 0 : t3.adds) && t3.adds.length > 0, i4 = (t3 == null ? void 0 : t3.removes) && t3.removes.length > 0;
688
+ if (n5 || i4) return void sendEvent(e4);
689
+ }
690
+ const s3 = `3:${o3}:${((_b = e4.data) == null ? void 0 : _b.id) || "unknown"}`;
691
+ n4.set(s3, e4), i3 || (i3 = setInterval(() => {
692
+ 0 !== n4.size && (n4.forEach((e5) => sendEvent(e5)), n4.clear());
693
+ }, t2));
694
+ }, flush: () => {
695
+ n4.size > 0 && (n4.forEach((e4) => sendEvent(e4)), n4.clear()), i3 && (clearInterval(i3), i3 = null);
696
+ } };
697
+ })(e2.textEditThrottleEnabled), emitWithContext = (e3) => {
698
+ Object.assign(e3, getUrlAndStoredUuids()), e3.sessionId = o2, n3.emit(e3);
699
+ }, startHeavyWork = async () => {
700
+ if (true === e2.enableFiberTracking) try {
701
+ const { installFiberHook: e3, processExistingTree: t2 } = await Promise.resolve().then(() => require("./fiberHook-CEzmPkx_.js"));
702
+ e3(), t2(), console.log("[Sailfish] React Fiber tracking enabled");
703
+ } catch (e3) {
704
+ console.warn("[Sailfish] Failed to enable Fiber tracking:", e3);
705
+ }
706
+ const { record: n4 } = await import("@sailfish-rrweb/rrweb-record-only");
707
+ if (Q = n4, await yieldToMain(), l2) {
708
+ const { chunkedSnapshot: i3 } = await Promise.resolve().then(() => require("./chunkSerializer-DM9muyGb.js")), o3 = n4.mirror;
709
+ let s3 = true;
710
+ const a3 = [];
711
+ n4({ emit(e3) {
712
+ s3 ? a3.push(e3) : emitWithContext(e3);
713
+ }, maskInputOptions: { text: true }, maskInputFn, maskTextClass: J, ...e2, recordDOM: false });
714
+ const r3 = Date.now(), l3 = await i3(document, o3, { chunkSize: 500, maxChunkMs: 16, blockClass: e2.blockClass, blockSelector: e2.blockSelector, maskTextClass: e2.maskTextClass ?? J, maskTextSelector: e2.maskTextSelector });
715
+ if (l3) {
716
+ emitWithContext({ type: t.EventType.Meta, data: { href: window.location.href, width: document.documentElement.clientWidth || document.body.clientWidth, height: document.documentElement.clientHeight || document.body.clientHeight }, timestamp: r3 }), emitWithContext({ type: t.EventType.FullSnapshot, data: { node: l3, initialOffset: { left: void 0 !== window.pageXOffset ? window.pageXOffset : document.documentElement.scrollLeft, top: void 0 !== window.pageYOffset ? window.pageYOffset : document.documentElement.scrollTop } }, timestamp: r3 });
717
+ for (const e3 of a3) emitWithContext(e3);
718
+ s3 = false;
719
+ } else console.warn("[Sailfish] chunkSnapshot serialization failed; session continues without initial DOM snapshot"), s3 = false;
720
+ } else n4({ emit(e3) {
721
+ emitWithContext(e3);
722
+ }, maskInputOptions: { text: true }, maskInputFn, maskTextClass: J, ...e2 });
723
+ };
724
+ if (a2) {
725
+ let e3 = false;
726
+ const startOnce = () => {
727
+ e3 || (e3 = true, startHeavyWork());
728
+ }, scheduleAfterLoad = () => {
729
+ const e4 = setTimeout(startOnce, 1e4);
730
+ "function" == typeof requestIdleCallback && requestIdleCallback(() => {
731
+ clearTimeout(e4), startOnce();
732
+ });
733
+ const t2 = ["click", "scroll", "keydown", "touchstart"], onInteraction = () => {
734
+ clearTimeout(e4), t2.forEach((e5) => window.removeEventListener(e5, onInteraction, true)), startOnce();
735
+ };
736
+ t2.forEach((e5) => window.addEventListener(e5, onInteraction, { once: true, capture: true }));
737
+ };
738
+ "complete" === document.readyState ? scheduleAfterLoad() : window.addEventListener("load", () => scheduleAfterLoad(), { once: true });
739
+ } else "function" == typeof requestIdleCallback ? requestIdleCallback(startHeavyWork, { timeout: 2e3 }) : setTimeout(startHeavyWork, 0);
740
+ window.addEventListener("beforeunload", () => {
741
+ n3.flush();
742
+ }), (function whenZendeskReady(e3) {
743
+ if ("undefined" == typeof window) return;
744
+ const t2 = window.zE;
745
+ if ("function" == typeof t2) try {
746
+ t2(e3);
747
+ } catch {
748
+ }
749
+ })(() => {
750
+ suppressConsoleLogsDuringCall(() => {
751
+ zE_safe("messenger:set", "conversationTags", [`sailfish-session-${o2}`]);
752
+ });
753
+ const handleWidgetOpen = () => {
754
+ Q == null ? void 0 : Q.addSailfishEvent(t.EventType.SailfishCustom, { action: "customer support chat opened", element_id: X, provider: Z });
755
+ }, handleWidgetClose = () => {
756
+ Q == null ? void 0 : Q.addSailfishEvent(t.EventType.SailfishCustom, { action: "customer support chat closed", element_id: X, provider: Z });
757
+ }, handleUnreadMessages = (e3) => {
758
+ Q == null ? void 0 : Q.addSailfishEvent(t.EventType.SailfishCustom, { action: "zendesk unreadmessages", element_id: X, provider: Z });
759
+ };
760
+ suppressConsoleLogsDuringCall(() => {
761
+ zE_safe("messenger:on", "open", handleWidgetOpen), zE_safe("messenger:on", "close", handleWidgetClose), zE_safe("messenger:on", "unreadMessages", handleUnreadMessages);
762
+ });
763
+ });
764
+ } catch (e3) {
765
+ console.error("Error importing plugins!", e3);
766
+ }
767
+ return c2;
768
+ }
769
+ const oe = ["jira", "linear", "zendesk"];
770
+ let se = null;
771
+ const ae = /* @__PURE__ */ new Map();
772
+ function getIntegrationData() {
773
+ return se;
774
+ }
775
+ function hasValidIntegration() {
776
+ return null !== se && true === se.installed;
777
+ }
778
+ function resolveIntegration(e2) {
779
+ var _a;
780
+ if ((e2 == null ? void 0 : e2.errors) && e2.errors.length > 0) return console.error("GraphQL errors fetching integrations:", e2.errors), null;
781
+ const t2 = (_a = e2 == null ? void 0 : e2.data) == null ? void 0 : _a.getEngineeringTicketPlatformIntegrationsFromApiKey, n2 = (t2 || []).filter((e3) => {
782
+ var _a2;
783
+ return oe.includes(((_a2 = e3.provider) == null ? void 0 : _a2.toLowerCase()) || "") && true === e3.installed;
784
+ });
785
+ if (0 === n2.length) return console.warn("No valid installed integrations found"), null;
786
+ const i2 = n2.find((e3) => {
787
+ var _a2;
788
+ return "jira" === ((_a2 = e3.provider) == null ? void 0 : _a2.toLowerCase());
789
+ }) || n2[0];
790
+ return (i2 == null ? void 0 : i2.primaryCloudId) && ae.set(i2.primaryCloudId, i2), i2;
791
+ }
792
+ async function refreshIntegrationData(e2, t2) {
793
+ try {
794
+ const n2 = resolveIntegration(await fetchEngineeringTicketPlatformIntegrations(e2, t2));
795
+ return se = n2, n2;
796
+ } catch (e3) {
797
+ return console.error("Error refreshing integration data:", e3), se;
798
+ }
799
+ }
800
+ function populateSelectOptions(e2, t2, n2) {
801
+ const i2 = document.createElement("option");
802
+ i2.value = "", i2.disabled = true, i2.selected = !n2, i2.textContent = "Select...", i2.style.color = "#9ca3af", e2.innerHTML = "", e2.appendChild(i2), t2.forEach((t3) => {
803
+ const n3 = document.createElement("option");
804
+ n3.value = t3.id || t3.value || t3, n3.textContent = t3.name || t3.label || t3, e2.appendChild(n3);
805
+ }), n2 ? (e2.value = n2, e2.style.color = "") : e2.style.color = "#9ca3af";
806
+ }
807
+ function populatePriorityOptions(e2, t2, n2) {
808
+ const i2 = "jira" === (t2 == null ? void 0 : t2.toLowerCase());
809
+ if (e2.innerHTML = "", i2) {
810
+ [{ id: "1", name: "Highest" }, { id: "2", name: "High" }, { id: "3", name: "Medium" }, { id: "4", name: "Low" }, { id: "5", name: "Lowest" }].forEach((t3) => {
811
+ const n3 = document.createElement("option");
812
+ n3.value = t3.id, n3.textContent = t3.name, e2.appendChild(n3);
813
+ });
814
+ } else {
815
+ [{ id: "0", name: "No Priority" }, { id: "1", name: "Urgent" }, { id: "2", name: "High" }, { id: "3", name: "Medium" }, { id: "4", name: "Low" }].forEach((t3) => {
816
+ const n3 = document.createElement("option");
817
+ n3.value = t3.id, n3.textContent = t3.name, e2.appendChild(n3);
818
+ });
819
+ }
820
+ null != n2 ? e2.value = String(n2) : i2 || (e2.value = "0");
821
+ }
822
+ function populateSprintOptions(e2, t2, n2) {
823
+ e2.innerHTML = "";
824
+ const i2 = document.createElement("option");
825
+ i2.value = "", i2.disabled = true, i2.selected = !n2, i2.textContent = "Select sprint...", i2.style.color = "#9ca3af", e2.appendChild(i2);
826
+ (t2 || []).filter((e3) => "active" === e3.state || "future" === e3.state).forEach((t3) => {
827
+ const n3 = document.createElement("option");
828
+ n3.value = String(t3.id), n3.textContent = t3.name || t3.id, e2.appendChild(n3);
829
+ }), n2 && (e2.value = n2);
830
+ }
831
+ function getSprintFieldId() {
832
+ if (!(se == null ? void 0 : se.fieldConfigurations)) return "customfield_10020";
833
+ const e2 = Array.isArray(se.fieldConfigurations) ? se.fieldConfigurations : [];
834
+ for (const t2 of e2) {
835
+ const e3 = (t2.fields || []).find((e4) => {
836
+ var _a;
837
+ return "com.pyxis.greenhopper.jira:gh-sprint" === ((_a = e4.schema) == null ? void 0 : _a.custom);
838
+ });
839
+ if (e3 == null ? void 0 : e3.fieldId) return e3.fieldId;
840
+ }
841
+ return "customfield_10020";
842
+ }
843
+ function updateIssueTypeOptions(e2, t2) {
844
+ var _a;
845
+ if (!(se == null ? void 0 : se.projects) || !t2) {
846
+ e2.innerHTML = "";
847
+ const t3 = document.createElement("option");
848
+ return t3.value = "", t3.disabled = true, t3.selected = true, t3.textContent = "Select project first...", t3.style.color = "#9ca3af", e2.appendChild(t3), void (e2.style.color = "#9ca3af");
849
+ }
850
+ const n2 = se.projects.find((e3) => e3.id === t2);
851
+ if (!n2 || !n2.issue_types) {
852
+ e2.innerHTML = "";
853
+ const t3 = document.createElement("option");
854
+ return t3.value = "", t3.disabled = true, t3.selected = true, t3.textContent = "No issue types available", t3.style.color = "#9ca3af", e2.appendChild(t3), void (e2.style.color = "#9ca3af");
855
+ }
856
+ const i2 = n2.issue_types || [];
857
+ e2.innerHTML = "";
858
+ const o2 = document.createElement("option");
859
+ if (o2.value = "", o2.disabled = true, o2.textContent = "Select...", o2.style.color = "#9ca3af", e2.appendChild(o2), i2.forEach((t3) => {
860
+ const n3 = document.createElement("option");
861
+ n3.value = t3.id || t3.value || t3, n3.textContent = t3.name || t3.label || t3, e2.appendChild(n3);
862
+ }), i2.length > 0) {
863
+ const t3 = i2.find((e3) => {
864
+ var _a2;
865
+ return "bug" === ((_a2 = e3.name) == null ? void 0 : _a2.toLowerCase());
866
+ }), n3 = i2.find((e3) => {
867
+ var _a2;
868
+ return "task" === ((_a2 = e3.name) == null ? void 0 : _a2.toLowerCase());
869
+ }), s2 = (t3 == null ? void 0 : t3.id) || (n3 == null ? void 0 : n3.id) || ((_a = i2[0]) == null ? void 0 : _a.id);
870
+ s2 ? (e2.value = s2, e2.style.color = "#000") : (o2.selected = true, e2.style.color = "#9ca3af");
871
+ }
872
+ }
873
+ function getFieldsForProject(e2, t2) {
874
+ if (!(se == null ? void 0 : se.fieldConfigurations) || !e2) return [];
875
+ const n2 = Array.isArray(se.fieldConfigurations) ? se.fieldConfigurations.find((n3) => n3.project_key === e2 && (!t2 || n3.issue_type_id === t2)) : se.fieldConfigurations[e2];
876
+ return n2 && n2.fields ? n2.fields : [];
877
+ }
878
+ function getUsers() {
879
+ return (se == null ? void 0 : se.users) ? se.users : [];
880
+ }
881
+ function getProjectsForTeam(e2) {
882
+ if (!se) return [];
883
+ const t2 = se.teams && Array.isArray(se.teams) && se.teams.length > 0;
884
+ if (t2 && e2) {
885
+ const t3 = se.teams.find((t4) => t4.id === e2);
886
+ return (t3 == null ? void 0 : t3.projects) || [];
887
+ }
888
+ return !t2 && se.projects ? se.projects : [];
889
+ }
890
+ function updateFormWithIntegrationData(e2) {
891
+ var _a;
892
+ if (!se) return e2;
893
+ const t2 = se.teams && Array.isArray(se.teams) && se.teams.length > 0, n2 = document.getElementById("sf-eng-ticket-team");
894
+ n2 && t2 && (populateSelectOptions(n2, se.teams, se.defaultTeam), e2.engTicketTeam ? n2.value = e2.engTicketTeam : e2.engTicketTeam = n2.value);
895
+ const i2 = document.getElementById("sf-eng-ticket-project");
896
+ if (i2) {
897
+ populateSelectOptions(i2, t2 ? getProjectsForTeam(e2.engTicketTeam) : se.projects || [], se.defaultProject), e2.engTicketProject ? i2.value = e2.engTicketProject : e2.engTicketProject = i2.value;
898
+ }
899
+ const o2 = document.getElementById("sf-eng-ticket-priority");
900
+ o2 && (populatePriorityOptions(o2, se.provider || "", se.defaultPriority), e2.engTicketPriority ? o2.value = String(e2.engTicketPriority) : e2.engTicketPriority = Number(o2.value));
901
+ const s2 = document.getElementById("sf-eng-ticket-sprint"), a2 = "jira" === ((_a = se.provider) == null ? void 0 : _a.toLowerCase());
902
+ s2 && a2 && se.sprints && populateSprintOptions(s2, se.sprints, e2.engTicketSprint || void 0);
903
+ const r2 = document.getElementById("sf-eng-ticket-type");
904
+ return r2 && a2 && e2.engTicketProject && (updateIssueTypeOptions(r2, e2.engTicketProject), e2.engTicketIssueType ? (r2.value = e2.engTicketIssueType, r2.style.color = "#000") : r2.value && (e2.engTicketIssueType = r2.value)), e2;
905
+ }
906
+ const re = Object.freeze(Object.defineProperty({ __proto__: null, fetchIntegrationData: async function fetchIntegrationData(e2, t2) {
907
+ if (!se) try {
908
+ const n2 = await fetchEngineeringTicketPlatformIntegrations(e2, t2);
909
+ se = resolveIntegration(n2);
910
+ } catch (e3) {
911
+ console.error("Error fetching integration data:", e3), se = null;
912
+ }
913
+ }, getFieldsForProject, getIntegrationData, getProjectsForTeam, getSprintFieldId, getUsers, hasValidIntegration, populatePriorityOptions, populateSelectOptions, populateSprintOptions, refreshIntegrationData, updateFormWithIntegrationData, updateIssueTypeOptions }, Symbol.toStringTag, { value: "Module" })), le = "sf-create-issue-preference", ce = "sf-create-eng-ticket-preference";
914
+ function getInitialState() {
915
+ const e2 = (function loadUserPreferences() {
916
+ return { createIssue: g && "true" === localStorage.getItem(le), createEngTicket: g && "true" === localStorage.getItem(ce) };
917
+ })();
918
+ return { mode: "lookback", description: "", occurredInThisTab: true, createIssue: e2.createIssue, issueName: "", issueDescription: "", createEngTicket: e2.createEngTicket, engTicketTeam: "", engTicketProject: "", engTicketPriority: 0, engTicketLabels: [], engTicketSprint: "", engTicketIssueType: "", engTicketCustomFields: {} };
919
+ }
920
+ let de = getInitialState(), ue = null, pe = null, fe = null, ge = false;
921
+ function setTimerInterval(e2) {
922
+ fe = e2;
923
+ }
924
+ function setIsRecording(e2) {
925
+ ge = e2;
926
+ }
927
+ function renderCustomMultiSelect(e2, t2, n2, i2, o2 = false) {
928
+ const s2 = o2 ? '<span style="color:#ef4444;">*</span>' : "", a2 = n2.filter((e3) => i2.includes(e3.id || e3.value || e3.name || e3)).map((e3) => e3.name || e3.value || e3).join(", ");
929
+ return `
930
+ <div style="position:relative;">
931
+ <label for="${e2}" style="display:block; font-size:14px; font-weight:500; margin-bottom:6px;">
932
+ ${t2} ${s2}
933
+ </label>
934
+ <div class="sf-custom-multiselect" id="${e2}-container" data-field-id="${e2}" style="position:relative;">
935
+ <div class="sf-multiselect-input" style="width:100%; padding:8px 12px; font-size:14px; border:1px solid #cbd5e1; border-radius:6px; background-color:white; cursor:pointer; min-height:38px; display:flex; align-items:center;" onclick="document.getElementById('${e2}-dropdown').style.display = document.getElementById('${e2}-dropdown').style.display === 'none' ? 'block' : 'none';">
936
+ <span style="color:${a2 ? "#000" : "#9ca3af"}; flex:1;">${a2 || "Select..."}</span>
937
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none" style="margin-left:8px;">
938
+ <path d="M4 6L8 10L12 6" stroke="#64748B" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
939
+ </svg>
940
+ </div>
941
+ <div id="${e2}-dropdown" class="sf-multiselect-dropdown" style="display:none; position:absolute; top:100%; left:0; right:0; margin-top:4px; background:white; border:1px solid #cbd5e1; border-radius:6px; max-height:200px; overflow-y:auto; z-index:1000; box-shadow:0 4px 6px -1px rgba(0,0,0,0.1);">
942
+ ${n2.map((e3) => {
943
+ const t3 = e3.id || e3.value || e3.name || e3, n3 = e3.name || e3.value || e3, o3 = i2.includes(t3);
944
+ return `
945
+ <div class="sf-multiselect-option" data-value="${t3}" data-selected="${o3}" style="padding:8px 12px; cursor:pointer; ${o3 ? "background-color:#e0f2fe;" : ""}" onmouseover="this.style.backgroundColor=this.dataset.selected === 'true' ? '#bae6fd' : '#f1f5f9'" onmouseout="this.style.backgroundColor=this.dataset.selected === 'true' ? '#e0f2fe' : ''" onclick="event.stopPropagation();">
946
+ ${n3}
947
+ </div>
948
+ `;
949
+ }).join("")}
950
+ </div>
951
+ </div>
952
+ </div>
953
+ `;
954
+ }
955
+ const me = { enabled: false, openModalExistingMode: { key: "e", requireCmdCtrl: false }, openModalCaptureNewMode: { key: "n", requireCmdCtrl: false }, closeModal: { key: "escape", requireCmdCtrl: false }, submitReport: { key: "enter", requireCmdCtrl: true }, startRecording: { key: "r", requireCmdCtrl: false }, stopRecording: { key: "escape", requireCmdCtrl: true } }, he = { shortcuts: { ...me }, resolveSessionId: null, apiKey: null, backendApi: null, triageBaseUrl: "https://app.sailfishqa.com", deactivateIsolation: () => {
956
+ }, integrationData: null };
957
+ let ye = null;
958
+ function setupCustomMultiSelectListeners(e2, t2) {
959
+ const n2 = document.getElementById(`${e2}-container`), i2 = document.getElementById(`${e2}-dropdown`);
960
+ if (!n2 || !i2) return;
961
+ i2.querySelectorAll(".sf-multiselect-option").forEach((e3) => {
962
+ e3.addEventListener("click", (o2) => {
963
+ o2.stopPropagation();
964
+ const s2 = e3, a2 = "true" === s2.dataset.selected;
965
+ s2.dataset.selected = String(!a2), s2.style.backgroundColor = a2 ? "" : "#e0f2fe";
966
+ const r2 = [], l2 = [];
967
+ i2.querySelectorAll(".sf-multiselect-option").forEach((e4) => {
968
+ const t3 = e4;
969
+ "true" === t3.dataset.selected && (r2.push(t3.dataset.value || ""), l2.push(t3.textContent || ""));
970
+ });
971
+ const c2 = n2.querySelector(".sf-multiselect-input span"), d2 = l2.join(", ");
972
+ c2 && (c2.textContent = d2 || "Select...", c2.style.color = d2 ? "#000" : "#9ca3af"), t2(r2);
973
+ });
974
+ }), document.addEventListener("click", (e3) => {
975
+ const t3 = e3.target;
976
+ n2.contains(t3) || (i2.style.display = "none");
977
+ });
978
+ }
979
+ function renderDynamicFields(e2, t2) {
980
+ const n2 = document.getElementById("sf-dynamic-fields-container");
981
+ if (!n2) return;
982
+ if (!e2) return void (n2.innerHTML = '<div style="font-size:14px; color:#64748B;">Select a project to see additional fields</div>');
983
+ const i2 = getFieldsForProject(e2, t2), o2 = getUsers();
984
+ if (!i2 || 0 === i2.length) return void (n2.innerHTML = "");
985
+ const s2 = i2.map((e3) => (function renderDynamicField(e4, t3, n3 = []) {
986
+ var _a, _b, _c, _d;
987
+ const i3 = e4.fieldId || e4.key, o3 = e4.name, s3 = (_a = e4.schema) == null ? void 0 : _a.type, a2 = (_b = e4.schema) == null ? void 0 : _b.system, r2 = (_c = e4.schema) == null ? void 0 : _c.custom, l2 = e4.required || false, c2 = e4.allowedValues, d2 = ["summary", "description", "project", "issuetype", "priority"];
988
+ if (d2.includes(i3) || d2.includes(a2)) return null;
989
+ const u2 = l2 ? '<span style="color:#ef4444;">*</span>' : "", p2 = "width:100%; padding:8px 12px; font-size:14px; border:1px solid #cbd5e1; border-radius:6px; outline:none;";
990
+ switch (s3) {
991
+ case "string":
992
+ return r2 && r2.includes("textarea") ? `
993
+ <div>
994
+ <label for="${i3}" style="display:block; font-size:14px; font-weight:500; margin-bottom:6px;">
995
+ ${o3} ${u2}
996
+ </label>
997
+ <textarea
998
+ id="${i3}"
999
+ class="sf-dynamic-field"
1000
+ data-field-id="${i3}"
1001
+ placeholder="Enter ${o3.toLowerCase()}"
1002
+ style="${p2} height:80px; resize:none;"
1003
+ ${l2 ? "required" : ""}
1004
+ >${t3 || ""}</textarea>
1005
+ </div>
1006
+ ` : `
1007
+ <div>
1008
+ <label for="${i3}" style="display:block; font-size:14px; font-weight:500; margin-bottom:6px;">
1009
+ ${o3} ${u2}
1010
+ </label>
1011
+ <input
1012
+ type="text"
1013
+ id="${i3}"
1014
+ class="sf-dynamic-field"
1015
+ data-field-id="${i3}"
1016
+ value="${t3 || ""}"
1017
+ placeholder="Enter ${o3.toLowerCase()}"
1018
+ style="${p2}"
1019
+ ${l2 ? "required" : ""}
1020
+ />
1021
+ </div>
1022
+ `;
1023
+ case "number":
1024
+ return `
1025
+ <div>
1026
+ <label for="${i3}" style="display:block; font-size:14px; font-weight:500; margin-bottom:6px;">
1027
+ ${o3} ${u2}
1028
+ </label>
1029
+ <input
1030
+ type="number"
1031
+ id="${i3}"
1032
+ class="sf-dynamic-field"
1033
+ data-field-id="${i3}"
1034
+ value="${t3 || ""}"
1035
+ placeholder="Enter ${o3.toLowerCase()}"
1036
+ style="${p2}"
1037
+ step="0.5"
1038
+ ${l2 ? "required" : ""}
1039
+ />
1040
+ </div>
1041
+ `;
1042
+ case "date":
1043
+ return `
1044
+ <div>
1045
+ <label for="${i3}" style="display:block; font-size:14px; font-weight:500; margin-bottom:6px;">
1046
+ ${o3} ${u2}
1047
+ </label>
1048
+ <input
1049
+ type="date"
1050
+ id="${i3}"
1051
+ class="sf-dynamic-field"
1052
+ data-field-id="${i3}"
1053
+ value="${t3 || ""}"
1054
+ style="${p2}"
1055
+ ${l2 ? "required" : ""}
1056
+ />
1057
+ </div>
1058
+ `;
1059
+ case "user":
1060
+ if (n3 && n3.length > 0) {
1061
+ const e5 = n3.map((e6) => {
1062
+ const n4 = e6.email ? `${e6.name} (${e6.email})` : e6.name, i4 = t3 === e6.id ? "selected" : "";
1063
+ return `<option value="${e6.id}" ${i4}>${n4}</option>`;
1064
+ }).join(""), s4 = t3 && n3.some((e6) => e6.id === t3);
1065
+ return `
1066
+ <div>
1067
+ <label for="${i3}" style="display:block; font-size:14px; font-weight:500; margin-bottom:6px;">
1068
+ ${o3} ${u2}
1069
+ </label>
1070
+ <select
1071
+ id="${i3}"
1072
+ class="sf-dynamic-field"
1073
+ data-field-id="${i3}"
1074
+ style="${p2} appearance:none; cursor:pointer; background-color: white; ${s4 ? "" : "color: #9ca3af;"}"
1075
+ ${l2 ? "required" : ""}
1076
+ >
1077
+ <option value="" disabled ${s4 ? "" : "selected"} style="color: #9ca3af;">Select ${o3.toLowerCase()}...</option>
1078
+ ${e5}
1079
+ </select>
1080
+ </div>
1081
+ `;
1082
+ }
1083
+ return null;
1084
+ case "option":
1085
+ if (c2 && c2.length > 0) {
1086
+ const e5 = c2.map((e6) => {
1087
+ const n5 = e6.id || e6.value || e6, i4 = e6.value || e6.name || e6;
1088
+ return `<option value="${n5}" ${t3 === n5 ? "selected" : ""}>${i4}</option>`;
1089
+ }).join(""), n4 = t3 && c2.some((e6) => (e6.id || e6.value || e6) === t3);
1090
+ return `
1091
+ <div>
1092
+ <label for="${i3}" style="display:block; font-size:14px; font-weight:500; margin-bottom:6px;">
1093
+ ${o3} ${u2}
1094
+ </label>
1095
+ <select
1096
+ id="${i3}"
1097
+ class="sf-dynamic-field"
1098
+ data-field-id="${i3}"
1099
+ style="${p2} appearance:none; cursor:pointer; background-color: white; ${n4 ? "" : "color: #9ca3af;"}"
1100
+ ${l2 ? "required" : ""}
1101
+ >
1102
+ <option value="" disabled ${n4 ? "" : "selected"} style="color: #9ca3af;">Select ${o3.toLowerCase()}...</option>
1103
+ ${e5}
1104
+ </select>
1105
+ </div>
1106
+ `;
1107
+ }
1108
+ return null;
1109
+ case "array":
1110
+ return "labels" === a2 ? null : c2 && c2.length > 0 ? renderCustomMultiSelect(i3, o3, c2, Array.isArray(t3) ? t3 : [], l2) : null;
1111
+ case "parent":
1112
+ case "issuelink":
1113
+ return `
1114
+ <div>
1115
+ <label for="${i3}" style="display:block; font-size:14px; font-weight:500; margin-bottom:6px;">
1116
+ ${o3} ${u2}
1117
+ </label>
1118
+ <input
1119
+ type="text"
1120
+ id="${i3}"
1121
+ class="sf-dynamic-field"
1122
+ data-field-id="${i3}"
1123
+ value="${t3 || ""}"
1124
+ placeholder="e.g., PROJ-123"
1125
+ style="${p2}"
1126
+ ${l2 ? "required" : ""}
1127
+ />
1128
+ </div>
1129
+ `;
1130
+ default:
1131
+ return ((_d = e4.operations) == null ? void 0 : _d.includes("set")) ? `
1132
+ <div>
1133
+ <label for="${i3}" style="display:block; font-size:14px; font-weight:500; margin-bottom:6px;">
1134
+ ${o3} ${u2}
1135
+ </label>
1136
+ <input
1137
+ type="text"
1138
+ id="${i3}"
1139
+ class="sf-dynamic-field"
1140
+ data-field-id="${i3}"
1141
+ value="${t3 || ""}"
1142
+ placeholder="Enter ${o3.toLowerCase()}"
1143
+ style="${p2}"
1144
+ ${l2 ? "required" : ""}
1145
+ />
1146
+ </div>
1147
+ ` : null;
1148
+ }
1149
+ })(e3, de.engTicketCustomFields[e3.fieldId || e3.key], o2)).filter(Boolean).join("");
1150
+ n2.innerHTML = s2 || "", i2.forEach((e3) => {
1151
+ var _a;
1152
+ const t3 = e3.fieldId || e3.key, n3 = (_a = e3.schema) == null ? void 0 : _a.type, i3 = e3.allowedValues;
1153
+ "array" === n3 && i3 && i3.length > 0 && setupCustomMultiSelectListeners(t3, (e4) => {
1154
+ de.engTicketCustomFields[t3] = e4;
1155
+ });
1156
+ });
1157
+ }
1158
+ function generateEngTicketFieldsHTML() {
1159
+ var _a;
1160
+ const e2 = he.integrationData;
1161
+ if (!e2) return "";
1162
+ const t2 = "jira" === ((_a = e2.provider) == null ? void 0 : _a.toLowerCase());
1163
+ let n2 = "<div style='display:flex; flex-direction:column; gap:12px;'>";
1164
+ return e2.teams && Array.isArray(e2.teams) && e2.teams.length > 0 && (n2 += '\n <div>\n <label for="sf-eng-ticket-team" style="display:block; font-size:14px; font-weight:500; margin-bottom:6px;">\n Team\n </label>\n <select id="sf-eng-ticket-team"\n style="width:100%; padding:8px 12px; font-size:14px; border:1px solid #cbd5e1; border-radius:6px; outline:none; appearance:none; cursor:pointer; background-color: white; color: #9ca3af;">\n <option value="" disabled selected style="color: #9ca3af;">Select team...</option>\n </select>\n </div>\n '), n2 += '\n <div>\n <label for="sf-eng-ticket-project" style="display:block; font-size:14px; font-weight:500; margin-bottom:6px;">\n Project\n </label>\n <select id="sf-eng-ticket-project"\n style="width:100%; padding:8px 12px; font-size:14px; border:1px solid #cbd5e1; border-radius:6px; outline:none; appearance:none; cursor:pointer; background-color: white; color: #9ca3af;">\n <option value="" disabled selected style="color: #9ca3af;">Select project...</option>\n </select>\n </div>\n ', t2 && (n2 += '\n <div>\n <label for="sf-eng-ticket-type" style="display:block; font-size:14px; font-weight:500; margin-bottom:6px;">\n Issue Type\n </label>\n <select id="sf-eng-ticket-type"\n style="width:100%; padding:8px 12px; font-size:14px; border:1px solid #cbd5e1; border-radius:6px; outline:none; appearance:none; cursor:pointer; background-color: white; color: #9ca3af;">\n <option value="" disabled selected style="color: #9ca3af;">Select project first...</option>\n </select>\n </div>\n '), n2 += '\n <div>\n <label for="sf-eng-ticket-priority" style="display:block; font-size:14px; font-weight:500; margin-bottom:6px;">\n Priority\n </label>\n <select id="sf-eng-ticket-priority"\n style="width:100%; padding:8px 12px; font-size:14px; border:1px solid #cbd5e1; border-radius:6px; outline:none; appearance:none; cursor:pointer; background-color: white;">\n </select>\n </div>\n ', e2.labels && Array.isArray(e2.labels) && e2.labels.length > 0 && (n2 += renderCustomMultiSelect("sf-eng-ticket-labels", "Labels", e2.labels, de.engTicketLabels, false)), t2 && e2.sprints && Array.isArray(e2.sprints) && e2.sprints.length > 0 && (n2 += '\n <div>\n <label for="sf-eng-ticket-sprint" style="display:block; font-size:14px; font-weight:500; margin-bottom:6px;">\n Sprint\n </label>\n <select id="sf-eng-ticket-sprint"\n style="width:100%; padding:8px 12px; font-size:14px; border:1px solid #cbd5e1; border-radius:6px; outline:none; appearance:none; cursor:pointer; background-color: white; color: #9ca3af;">\n <option value="" disabled selected style="color: #9ca3af;">Select sprint...</option>\n </select>\n </div>\n '), n2 += '\n <div id="sf-dynamic-fields-container" style="display: flex; flex-direction: column; gap: 12px;"></div>\n ', n2 += "</div>", n2;
1165
+ }
1166
+ function getShortcutKeyCmdCtrlLabel() {
1167
+ return (function isMacPlatform() {
1168
+ const e2 = navigator.userAgentData;
1169
+ return (e2 == null ? void 0 : e2.platform) ? e2.platform.toLowerCase().includes("mac") : /mac/i.test(navigator.userAgent);
1170
+ })() ? "⌘" : "Ctrl";
1171
+ }
1172
+ function getShortcutLabelFromContext(e2) {
1173
+ return (function getShortcutLabel(e3) {
1174
+ const t2 = [];
1175
+ return e3.requireCmdCtrl && t2.push(getShortcutKeyCmdCtrlLabel()), t2.push((function formatShortcutKeyLabel(e4) {
1176
+ return ({ escape: "esc" }[e4.toLowerCase()] || e4).toUpperCase();
1177
+ })(e3.key)), t2.map((e4) => `<span style="background: #F1F5F9; border:1px solid #cbd5e1; border-radius: 4px; padding: 0 4px; font-weight: 500; font-size: 12px; color: #94A3B8; line-height: 16px;">${e4}</span>`).join(e3.requireCmdCtrl ? " + " : "");
1178
+ })(he.shortcuts[e2]);
1179
+ }
1180
+ function getSessionIdSafely() {
1181
+ if (!he.resolveSessionId) throw new Error("getSessionId not defined");
1182
+ return he.resolveSessionId();
1183
+ }
1184
+ function openReportIssueModal() {
1185
+ ge ? stopRecording() : (injectModalHTML(), ye && document.body.appendChild(ye));
1186
+ }
1187
+ function closeModal() {
1188
+ he.deactivateIsolation(), document.activeElement instanceof HTMLElement && document.activeElement.blur(), (ye == null ? void 0 : ye.parentNode) && ye.parentNode.removeChild(ye), ye = null, ge || (function resetState() {
1189
+ de = getInitialState(), ue = null, pe = null;
1190
+ })(), fe && (clearInterval(fe), setTimerInterval(null));
1191
+ }
1192
+ function activateModalIsolation(e2) {
1193
+ e2.setAttribute("role", "dialog"), e2.setAttribute("aria-modal", "true"), e2.hasAttribute("tabindex") || e2.setAttribute("tabindex", "-1");
1194
+ const t2 = e2.querySelector("#sf-issue-description") || e2.querySelector("button, [href], input, select, textarea, [tabindex]:not([tabindex='-1'])") || e2, n2 = document.createElement("div"), i2 = document.createElement("div");
1195
+ n2.tabIndex = 0, i2.tabIndex = 0, n2.style.position = i2.style.position = "fixed", n2.style.width = i2.style.width = "1px", n2.style.height = i2.style.height = "1px", n2.style.outline = i2.style.outline = "none", e2.prepend(n2), e2.append(i2);
1196
+ const cycleFocus = (t3) => {
1197
+ const n3 = Array.from(e2.querySelectorAll("button, [href], input, select, textarea, [tabindex]:not([tabindex='-1'])")).filter((e3) => !e3.hasAttribute("disabled") && null !== e3.offsetParent);
1198
+ if (0 === n3.length) return;
1199
+ (t3 ? n3[0] : n3[n3.length - 1]).focus({ preventScroll: true });
1200
+ };
1201
+ n2.addEventListener("focus", () => cycleFocus(false)), i2.addEventListener("focus", () => cycleFocus(true));
1202
+ const quarantine = (t3) => {
1203
+ const n3 = t3.target;
1204
+ n3 && (e2.contains(n3) || (t3.stopImmediatePropagation(), t3.preventDefault(), refocus()));
1205
+ }, o2 = ["mousedown", "mouseup", "click", "pointerdown", "pointerup", "touchstart", "touchend", "wheel", "keydown", "keyup", "focus", "focusin", "focusout", "blur"];
1206
+ o2.forEach((e3) => document.addEventListener(e3, quarantine, true));
1207
+ let s2 = 0, a2 = null;
1208
+ const r2 = t2 instanceof HTMLTextAreaElement ? t2 : null, refocus = () => {
1209
+ if ((e2.querySelector(":focus") || r2 || t2 || e2).focus({ preventScroll: true }), r2 && document.activeElement === r2 && a2) try {
1210
+ r2.setSelectionRange(a2.start, a2.end, "none");
1211
+ } catch {
1212
+ }
1213
+ }, selectionInsideModal = () => {
1214
+ const t3 = "function" == typeof document.getSelection ? document.getSelection() : null;
1215
+ if (!t3) return false;
1216
+ if ([t3.anchorNode, t3.focusNode].filter(Boolean).some((t4) => e2.contains(t4))) return true;
1217
+ if (t3.rangeCount > 0) {
1218
+ const n3 = t3.getRangeAt(0).commonAncestorContainer;
1219
+ if (n3 && e2.contains(3 === n3.nodeType ? n3.parentNode : n3)) return true;
1220
+ }
1221
+ return false;
1222
+ };
1223
+ let l2 = 0;
1224
+ const watchdog = () => {
1225
+ const t3 = document.activeElement, n3 = t3 === document.body || null == t3 || !e2.contains(t3), i3 = selectionInsideModal();
1226
+ n3 && !i3 ? (l2 += 1, l2 >= 2 && (refocus(), l2 = 0)) : (l2 = 0, (() => {
1227
+ if (r2 && document.activeElement === r2) try {
1228
+ a2 = { start: r2.selectionStart ?? r2.value.length, end: r2.selectionEnd ?? r2.value.length };
1229
+ } catch {
1230
+ }
1231
+ })()), s2 = window.requestAnimationFrame(watchdog);
1232
+ };
1233
+ s2 = window.requestAnimationFrame(watchdog);
1234
+ const onBlurLike = () => {
1235
+ setTimeout(() => {
1236
+ const t3 = document.activeElement;
1237
+ (t3 === document.body || null == t3 || !e2.contains(t3)) && !selectionInsideModal() && refocus();
1238
+ }, 0);
1239
+ };
1240
+ return window.addEventListener("blur", onBlurLike, true), document.addEventListener("focusout", onBlurLike, true), setTimeout(() => t2.focus({ preventScroll: true }), 0), () => {
1241
+ try {
1242
+ n2.remove(), i2.remove();
1243
+ } catch {
1244
+ }
1245
+ o2.forEach((e3) => document.removeEventListener(e3, quarantine, true)), window.removeEventListener("blur", onBlurLike, true), document.removeEventListener("focusout", onBlurLike, true), s2 && cancelAnimationFrame(s2);
1246
+ };
1247
+ }
1248
+ function injectModalHTML(e2 = "lookback") {
1249
+ ye && (ye.remove(), ye = null), ye = document.createElement("div"), ye.id = "sf-report-issue-modal";
1250
+ const t2 = "startnow" === e2;
1251
+ ye.innerHTML = `
1252
+ <div style="position:fixed; inset:0; background:rgba(0,0,0,0.4); z-index:9998;"></div>
1253
+ <div style="position:fixed; top:50%; left:50%; transform:translate(-50%, -50%);
1254
+ background:#fff; border-radius:12px;
1255
+ width:476px; max-width:90%; max-height:90vh; z-index:9999;
1256
+ box-shadow:0 4px 20px rgba(0,0,0,0.15); font-family:sans-serif;
1257
+ display:flex; flex-direction:column;">
1258
+
1259
+ <!-- Fixed Header -->
1260
+ <div style="padding:24px 24px 16px 24px; flex-shrink:0; position:relative;">
1261
+ <button id="sf-modal-close-btn"
1262
+ style="position:absolute; top:24px; right:24px; background:none; border:none; cursor:pointer; padding:0;">
1263
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
1264
+ <path d="M18 6L6 18" stroke="#71717A" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
1265
+ <path d="M6 6L18 18" stroke="#71717A" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
1266
+ </svg>
1267
+ </button>
1268
+
1269
+ <h2 style="font-size:18px; font-weight:600; margin-bottom:16px;">Report Issue</h2>
1270
+
1271
+ <div id="sf-issue-tabs" style="display:flex; gap:4px; background:#f1f5f9; padding:6px; border-radius:6px; width: fit-content;">
1272
+ <button id="sf-tab-lookback" data-mode="lookback" class="sf-issue-tab ${t2 ? "" : "active"}"
1273
+ style="padding:6px 12px; border:none; background:${t2 ? "transparent" : "white"}; color: ${t2 ? "#64748B" : "#0F172A"}; border-radius:4px; font-size:14px; cursor:pointer; font-weight:500; height:32px; display: flex; align-items: center; gap: 8px;">
1274
+ Existing ${getShortcutLabelFromContext("openModalExistingMode")}
1275
+ </button>
1276
+ <button id="sf-tab-startnow" data-mode="startnow" class="sf-issue-tab ${t2 ? "active" : ""}"
1277
+ style="padding:6px 12px; border:none; background:${t2 ? "white" : "transparent"}; color: ${t2 ? "#0F172A" : "#64748B"}; border-radius:4px; font-size:14px; cursor:pointer; font-weight:500; height:32px; display: flex; align-items: center; gap: 8px;">
1278
+ Capture new ${getShortcutLabelFromContext("openModalCaptureNewMode")}
1279
+ </button>
1280
+ </div>
1281
+ </div>
1282
+
1283
+ <!-- Scrollable Content -->
1284
+ <div style="flex:1; overflow-y:auto; padding:0 24px;">
1285
+
1286
+ <div id="sf-issue-mode-info" style="display:flex; align-items:flex-start; gap:8px; margin-bottom:24px;">
1287
+ <svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg" style="margin-top:4px;">
1288
+ <g clip-path="url(#clip0_2477_11797)">
1289
+ <path d="M6.99935 12.8333C10.221 12.8333 12.8327 10.2216 12.8327 6.99996C12.8327 3.7783 10.221 1.16663 6.99935 1.16663C3.77769 1.16663 1.16602 3.7783 1.16602 6.99996C1.16602 10.2216 3.77769 12.8333 6.99935 12.8333Z" stroke="#A1A1AA" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
1290
+ <path d="M7 9.33333V7" stroke="#A1A1AA" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
1291
+ <path d="M7 4.66663H7.00583" stroke="#A1A1AA" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
1292
+ </g>
1293
+ <defs><clipPath id="clip0_2477_11797"><rect width="14" height="14" fill="white"/></clipPath></defs>
1294
+ </svg>
1295
+ <div style="font-size:14px;">
1296
+ ${t2 ? "I want to reproduce the issue right now." : "Something already happened. Capture the past few minutes."}
1297
+ </div>
1298
+ </div>
1299
+
1300
+ <label for="sf-issue-description" style="display:block; font-size:14px; font-weight:500; margin-bottom:6px;">
1301
+ What happened? (optional)
1302
+ </label>
1303
+ <textarea id="sf-issue-description" placeholder="Add description here"
1304
+ style="width:100%; height:80px; padding:8px 12px; font-size:14px;
1305
+ border:1px solid #cbd5e1; border-radius:6px; margin-bottom:20px;
1306
+ resize:none; outline:none;">${de.description}</textarea>
1307
+
1308
+ <!-- When did this happen Section -->
1309
+ <div id="sf-lookback-container" style="display:${t2 ? "none" : "block"}; margin-bottom:20px;">
1310
+ <label for="sf-lookback-minutes" style="display:block; font-size:14px; font-weight:500; margin-bottom:6px;">
1311
+ When did this happen?
1312
+ </label>
1313
+ <div style="display:flex; align-items:center; justify-content:space-between; gap:12px;">
1314
+ <div style="position:relative; display:flex; align-items:center; gap:6px;">
1315
+ <select id="sf-lookback-minutes"
1316
+ style="
1317
+ background: white;
1318
+ padding: 4px 8px;
1319
+ font-size: 14px;
1320
+ border: 1px solid #cbd5e1;
1321
+ border-radius: 6px;
1322
+ color: #64748B;
1323
+ font-family: sans-serif;
1324
+ outline: none;
1325
+ box-shadow: none;
1326
+ appearance: none;
1327
+ -webkit-appearance: none;
1328
+ -moz-appearance: none;
1329
+ padding-right: 28px;
1330
+ cursor: pointer;
1331
+ font-size: 14px;
1332
+ line-height: 20px;
1333
+ ">
1334
+ ${Array.from({ length: 15 }, (e3, t3) => {
1335
+ const n2 = t3 + 1;
1336
+ return `<option value="${n2}" ${2 === n2 ? "selected" : ""}>${n2}</option>`;
1337
+ }).join("")}
1338
+ </select>
1339
+ <div style="position:absolute; left:32px; top:50%; transform:translateY(-50%); pointer-events:none;">
1340
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none"
1341
+ xmlns="http://www.w3.org/2000/svg">
1342
+ <path d="M4 6L8 10L12 6" stroke="#52525B" stroke-width="1.33333"
1343
+ stroke-linecap="round" stroke-linejoin="round"/>
1344
+ </svg>
1345
+ </div>
1346
+ <span style="font-size:14px; color: #64748B;">minutes ago</span>
1347
+ </div>
1348
+ <div>
1349
+ <label for="sf-occurred-in-tab"
1350
+ style="display:flex; align-items:center; gap:6px; font-size:14px; color:#0F172A; cursor:pointer; white-space:nowrap;">
1351
+ <input
1352
+ type="checkbox"
1353
+ id="sf-occurred-in-tab"
1354
+ checked
1355
+ disabled
1356
+ style="width:16px; height:16px; accent-color:#295DBF; cursor:pointer;"
1357
+ />
1358
+ The issue occurred in this tab?
1359
+ </label>
1360
+ </div>
1361
+ </div>
1362
+ </div>
1363
+
1364
+ <!-- Divider -->
1365
+ <div style="height: 1px; background: #e2e8f0; margin: 20px 0;"></div>
1366
+
1367
+ <!-- Create an Issue & Engineering Ticket Section -->
1368
+ <div style="margin-bottom:20px;">
1369
+ <!-- Checkboxes on same line -->
1370
+ <div style="display:flex; align-items:center; gap:24px; margin-bottom:16px;">
1371
+ <label style="display:flex; align-items:center; gap:8px; font-size:14px; font-weight:500; cursor:pointer;">
1372
+ <input type="checkbox" id="sf-create-issue-checkbox" ${de.createIssue ? "checked" : ""}
1373
+ style="width:16px; height:16px; accent-color:#295DBF; cursor:pointer;">
1374
+ Create an Issue
1375
+ </label>
1376
+
1377
+ <label id="sf-create-eng-ticket-label" style="display:${he.integrationData ? "flex" : "none"}; align-items:center; gap:8px; font-size:14px; font-weight:500; cursor:pointer;">
1378
+ <input type="checkbox" id="sf-create-eng-ticket-checkbox" ${de.createEngTicket ? "checked" : ""}
1379
+ style="width:16px; height:16px; accent-color:#295DBF; cursor:pointer;">
1380
+ Create an Eng Ticket
1381
+ </label>
1382
+ </div>
1383
+
1384
+ <!-- Issue Title Field (always shown when create issue is checked) -->
1385
+ <div id="sf-issue-fields-container" style="display:${de.createIssue ? "block" : "none"};">
1386
+ <div style="display:flex; flex-direction:column; gap:12px;">
1387
+ <div>
1388
+ <label for="sf-issue-name" style="display:block; font-size:14px; font-weight:500; margin-bottom:6px;">
1389
+ Title <span style="color:#ef4444;">*</span>
1390
+ </label>
1391
+ <input type="text" id="sf-issue-name" placeholder="Enter title"
1392
+ value="${de.issueName}"
1393
+ style="width:100%; padding:8px 12px; font-size:14px; border:1px solid #cbd5e1; border-radius:6px; outline:none;">
1394
+ </div>
1395
+ </div>
1396
+ </div>
1397
+
1398
+ <!-- Engineering Ticket Fields (shown when create eng ticket is checked) -->
1399
+ <div id="sf-eng-ticket-fields-container" style="display:${de.createEngTicket ? "block" : "none"}; margin-top: ${de.createIssue ? "12px" : "0"};">
1400
+ ${generateEngTicketFieldsHTML()}
1401
+ </div>
1402
+ </div>
1403
+
1404
+ <!-- Divider -->
1405
+ <div style="height: 1px; background: #e2e8f0; margin-top: 20px;"></div>
1406
+ </div>
1407
+
1408
+ <!-- Fixed Footer -->
1409
+ <div style="padding:20px 24px; flex-shrink:0;">
1410
+ <div id="sf-modal-footer" style="display:flex; justify-content:${t2 ? "space-between" : "flex-end"}; align-items:flex-end;">
1411
+
1412
+ <div id="sf-record-button-container" style="display:${t2 ? "block" : "none"};">
1413
+ <div id="sf-recording-timer-label" style="display:none; font-size:14px; margin-bottom:20px;">
1414
+ Recording: <span id="sf-recording-timer-display">00:00</span>
1415
+ </div>
1416
+ <button id="sf-start-recording-btn"
1417
+ style="display:flex; align-items:center; gap:8px; border:1px solid #fc5555;
1418
+ background:transparent; padding:6px 12px; font-size:14px;
1419
+ color: #fc5555; border-radius:6px; cursor:pointer; font-weight:500;">
1420
+ <div id="sf-record-icon" style="padding: 6px; border-radius: 6px; border: 1px solid #fc5555; cursor: pointer;">
1421
+ <div style="width: 14px; height: 14px; background: #fc5555; border-radius: 50%; border: 1px solid #991b1b;"></div>
1422
+ </div>
1423
+ <span>Start Recording</span>
1424
+ ${getShortcutLabelFromContext("startRecording")}
1425
+ </button>
1426
+ </div>
1427
+
1428
+ <button id="sf-issue-submit-btn"
1429
+ style="background: #295DBF; color:white; border:none; padding:8px 16px;
1430
+ border-radius:6px; font-size:14px; line-height: 24px; font-weight:500;
1431
+ cursor:${t2 ? "not-allowed" : "pointer"}; opacity:${t2 ? "0.4" : "1"}; margin-bottom:1px" ${t2 ? "disabled" : ""}>
1432
+ Report <span style="margin-left: 8px; display: inline-flex; align-items: center; gap: 4px; color: #94A3B8; font-size: 12px; line-height:16px;">
1433
+ ${getShortcutLabelFromContext("submitReport")}
1434
+ </span>
1435
+ </button>
1436
+ </div>
1437
+ <div style="display:flex; justify-content:center; font-size: 12px; margin-top: 12px; color: #295dbf;">
1438
+ <a href="mailto:info@sailfishqa.com?subject=I'd%20love%20to%20learn%20more&body=Hey%2C%20Sailfish%20AI%20team%20-%20I'd%20love%20to%20learn%20more%20about%20Sailfish%20AI!">Powered by Sailfish AI</a>
1439
+ </div>
1440
+ </div>
1441
+ </div>
1442
+ `, de.mode = e2, document.body.appendChild(ye), (function bindListeners() {
1443
+ const e3 = ye == null ? void 0 : ye.querySelectorAll(".sf-issue-tab"), t3 = document.getElementById("sf-start-recording-btn"), n2 = document.getElementById("sf-modal-close-btn"), i2 = document.getElementById("sf-issue-submit-btn"), o2 = document.getElementById("sf-lookback-minutes");
1444
+ e3 == null ? void 0 : e3.forEach((e4) => {
1445
+ e4.addEventListener("click", (e5) => {
1446
+ const t4 = e5.currentTarget.dataset.mode;
1447
+ setActiveTab(t4), updateModeSpecificUI(t4);
1448
+ });
1449
+ }), n2 && (n2.onclick = closeModal);
1450
+ o2 && o2.addEventListener("change", () => {
1451
+ "lookback" === de.mode && (i2.disabled = false, i2.style.opacity = "1", i2.style.cursor = "pointer");
1452
+ });
1453
+ const s2 = ye == null ? void 0 : ye.querySelectorAll(".sf-collapsible-header");
1454
+ s2 == null ? void 0 : s2.forEach((e4) => {
1455
+ e4.addEventListener("click", (e5) => {
1456
+ const t4 = e5.currentTarget, n3 = t4.dataset.target, i3 = document.getElementById(n3), o3 = t4.querySelector(".sf-chevron");
1457
+ if (i3 && o3) {
1458
+ const e6 = "none" !== i3.style.display;
1459
+ i3.style.display = e6 ? "none" : "block", o3.innerHTML = /* @__PURE__ */ (function getChevronSVG(e7) {
1460
+ return e7 ? '<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">\n <path d="M12 6L8 10L4 6" stroke="#52525B" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>\n </svg>' : '<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">\n <path d="M6 12L10 8L6 4" stroke="#52525B" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>\n </svg>';
1461
+ })(!e6);
1462
+ }
1463
+ });
1464
+ });
1465
+ const a2 = document.getElementById("sf-create-issue-checkbox"), r2 = document.getElementById("sf-issue-fields-container"), l2 = document.getElementById("sf-create-eng-ticket-checkbox"), c2 = document.getElementById("sf-eng-ticket-fields-container");
1466
+ a2 && a2.addEventListener("change", () => {
1467
+ const e4 = a2.checked;
1468
+ de.createIssue = e4, localStorage.setItem(le, String(e4)), r2 && (r2.style.display = e4 ? "block" : "none"), !e4 && l2 && (l2.checked = false, de.createEngTicket = false, localStorage.setItem(ce, "false"), c2 && (c2.style.display = "none"));
1469
+ });
1470
+ l2 && l2.addEventListener("change", async () => {
1471
+ var _a;
1472
+ const e4 = l2.checked;
1473
+ if (de.createEngTicket = e4, localStorage.setItem(ce, String(e4)), e4 && !de.createIssue && (de.createIssue = true, localStorage.setItem(le, "true"), a2 && (a2.checked = true), r2 && (r2.style.display = "block")), c2 && (c2.style.display = e4 ? "block" : "none"), e4) {
1474
+ if (!hasValidIntegration()) return l2.checked = false, de.createEngTicket = false, localStorage.setItem(ce, "false"), c2 && (c2.style.display = "none"), void alert("No engineering ticket integration found. Please install and configure an integration (Jira, Linear, or Zendesk) first.");
1475
+ const e5 = getIntegrationData();
1476
+ if (e5) {
1477
+ if (!de.engTicketTeam && e5.defaultTeam && (de.engTicketTeam = e5.defaultTeam), !de.engTicketProject && e5.defaultProject && (de.engTicketProject = e5.defaultProject), !de.engTicketPriority && e5.defaultPriority && (de.engTicketPriority = e5.defaultPriority), updateFormWithIntegrationData(de), "jira" === ((_a = e5.provider) == null ? void 0 : _a.toLowerCase()) && e5.jiraReporterAccountId && de.engTicketProject) {
1478
+ getFieldsForProject(de.engTicketProject, de.engTicketIssueType).find((e6) => "reporter" === e6.fieldId) && !de.engTicketCustomFields.reporter && (de.engTicketCustomFields.reporter = e5.jiraReporterAccountId);
1479
+ }
1480
+ const t4 = document.getElementById("sf-eng-ticket-project"), n3 = document.getElementById("sf-eng-ticket-type");
1481
+ t4 && t4.value && renderDynamicFields(t4.value, n3 == null ? void 0 : n3.value);
1482
+ }
1483
+ }
1484
+ });
1485
+ const d2 = document.getElementById("sf-issue-name");
1486
+ d2 && d2.addEventListener("input", () => {
1487
+ de.issueName = d2.value;
1488
+ });
1489
+ bindEngTicketListeners(), t3 && (t3.onclick = () => {
1490
+ const e4 = document.getElementById("sf-issue-description");
1491
+ e4 && (de.description = e4.value), (function startCountdownThenRecord() {
1492
+ if (document.getElementById("sf-countdown-overlay")) return;
1493
+ const e5 = document.createElement("div");
1494
+ e5.id = "sf-countdown-overlay", e5.style.cssText = "\n position: fixed;\n inset: 0;\n background: rgba(0,0,0,0.6);\n z-index: 10001;\n display: flex;\n justify-content: center;\n align-items: center;\n font-size: 80px;\n font-weight: bold;\n color: white;\n font-family: sans-serif;\n ";
1495
+ let t4 = 3;
1496
+ e5.textContent = t4.toString(), document.body.appendChild(e5);
1497
+ const n3 = setInterval(async () => {
1498
+ if (t4--, t4 > 0) e5.textContent = t4.toString();
1499
+ else {
1500
+ clearInterval(n3), document.body.removeChild(e5), (function setRecordingStartTime(e6) {
1501
+ ue = e6;
1502
+ })(Date.now()), setIsRecording(true);
1503
+ try {
1504
+ const { enableFunctionSpanTracking: e6 } = await Promise.resolve().then(() => j);
1505
+ e6();
1506
+ } catch (e6) {
1507
+ console.error("[Report Issue] Failed to enable function span tracking:", e6);
1508
+ }
1509
+ closeModal(), (function showFloatingTimer() {
1510
+ const e6 = document.createElement("div");
1511
+ e6.id = "sf-recording-indicator", e6.style.cssText = "\n position: fixed;\n bottom: 20px;\n right: 20px;\n background: white;\n border-radius: 8px;\n box-shadow: 0 4px 20px rgba(0,0,0,0.15);\n padding: 8px 12px;\n font-family: sans-serif;\n font-size: 14px;\n display: flex;\n align-items: start;\n gap: 24px;\n z-index: 10000;\n cursor: pointer;\n ", e6.innerHTML = `
1512
+ <div style="display:flex; align-items:center; gap:8px;">
1513
+ <div style="width:32px; height:32px; background:#FC5555; border-radius:6px; border:1px solid #991b1b; display:flex; align-items:center; justify-content:center;">
1514
+ <div style="width:10px; height:10px; background:white; border-radius:2px;"></div>
1515
+ </div>
1516
+ <div style="display:flex; flex-direction:column; font-size:14px; line-height:20px;">
1517
+ <span id="sf-recording-timer" style="font-weight:600; color: #171717;">00:00</span>
1518
+ <span style="font-size:12px; line-height:12px; color: #71717A;">Max time 15 mins</span>
1519
+ </div>
1520
+ </div>
1521
+ <div style="display:flex; align-items:center; gap:4px; margin-left:auto; font-size:14px; color:#0F172A;">
1522
+ <span style="color: #71717A;">stop</span>
1523
+ <span style="display: inline-flex; align-items: center; gap: 4px; color: #94A3B8; font-size: 12px; line-height:16px;">
1524
+ ${getShortcutLabelFromContext("stopRecording")}
1525
+ </span>
1526
+ </div>
1527
+ `, e6.addEventListener("click", () => stopRecording()), document.body.appendChild(e6);
1528
+ const t5 = e6.querySelector("#sf-recording-timer");
1529
+ if (!t5) return;
1530
+ const n4 = setInterval(() => {
1531
+ const e7 = Date.now() - (ue ?? Date.now()), n5 = Math.floor(e7 / 6e4).toString().padStart(2, "0"), i3 = Math.floor(e7 % 6e4 / 1e3).toString().padStart(2, "0");
1532
+ t5.textContent = `${n5}:${i3}`;
1533
+ }, 1e3);
1534
+ setTimerInterval(n4);
1535
+ })();
1536
+ }
1537
+ }, 1e3);
1538
+ })();
1539
+ });
1540
+ ye == null ? void 0 : ye.addEventListener("click", (e4) => {
1541
+ var _a;
1542
+ if (e4.target.closest("#sf-issue-submit-btn")) {
1543
+ const e5 = ((_a = document.getElementById("sf-issue-description")) == null ? void 0 : _a.value) || "", t4 = de.mode;
1544
+ if (de.description = e5, de.createIssue && !de.issueName.trim()) return void alert("Issue title is required when creating an issue.");
1545
+ let n3, i3;
1546
+ if ("startnow" === t4) n3 = ue ?? Date.now() - 3e5, i3 = pe ?? Date.now();
1547
+ else {
1548
+ const e6 = 60 * Number((o2 == null ? void 0 : o2.value) || "2") * 1e3;
1549
+ i3 = Date.now(), n3 = i3 - e6;
1550
+ }
1551
+ if (de.createIssue) {
1552
+ const t5 = document.getElementById("sf-issue-name"), o3 = document.getElementById("sf-eng-ticket-team"), s3 = document.getElementById("sf-eng-ticket-project"), a3 = document.getElementById("sf-eng-ticket-priority"), r3 = document.getElementById("sf-eng-ticket-type"), l3 = (t5 == null ? void 0 : t5.value) || "", c3 = e5, d3 = (o3 == null ? void 0 : o3.value) || "", u2 = (s3 == null ? void 0 : s3.value) || "", p2 = a3 ? Number(a3.value) : 0, f2 = de.engTicketLabels, g2 = (r3 == null ? void 0 : r3.value) || "", m2 = { ...de.engTicketCustomFields };
1553
+ document.querySelectorAll(".sf-dynamic-field").forEach((e6) => {
1554
+ const t6 = e6, n4 = t6.dataset.fieldId;
1555
+ n4 && ("checkbox" === t6.type ? m2[n4] = t6.checked : "number" === t6.type ? m2[n4] = parseFloat(t6.value) || null : t6.classList.contains("sf-custom-multiselect") || (m2[n4] = t6.value));
1556
+ });
1557
+ const h2 = document.getElementById("sf-eng-ticket-sprint"), y2 = (h2 == null ? void 0 : h2.value) || de.engTicketSprint;
1558
+ if (y2) {
1559
+ const e6 = getSprintFieldId();
1560
+ m2[e6] = parseInt(y2, 10);
1561
+ }
1562
+ closeModal(), (async function createTriageAndIssue(e6, t6, n4, i4, o4, s4, a4, r4, l4, c4, d4, u3) {
1563
+ var _a2, _b;
1564
+ try {
1565
+ showStatusModal(true);
1566
+ const p3 = await createTriageAndIssueFromRecorder(he.apiKey, he.backendApi, getSessionIdSafely(), e6, t6, n4, i4, o4, s4, a4, r4, l4, c4, d4, u3), f3 = (_b = (_a2 = p3 == null ? void 0 : p3.data) == null ? void 0 : _a2.createTriageAndIssueFromRecorder) == null ? void 0 : _b.id;
1567
+ f3 ? showStatusModal(false, { type: "issue", id: f3 }) : (console.error("No Issue ID returned from backend."), showStatusModal(false, null));
1568
+ } catch (e7) {
1569
+ console.error("Error creating triage and issue:", e7), showStatusModal(false, null);
1570
+ }
1571
+ })(`${n3}`, `${i3}`, e5, l3, c3, de.createEngTicket, d3, u2, p2, f2, g2, m2);
1572
+ } else closeModal(), (async function createTriage(e6, t5, n4) {
1573
+ var _a2, _b;
1574
+ try {
1575
+ showStatusModal(true);
1576
+ const i4 = await createTriageFromRecorder(he.apiKey, he.backendApi, getSessionIdSafely(), e6, t5, n4), o3 = (_b = (_a2 = i4 == null ? void 0 : i4.data) == null ? void 0 : _a2.createTriageFromRecorder) == null ? void 0 : _b.id;
1577
+ o3 ? showStatusModal(false, { type: "triage", id: o3 }) : (console.error("No Triage ID returned from backend."), showStatusModal(false, null));
1578
+ } catch (e7) {
1579
+ console.error("Error creating triage:", e7), showStatusModal(false, null);
1580
+ }
1581
+ })(`${n3}`, `${i3}`, e5);
1582
+ }
1583
+ });
1584
+ })(), he.deactivateIsolation = activateModalIsolation(ye), he.integrationData && de.createEngTicket ? initializeEngTicketForm() : he.integrationData || (de.createEngTicket = false), he.apiKey && he.backendApi && refreshIntegrationData(he.apiKey, he.backendApi).then((e3) => {
1585
+ if (!e3 || !document.getElementById("sf-report-issue-modal")) return;
1586
+ he.integrationData = e3;
1587
+ const t3 = document.getElementById("sf-eng-ticket-fields-container");
1588
+ if (t3) {
1589
+ const e4 = generateEngTicketFieldsHTML();
1590
+ e4 && (t3.innerHTML = e4, initializeEngTicketForm(), bindEngTicketListeners(), updateFormWithIntegrationData(de), renderDynamicFields(de.engTicketProject, de.engTicketIssueType));
1591
+ }
1592
+ const n2 = document.getElementById("sf-create-eng-ticket-label");
1593
+ n2 && (n2.style.display = "flex");
1594
+ });
1595
+ }
1596
+ function initializeEngTicketForm() {
1597
+ var _a;
1598
+ const e2 = he.integrationData;
1599
+ if (e2) {
1600
+ if (!de.engTicketTeam && e2.defaultTeam && (de.engTicketTeam = e2.defaultTeam), !de.engTicketProject && e2.defaultProject && (de.engTicketProject = e2.defaultProject), !de.engTicketPriority && e2.defaultPriority && (de.engTicketPriority = e2.defaultPriority), updateFormWithIntegrationData(de), "jira" === ((_a = e2.provider) == null ? void 0 : _a.toLowerCase()) && e2.jiraReporterAccountId && de.engTicketProject) {
1601
+ getFieldsForProject(de.engTicketProject, de.engTicketIssueType).find((e3) => "reporter" === e3.fieldId) && !de.engTicketCustomFields.reporter && (de.engTicketCustomFields.reporter = e2.jiraReporterAccountId);
1602
+ }
1603
+ de.engTicketProject && renderDynamicFields(de.engTicketProject, de.engTicketIssueType);
1604
+ }
1605
+ }
1606
+ function setActiveTab(e2) {
1607
+ de.mode = e2;
1608
+ const t2 = ye == null ? void 0 : ye.querySelector("#sf-tab-lookback"), n2 = ye == null ? void 0 : ye.querySelector("#sf-tab-startnow");
1609
+ "lookback" === e2 ? (t2.style.background = "white", t2.style.color = "#0F172A", n2.style.background = "transparent", n2.style.color = "#64748B") : (n2.style.background = "white", n2.style.color = "#0F172A", t2.style.background = "transparent", t2.style.color = "#64748B");
1610
+ }
1611
+ function updateModeSpecificUI(e2) {
1612
+ const t2 = document.querySelector("#sf-issue-mode-info div"), n2 = document.getElementById("sf-issue-submit-btn"), i2 = document.getElementById("sf-record-button-container"), o2 = document.getElementById("sf-recording-timer-label"), s2 = document.getElementById("sf-recording-timer-display"), a2 = document.getElementById("sf-modal-footer"), r2 = document.getElementById("sf-lookback-container");
1613
+ if (t2 && n2 && i2 && o2 && s2 && a2 && r2) if ("startnow" === e2) {
1614
+ i2.style.display = "block", r2.style.display = "none", a2.style.justifyContent = "space-between", t2.textContent = "I want to reproduce the issue right now.";
1615
+ const e3 = null !== ue && null !== pe;
1616
+ if (n2.disabled = !e3, n2.style.opacity = e3 ? "1" : "0.4", n2.style.cursor = e3 ? "pointer" : "not-allowed", ue && pe) {
1617
+ const e4 = Math.floor((pe - ue) / 1e3), t3 = String(Math.floor(e4 / 60)).padStart(2, "0"), n3 = String(e4 % 60).padStart(2, "0");
1618
+ o2.style.display = "block", s2.textContent = `${t3}:${n3}`;
1619
+ } else o2.style.display = "none";
1620
+ } else i2.style.display = "none", o2.style.display = "none", r2.style.display = "block", a2.style.justifyContent = "flex-end", t2.textContent = "Something already happened. Capture the past few minutes.", n2.disabled = false, n2.style.opacity = "1", n2.style.cursor = "pointer";
1621
+ }
1622
+ function bindEngTicketListeners() {
1623
+ const e2 = document.getElementById("sf-eng-ticket-team"), t2 = document.getElementById("sf-eng-ticket-project"), n2 = document.getElementById("sf-eng-ticket-priority"), i2 = document.getElementById("sf-eng-ticket-labels-container"), o2 = document.getElementById("sf-eng-ticket-type"), s2 = document.getElementById("sf-eng-ticket-sprint");
1624
+ e2 && e2.addEventListener("change", () => {
1625
+ de.engTicketTeam = e2.value, e2.style.color = e2.value ? "" : "#9ca3af";
1626
+ const t3 = document.getElementById("sf-eng-ticket-project");
1627
+ if (t3) {
1628
+ de.engTicketProject = "", de.engTicketCustomFields = {};
1629
+ const n3 = getProjectsForTeam(e2.value);
1630
+ t3.innerHTML = '<option value="">Select project...</option>', n3.forEach((e3) => {
1631
+ const n4 = document.createElement("option");
1632
+ n4.value = e3.id || e3.value || e3, n4.textContent = e3.name || e3.label || e3, t3.appendChild(n4);
1633
+ });
1634
+ }
1635
+ }), t2 && t2.addEventListener("change", () => {
1636
+ var _a;
1637
+ de.engTicketProject = t2.value, t2.style.color = t2.value ? "" : "#9ca3af", de.engTicketCustomFields = {};
1638
+ const e3 = getIntegrationData();
1639
+ if (e3 && o2 && (updateIssueTypeOptions(o2, t2.value), de.engTicketIssueType = o2.value), e3 && "jira" === ((_a = e3.provider) == null ? void 0 : _a.toLowerCase()) && e3.jiraReporterAccountId && t2.value) {
1640
+ getFieldsForProject(t2.value, de.engTicketIssueType).find((e4) => "reporter" === e4.fieldId) && (de.engTicketCustomFields.reporter = e3.jiraReporterAccountId);
1641
+ }
1642
+ renderDynamicFields(t2.value, de.engTicketIssueType);
1643
+ }), s2 && s2.addEventListener("change", () => {
1644
+ de.engTicketSprint = s2.value, s2.style.color = s2.value ? "" : "#9ca3af";
1645
+ }), n2 && n2.addEventListener("change", () => {
1646
+ de.engTicketPriority = Number(n2.value);
1647
+ }), i2 && setupCustomMultiSelectListeners("sf-eng-ticket-labels", (e3) => {
1648
+ de.engTicketLabels = e3;
1649
+ }), o2 && o2.addEventListener("change", () => {
1650
+ de.engTicketIssueType = o2.value, o2.style.color = o2.value ? "" : "#9ca3af";
1651
+ const e3 = document.getElementById("sf-eng-ticket-project");
1652
+ if (e3 && e3.value) {
1653
+ const t3 = de.engTicketCustomFields.reporter;
1654
+ de.engTicketCustomFields = {}, t3 && (de.engTicketCustomFields.reporter = t3), renderDynamicFields(e3.value, o2.value);
1655
+ }
1656
+ });
1657
+ const a2 = document.getElementById("sf-dynamic-fields-container");
1658
+ a2 && (a2.addEventListener("input", (e3) => {
1659
+ const t3 = e3.target;
1660
+ if (t3.classList.contains("sf-dynamic-field")) {
1661
+ const e4 = t3.dataset.fieldId;
1662
+ e4 && ("checkbox" === t3.type ? de.engTicketCustomFields[e4] = t3.checked : "number" === t3.type ? de.engTicketCustomFields[e4] = parseFloat(t3.value) || null : de.engTicketCustomFields[e4] = t3.value);
1663
+ }
1664
+ }), a2.addEventListener("change", (e3) => {
1665
+ const t3 = e3.target;
1666
+ if (t3.classList.contains("sf-dynamic-field")) {
1667
+ const e4 = t3.dataset.fieldId;
1668
+ if (e4 && (de.engTicketCustomFields[e4] = t3.value), "SELECT" === t3.tagName) {
1669
+ const e5 = t3;
1670
+ e5.style.color = e5.value ? "" : "#9ca3af";
1671
+ }
1672
+ }
1673
+ }));
1674
+ }
1675
+ async function stopRecording() {
1676
+ var _a;
1677
+ !(function setRecordingEndTime(e2) {
1678
+ pe = e2;
1679
+ })(Date.now()), setIsRecording(false), fe && (clearInterval(fe), setTimerInterval(null)), (_a = document.getElementById("sf-recording-indicator")) == null ? void 0 : _a.remove();
1680
+ try {
1681
+ const { disableFunctionSpanTracking: e2 } = await Promise.resolve().then(() => j);
1682
+ e2();
1683
+ } catch (e2) {
1684
+ console.error("[Report Issue] Failed to disable function span tracking:", e2);
1685
+ }
1686
+ !(function reopenModalAfterStop() {
1687
+ injectModalHTML("startnow");
1688
+ const e2 = document.getElementById("sf-start-recording-btn");
1689
+ if (e2) {
1690
+ const t3 = e2.querySelector("span");
1691
+ t3 && (t3.textContent = "Re-record");
1692
+ }
1693
+ const t2 = document.getElementById("sf-recording-timer-label"), n2 = document.getElementById("sf-recording-timer-display");
1694
+ if (t2 && n2 && ue && pe) {
1695
+ const e3 = Math.floor((pe - ue) / 1e3), i3 = Math.floor(e3 / 60).toString().padStart(2, "0"), o3 = (e3 % 60).toString().padStart(2, "0");
1696
+ n2.textContent = `${i3}:${o3}`, t2.style.display = "block";
1697
+ }
1698
+ const i2 = document.getElementById("sf-issue-description");
1699
+ i2 && (i2.value = de.description);
1700
+ const o2 = document.querySelector('input[value="startnow"]');
1701
+ o2 && (o2.checked = true);
1702
+ const s2 = document.getElementById("sf-inline-record-chip"), a2 = document.getElementById("sf-inline-record-timer");
1703
+ if (s2 && a2) {
1704
+ const e3 = Math.floor(((pe ?? 0) - (ue ?? 0)) / 1e3), t3 = Math.floor(e3 / 60).toString().padStart(2, "0"), n3 = Math.floor(e3 % 60).toString().padStart(2, "0");
1705
+ a2.textContent = `${t3}:${n3}`, a2.style.color = "black", s2.style.display = "flex";
1706
+ }
1707
+ const r2 = document.getElementById("sf-issue-submit-btn");
1708
+ r2.disabled = false, r2.style.opacity = "1", r2.style.cursor = "pointer";
1709
+ })();
1710
+ }
1711
+ function showStatusModal(e2, t2) {
1712
+ !(function showTriageStatusModal(e3, t3, n2) {
1713
+ var _a;
1714
+ !(function removeExistingModals() {
1715
+ var _a2, _b;
1716
+ (_a2 = document.getElementById("sf-report-issue-modal")) == null ? void 0 : _a2.remove(), (_b = document.getElementById("sf-triage-status-modal")) == null ? void 0 : _b.remove();
1717
+ })();
1718
+ const i2 = n2 ? `${he.triageBaseUrl}/issues/${n2}?from=inAppReportIssue` : t3 ? `${he.triageBaseUrl}/triage/${t3}?from=inAppReportIssue` : "", o2 = document.createElement("div");
1719
+ o2.id = "sf-triage-status-modal", Object.assign(o2.style, { position: "fixed", inset: "0", zIndex: "9998", display: "flex", alignItems: "center", justifyContent: "center" });
1720
+ const s2 = e3 ? "Reporting Issue..." : "Issue reported!", a2 = e3 ? '<p style="font-size:14px; color:#64748b; line-height:20px;">This may take ~10 seconds</p>' : "", r2 = e3 ? '<div style="display:flex; justify-content:center; align-items:center; padding: 40px 0;">\n <div style="width:24px; height:24px; border:2px solid #295dbf; border-top:2px solid white; border-radius:50%; animation:spin 1s linear infinite;"></div>\n </div>' : "", l2 = e3 ? "" : '<div id="sf-copied-status" style="display:none; font-size:12px; font-weight:500; color:white;\n background-color:#22c55e; padding:4px 8px; border-radius:6px; white-space:nowrap; align-items:center; gap:6px;">\n <svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">\n <path fill-rule="evenodd" clip-rule="evenodd" d="M21 7.5L9 19.5L3 13.5L5.25 11.25L9 15L18.75 5.25L21 7.5Z" fill="white"/>\n </svg>\n Copied\n </div>';
1721
+ o2.innerHTML = `
1722
+ <div style="position:fixed; inset:0; background:rgba(0,0,0,0.4); z-index:9998;"></div>
1723
+ <div id="sf-triage-card"
1724
+ style="position:relative; background:#fff; padding:24px; border-radius:12px; width:300px; max-width:90%;
1725
+ font-family:sans-serif; box-shadow:0 4px 20px rgba(0,0,0,0.15);
1726
+ z-index:9999; opacity:1; transition:opacity 300ms ease;">
1727
+ <div style="position:absolute; top:24px; right:48px;">${l2}</div>
1728
+
1729
+ <button id="sf-triage-modal-close"
1730
+ style="position:absolute; top:24px; right:16px; background:none; border:none; cursor:pointer;">
1731
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
1732
+ <path d="M18 6L6 18" stroke="#71717A" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
1733
+ <path d="M6 6L18 18" stroke="#71717A" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
1734
+ </svg>
1735
+ </button>
1736
+
1737
+ <h2 style="font-size:18px; font-weight:600; margin-bottom:${e3 ? 8 : 40}px; line-height:28px;">${s2}</h2>
1738
+ ${a2}
1739
+ ${r2}
1740
+
1741
+ <div style="display:flex; justify-content:flex-end; align-items:center; gap:8px;">
1742
+ <button id="sf-copy-triage-link"
1743
+ style="background:white; border:1px solid #e2e8f0; padding:8px 16px; border-radius:6px;
1744
+ font-size:14px; color: #0f172a; cursor:pointer;">
1745
+ Share
1746
+ </button>
1747
+ <button id="sf-view-triage-btn"
1748
+ style="display:flex; align-items:center; gap:8px; background:#295dbf; border:none;
1749
+ padding:8px 16px; border-radius:6px; font-size:14px; color:white; cursor:pointer;">
1750
+ View
1751
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
1752
+ <path d="M12 8.66667V12.6667C12 13.0203 11.8595 13.3594 11.6095 13.6095C11.3594 13.8595 11.0203 14 10.6667 14H3.33333C2.97971 14 2.64057 13.8595 2.39052 13.6095C2.14048 13.3594 2 13.0203 2 12.6667V5.33333C2 4.97971 2.14048 4.64057 2.39052 4.39052C2.64057 4.14048 2.97971 4 3.33333 4H7.33333" stroke="white" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
1753
+ <path d="M10 2H14V6" stroke="white" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
1754
+ <path d="M6.66602 9.33333L13.9993 2" stroke="white" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
1755
+ </svg>
1756
+ </button>
1757
+ </div>
1758
+ </div>
1759
+ <style>
1760
+ @keyframes spin { to { transform: rotate(360deg); } }
1761
+ </style>
1762
+ `, document.body.appendChild(o2);
1763
+ const c2 = o2.querySelector("#sf-triage-card");
1764
+ (_a = document.getElementById("sf-triage-modal-close")) == null ? void 0 : _a.addEventListener("click", () => {
1765
+ fadeCardAndRemove(o2, c2, 300);
1766
+ });
1767
+ const d2 = document.getElementById("sf-copy-triage-link"), u2 = document.getElementById("sf-view-triage-btn");
1768
+ e3 ? (d2.disabled = true, d2.style.opacity = "0.4", d2.style.cursor = "not-allowed", u2.disabled = true, u2.style.opacity = "0.4", u2.style.cursor = "not-allowed") : (d2.disabled = false, d2.addEventListener("click", () => {
1769
+ navigator.clipboard.writeText(i2).then(() => {
1770
+ const e4 = document.getElementById("sf-copied-status");
1771
+ e4 && (e4.style.display = "flex");
1772
+ });
1773
+ }), u2.disabled = false, u2.addEventListener("click", () => {
1774
+ (t3 || n2) && window.open(i2, "_blank");
1775
+ }), setTimeout(() => fadeCardAndRemove(o2, c2, 300), 1e4));
1776
+ })(e2, "triage" === (t2 == null ? void 0 : t2.type) ? t2.id : void 0, "issue" === (t2 == null ? void 0 : t2.type) ? t2.id : void 0);
1777
+ }
1778
+ function fadeCardAndRemove(e2, t2, n2 = 300) {
1779
+ t2.style.opacity = "0", t2.addEventListener("transitionend", () => e2.remove(), { once: true }), setTimeout(() => e2.remove(), n2 + 100);
1780
+ }
1781
+ const be = Object.freeze(Object.defineProperty({ __proto__: null, ReportIssueContext: he, openReportIssueModal, setupIssueReporting: function setupIssueReporting(e2) {
1782
+ he.apiKey = e2.apiKey, he.backendApi = e2.backendApi, he.resolveSessionId = e2.getSessionId, he.integrationData = e2.integrationData || null, e2.customBaseUrl && (he.triageBaseUrl = e2.customBaseUrl), he.shortcuts = (function mergeShortcutsConfig(e3) {
1783
+ const t3 = { ...me };
1784
+ if (!e3) return t3;
1785
+ "boolean" == typeof e3.enabled && (t3.enabled = e3.enabled);
1786
+ const n2 = ["openModalExistingMode", "openModalCaptureNewMode", "closeModal", "submitReport", "startRecording", "stopRecording"];
1787
+ for (const i2 of n2) {
1788
+ const n3 = e3[i2];
1789
+ n3 && "object" == typeof n3 && (t3[i2] = { ...t3[i2], ...n3 }, t3[i2].key = t3[i2].key.toLowerCase());
1790
+ }
1791
+ return t3;
1792
+ })(e2.shortcuts);
1793
+ const { shortcuts: t2 } = he;
1794
+ window.addEventListener("keydown", (e3) => {
1795
+ const n2 = (function isTypingInInput() {
1796
+ const e4 = document.activeElement;
1797
+ return e4 instanceof HTMLInputElement || e4 instanceof HTMLTextAreaElement || e4 instanceof HTMLElement && e4.isContentEditable;
1798
+ })(), i2 = e3.key.toLowerCase(), o2 = e3.metaKey || e3.ctrlKey, s2 = !!document.getElementById("sf-report-issue-modal"), a2 = !n2 && (t2.enabled || s2), shortcutUsed = (e4) => i2 === t2[e4].key && o2 === t2[e4].requireCmdCtrl, r2 = s2 ? (e4) => {
1799
+ setActiveTab(e4), updateModeSpecificUI(e4);
1800
+ } : injectModalHTML;
1801
+ if (a2 && shortcutUsed("openModalExistingMode")) return e3.preventDefault(), void r2("lookback");
1802
+ if (a2 && shortcutUsed("openModalCaptureNewMode")) return e3.preventDefault(), void r2("startnow");
1803
+ if (s2 && !ge && shortcutUsed("closeModal")) return e3.preventDefault(), void closeModal();
1804
+ if (s2 && shortcutUsed("submitReport")) {
1805
+ const t3 = document.getElementById("sf-issue-submit-btn");
1806
+ return void (t3 && !t3.disabled && (e3.preventDefault(), t3.click()));
1807
+ }
1808
+ if (ge && i2 === t2.stopRecording.key && o2 === t2.stopRecording.requireCmdCtrl) return e3.preventDefault(), void stopRecording();
1809
+ if (s2 && "startnow" === de.mode && i2 === t2.startRecording.key && o2 === t2.startRecording.requireCmdCtrl && !n2) {
1810
+ const t3 = document.getElementById("sf-start-recording-btn");
1811
+ return void (t3 && (e3.preventDefault(), t3.click()));
1812
+ }
1813
+ });
1814
+ } }, Symbol.toStringTag, { value: "Module" })), Se = readDebugFlag(), we = /* @__PURE__ */ new Map();
1815
+ function getCachedRegex(e2, t2) {
1816
+ const n2 = `${e2}|${t2}`;
1817
+ let i2 = we.get(n2);
1818
+ return i2 || (i2 = new RegExp(e2, t2), we.set(n2, i2)), i2;
1819
+ }
1820
+ const ve = new Set([".js", ".mjs", ".cjs", ".ts", ".css", ".scss", ".sass", ".less", ".styl", ".stylus", ".png", ".jpg", ".jpeg", ".gif", ".svg", ".webp", ".avif", ".bmp", ".ico", ".tiff", ".tif", ".heic", ".woff", ".woff2", ".ttf", ".otf", ".eot", ".mp4", ".webm", ".ogv", ".mp3", ".wav", ".flac", ".pdf", ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".csv", ".json", ".xml", ".txt", ".zip", ".rar", ".gz", ".tar", ".7z", ".map", ".webmanifest"].map((e2) => e2.toLowerCase())), ke = ["t.co", "*.twitter.com", "*.gravatar.com", "*.googleapis.com", "*.amazonaws.com", "*.smooch.io", "*.zendesk.com", "*.zdassets.com"], xe = [400, 403], Ie = "CORS", Te = "authorization", Ee = "Authorization", Ce = { recordCanvas: false, recordCrossOriginIframes: false, collectFonts: false, inlineImages: false, recordPassword: false, recordRealName: true, recordCreditCardInfo: false, recordSsn: false, recordDob: false, sampling: {}, enableFiberTracking: false }, $e = { level: ["info", "log", "warn", "error"], lengthThreshold: 1e4, stringifyOptions: { stringLengthLimit: 1e3, numOfKeysLimit: 20, depthOfLimit: 4 }, logger: "console" };
1821
+ function maskAuthorizationHeader(e2) {
1822
+ const t2 = e2[Te] ? Te : e2[Ee] ? Ee : null;
1823
+ if (!t2) return;
1824
+ const n2 = e2[t2], i2 = n2.indexOf(" ");
1825
+ if (-1 !== i2) {
1826
+ const o2 = n2.slice(0, i2 + 1), s2 = n2.slice(i2 + 1);
1827
+ s2.length > 8 ? e2[t2] = o2 + s2.slice(0, 4) + "*".repeat(s2.length - 8) + s2.slice(-4) : e2[t2] = o2 + "*".repeat(s2.length);
1828
+ } else n2.length > 8 ? e2[t2] = n2.slice(0, 4) + "*".repeat(n2.length - 8) + n2.slice(-4) : e2[t2] = "*".repeat(n2.length);
1829
+ }
1830
+ function trackDomainChangesOnce() {
1831
+ const e2 = window.__sailfish_recorder || (window.__sailfish_recorder = {});
1832
+ if (e2.routeWatcherIntervalId) return;
1833
+ let t2 = window.location.href.split("?")[0];
1834
+ const checkDomainChange = (e3 = false) => {
1835
+ const n3 = window.location.href.split("?")[0];
1836
+ if (e3 || n3 !== t2) {
1837
+ t2 = n3;
1838
+ const e4 = uuidv4(), i2 = sessionStorage.getItem("pageVisitUUID");
1839
+ sessionStorage.setItem("pageVisitUUID", e4), sessionStorage.setItem("prevPageVisitUUID", i2), invalidateUrlCache();
1840
+ sendMessage({ type: "routeChange", data: { url: n3, timestamp: Date.now(), page_visit_uuid: e4, prev_page_visit_uuid: i2 } });
1841
+ }
1842
+ }, n2 = /* @__PURE__ */ (function debounce(e3, t3) {
1843
+ let n3;
1844
+ return function(...i2) {
1845
+ clearTimeout(n3), n3 = setTimeout(() => e3(...i2), t3);
1846
+ };
1847
+ })(() => checkDomainChange(), 500);
1848
+ checkDomainChange(true), e2.routeWatcherIntervalId = window.setInterval(n2, 1e3);
1849
+ }
1850
+ function sendUserDeviceUuid() {
1851
+ sendMessage({ type: "userDeviceUuid", userDeviceUuid: (function getOrSetUserDeviceUuid() {
1852
+ let e2 = null;
1853
+ if (g) try {
1854
+ e2 = localStorage.getItem("sailfishUserDeviceUuid");
1855
+ } catch {
1856
+ }
1857
+ if (!e2) {
1858
+ e2 = uuidv4();
1859
+ try {
1860
+ g && localStorage.setItem("sailfishUserDeviceUuid", e2);
1861
+ } catch {
1862
+ }
1863
+ }
1864
+ return e2;
1865
+ })() });
1866
+ }
1867
+ function handleVisibilityChange() {
1868
+ const e2 = document.visibilityState, t2 = Date.now();
1869
+ "visible" === e2 && getOrSetSessionId();
1870
+ try {
1871
+ sendMessage({ type: "visibilityChange", data: { state: e2, url: window.location.href.split("?")[0], timestamp: t2, ...getUrlAndStoredUuids() } }), Se && console.log(`[Sailfish] Tab became ${e2}, sent visibility change event`);
1872
+ } catch (e3) {
1873
+ console.warn("[Sailfish] Failed to send visibility change event:", e3);
1874
+ }
1875
+ sessionStorage.setItem("tabVisibilityChanged", t2.toString()), sessionStorage.setItem("tabVisibilityState", e2), invalidateUrlCache();
1876
+ }
1877
+ function clearPageVisitDataFromSessionStorage() {
1878
+ m && (sessionStorage.removeItem("pageVisitUUID"), sessionStorage.removeItem("prevPageVisitUUID"), sessionStorage.removeItem("tabVisibilityChanged"), sessionStorage.removeItem("tabVisibilityState"), invalidateUrlCache());
1879
+ }
1880
+ let Fe = false;
1881
+ function _ensureModuleSideEffects() {
1882
+ Fe || (Fe = true, restoreFuncSpanState(), (function ensureSessionListeners() {
1883
+ S || (S = true, p && window.addEventListener("beforeunload", () => {
1884
+ window.name = y + window.name;
1885
+ }));
1886
+ })(), p && (sendUserDeviceUuid(), (function sendTimeZone() {
1887
+ sendMessage({ type: "timeZone", timezone: Intl.DateTimeFormat().resolvedOptions().timeZone });
1888
+ })()), f && document.addEventListener("visibilitychange", handleVisibilityChange), p && window.addEventListener("beforeunload", () => {
1889
+ clearPageVisitDataFromSessionStorage();
1890
+ }));
1891
+ }
1892
+ function matchUrlWithWildcard(e2, t2) {
1893
+ let n2, i2;
1894
+ if ("string" == typeof e2 ? n2 = e2 : "undefined" != typeof URL && e2 instanceof URL ? n2 = e2.href : "undefined" != typeof Request && e2 instanceof Request ? n2 = e2.url : null != e2 && "function" == typeof e2.toString && (n2 = e2.toString()), !n2) return false;
1895
+ try {
1896
+ const e3 = "undefined" != typeof window ? window.location.href : "http://localhost/";
1897
+ i2 = new URL(n2, e3);
1898
+ } catch {
1899
+ return false;
1900
+ }
1901
+ const { hostname: o2, pathname: s2, port: a2, protocol: r2 } = i2;
1902
+ if (!/^https?:$/.test(r2)) return false;
1903
+ const l2 = o2.startsWith("www.") ? o2.slice(4).toLowerCase() : o2.toLowerCase();
1904
+ return t2.some((e3) => {
1905
+ const t3 = String(e3 || "").replace(/^[a-zA-Z]+:\/\//, "");
1906
+ let [n3, i3] = t3.split("/", 2), o3 = "";
1907
+ n3.includes(":") && ([n3, o3] = n3.split(":"));
1908
+ const r3 = getCachedRegex(`^${n3.replace(/\./g, "\\.").replace(/\*/g, ".*")}$`, "i"), c2 = l2.startsWith("www.") ? l2.slice(4) : l2;
1909
+ if (o3 && a2 !== o3) return false;
1910
+ if (n3.startsWith("*.")) {
1911
+ const e4 = n3.slice(2).toLowerCase();
1912
+ if (!(l2 === e4 || c2 === e4 || l2.endsWith("." + e4))) return false;
1913
+ if (i3) {
1914
+ return getCachedRegex(`^/${i3.replace(/\*/g, ".*").replace(/\/$/, "")}`, "i").test(s2);
1915
+ }
1916
+ return true;
1917
+ }
1918
+ if (!r3.test(c2) && !r3.test(l2)) return false;
1919
+ if (i3) {
1920
+ return getCachedRegex(`^/${i3.replace(/\*/g, ".*").replace(/\/$/, "")}`, "i").test(s2);
1921
+ }
1922
+ return true;
1923
+ });
1924
+ }
1925
+ function createSkipHeadersPropagationChecker(e2 = []) {
1926
+ const t2 = [...ke, ...e2];
1927
+ return function shouldSkipHeadersPropagation(e3) {
1928
+ let n2;
1929
+ try {
1930
+ n2 = new URL("string" == typeof e3 ? e3 : String((e3 == null ? void 0 : e3.url) ?? e3), window.location.href);
1931
+ } catch {
1932
+ return true;
1933
+ }
1934
+ const i2 = n2.pathname.toLowerCase(), o2 = i2.lastIndexOf(".");
1935
+ return !(-1 === o2 || !ve.has(i2.slice(o2))) || !!matchUrlWithWildcard(e3, t2);
1936
+ };
1937
+ }
1938
+ function setupFetchInterceptor(e2 = [], t2 = { captureStreamingResponseBody: true, captureResponseBodyMaxMb: 10, captureStreamPrefixKb: 64, captureStreamTimeoutMs: 1e4 }) {
1939
+ const i2 = window.fetch, o2 = getOrSetSessionId(), s2 = createSkipHeadersPropagationChecker(e2), a2 = ["text/event-stream", "application/x-ndjson", "application/stream+json", "application/grpc", "application/grpc-web"], r2 = ["application/octet-stream"];
1940
+ window.fetch = new Proxy(i2, { apply: async (e3, i3, l2) => {
1941
+ let c2, d2 = l2[0], u2 = l2[1] || {};
1942
+ if ("string" == typeof d2) c2 = d2;
1943
+ else if (d2 instanceof Request) c2 = d2.url;
1944
+ else {
1945
+ if (!(d2 instanceof URL)) return e3.apply(i3, l2);
1946
+ c2 = d2.href;
1947
+ }
1948
+ return s2(c2) ? e3.apply(i3, l2) : (async function injectHeaderWrapper(e4, i4, o3, s3, l3, c3, d3) {
1949
+ var _a, _b;
1950
+ if (!c3) return e4.apply(i4, o3);
1951
+ let u3 = uuidv4();
1952
+ const p2 = getUrlAndStoredUuids(), f2 = l3.method || "GET", g2 = Date.now();
1953
+ let m2, h2 = {}, y2 = null;
1954
+ try {
1955
+ if (s3 instanceof Request) {
1956
+ s3.headers.forEach((e5, t3) => {
1957
+ h2[t3] = e5;
1958
+ });
1959
+ try {
1960
+ y2 = s3.clone();
1961
+ } catch (e5) {
1962
+ y2 = null;
1963
+ }
1964
+ } else l3.headers && (l3.headers instanceof Headers ? l3.headers.forEach((e5, t3) => {
1965
+ h2[t3] = e5;
1966
+ }) : Array.isArray(l3.headers) ? l3.headers.forEach(([e5, t3]) => {
1967
+ h2[e5] = t3;
1968
+ }) : h2 = { ...l3.headers }), m2 = l3.body;
1969
+ } catch (e5) {
1970
+ Se && console.warn("[Sailfish] Failed to capture request data:", e5);
1971
+ }
1972
+ delete h2[n];
1973
+ const b2 = getFuncSpanHeader();
1974
+ b2 && delete h2[b2.name];
1975
+ const S2 = `${c3}/${p2.page_visit_uuid}/${u3}`;
1976
+ h2[n] = S2, b2 && (h2[b2.name] = b2.value);
1977
+ maskAuthorizationHeader(h2);
1978
+ try {
1979
+ let b3 = await (async function injectHeader(e5, t3, i5, o4, s4, a3, r3) {
1980
+ const l4 = getFuncSpanHeader();
1981
+ if (i5 instanceof Request) {
1982
+ const c4 = i5.clone(), d4 = new Headers(c4.headers);
1983
+ d4.set(n, `${s4}/${a3}/${r3}`), l4 && (d4.set(l4.name, l4.value), Se && console.log("[Sailfish] Added funcspan header to HTTP Request:", { url: i5.url, header: l4.name }));
1984
+ const u4 = new Request(c4, { headers: d4 });
1985
+ return await e5.call(t3, u4, o4);
1986
+ }
1987
+ {
1988
+ const c4 = { ...o4 }, d4 = new Headers(o4.headers || {});
1989
+ return d4.set(n, `${s4}/${a3}/${r3}`), l4 && (d4.set(l4.name, l4.value), Se && console.log("[Sailfish] Added funcspan header to HTTP fetch:", { url: "string" == typeof i5 ? i5 : i5.href, header: l4.name })), c4.headers = d4, await e5.call(t3, i5, c4);
1990
+ }
1991
+ })(e4, i4, s3, l3, c3, p2.page_visit_uuid, u3), S3 = false;
1992
+ xe.includes(b3.status) && (Se && console.log("Perform retry as status was fail:", b3), delete h2[n], b3 = await (async function retryWithoutPropagateHeaders(e5, t3, i5, o4) {
1993
+ try {
1994
+ let o5 = i5[0], s4 = i5[1] || {};
1995
+ if ("string" == typeof o5 || o5 instanceof URL) {
1996
+ const i6 = { ...s4 }, a3 = new Headers(s4.headers || {});
1997
+ a3.delete(n), i6.headers = a3;
1998
+ return await e5.call(t3, o5, i6);
1999
+ }
2000
+ if (o5 instanceof Request) {
2001
+ const i6 = o5.clone(), a3 = new Headers(i6.headers);
2002
+ a3.delete(n);
2003
+ const r3 = new Request(i6, { headers: a3 });
2004
+ return await e5.call(t3, r3, s4);
2005
+ }
2006
+ return e5.apply(t3, i5);
2007
+ } catch (e6) {
2008
+ throw Se && console.log(`Retry without ${n} for ${o4} also failed:`, e6), e6;
2009
+ }
2010
+ })(e4, i4, o3, d3), S3 = true);
2011
+ const w2 = Date.now(), v2 = b3.status, k2 = b3.ok, x2 = k2 ? "" : `Request Error: ${b3.statusText}`;
2012
+ let I2 = null;
2013
+ try {
2014
+ I2 = {}, b3.headers.forEach((e5, t3) => {
2015
+ I2[t3] = e5;
2016
+ });
2017
+ } catch (e5) {
2018
+ Se && console.warn("[Sailfish] Failed to capture response headers:", e5), I2 = null;
2019
+ }
2020
+ const T2 = { type: 27, timestamp: w2, sessionId: c3, data: { request_id: u3, session_id: c3, timestamp_start: g2, timestamp_end: w2, response_code: v2, success: k2, error: x2, method: f2, url: d3, retry_without_trace_id: S3, request_headers: h2, request_body: m2, response_headers: I2, response_body: null }, ...p2 }, sendEventWithBody = (e5) => {
2021
+ T2.data.response_body = e5, y2 ? y2.text().then((e6) => {
2022
+ T2.data.request_body = e6, sendEvent(T2);
2023
+ }, () => {
2024
+ sendEvent(T2);
2025
+ }) : sendEvent(T2);
2026
+ }, E2 = 1024 * t2.captureResponseBodyMaxMb * 1024;
2027
+ if (0 === t2.captureResponseBodyMaxMb) sendEventWithBody(null);
2028
+ else if ((function shouldSkipBodyCapture(e5) {
2029
+ const t3 = e5.headers.get("content-type");
2030
+ if (!t3) return false;
2031
+ const n2 = t3.toLowerCase();
2032
+ return r2.some((e6) => n2.includes(e6));
2033
+ })(b3)) sendEventWithBody(null);
2034
+ else if ((function isStreamingResponse(e5) {
2035
+ const t3 = e5.headers.get("content-type");
2036
+ if (!t3) return false;
2037
+ const n2 = t3.toLowerCase();
2038
+ return a2.some((e6) => n2.includes(e6));
2039
+ })(b3)) if (t2.captureStreamingResponseBody) try {
2040
+ (async function readStreamPrefix(e5, t3, n2) {
2041
+ const i5 = e5.body;
2042
+ if (!i5) return null;
2043
+ const o4 = i5.getReader(), s4 = new TextDecoder(), a3 = [];
2044
+ let r3 = 0;
2045
+ const readWithLimit = async () => {
2046
+ try {
2047
+ for (; r3 < t3; ) {
2048
+ const { done: e6, value: t4 } = await o4.read();
2049
+ if (e6) break;
2050
+ r3 += t4.byteLength, a3.push(s4.decode(t4, { stream: true }));
2051
+ }
2052
+ return a3.push(s4.decode()), a3.join("");
2053
+ } catch {
2054
+ return a3.length > 0 ? a3.join("") : null;
2055
+ } finally {
2056
+ try {
2057
+ o4.cancel();
2058
+ } catch {
2059
+ }
2060
+ }
2061
+ };
2062
+ try {
2063
+ return await Promise.race([readWithLimit(), new Promise((e6) => setTimeout(() => {
2064
+ try {
2065
+ o4.cancel();
2066
+ } catch {
2067
+ }
2068
+ e6(a3.length > 0 ? a3.join("") : null);
2069
+ }, n2))]);
2070
+ } catch {
2071
+ try {
2072
+ o4.cancel();
2073
+ } catch {
2074
+ }
2075
+ return null;
2076
+ }
2077
+ })(b3.clone(), 1024 * t2.captureStreamPrefixKb, t2.captureStreamTimeoutMs).then((e5) => sendEventWithBody(e5), () => sendEventWithBody(null));
2078
+ } catch {
2079
+ sendEventWithBody(null);
2080
+ }
2081
+ else sendEventWithBody(null);
2082
+ else {
2083
+ const e5 = b3.headers.get("content-length"), t3 = e5 ? parseInt(e5, 10) : NaN;
2084
+ if (!isNaN(t3) && t3 > E2) sendEventWithBody(null);
2085
+ else try {
2086
+ b3.clone().text().then((e6) => {
2087
+ e6.length > E2 ? sendEventWithBody(null) : sendEventWithBody(e6);
2088
+ }, () => sendEventWithBody(null));
2089
+ } catch {
2090
+ sendEventWithBody(null);
2091
+ }
2092
+ }
2093
+ return b3;
2094
+ } catch (t3) {
2095
+ const n2 = Date.now(), s4 = false, a3 = ((_a = t3.response) == null ? void 0 : _a.status) || 500, r3 = t3.message || "Fetch request failed";
2096
+ if (t3 instanceof TypeError && ((_b = t3 == null ? void 0 : t3.message) == null ? void 0 : _b.toLowerCase().includes(Ie.toLowerCase()))) return e4.apply(i4, o3);
2097
+ let l4 = m2;
2098
+ if (y2) try {
2099
+ l4 = await y2.text();
2100
+ } catch {
2101
+ l4 = null;
2102
+ }
2103
+ throw sendEvent({ type: 27, timestamp: n2, sessionId: c3, data: { request_id: u3, session_id: c3, timestamp_start: g2, timestamp_end: n2, response_code: a3, success: s4, error: r3, method: f2, url: d3, request_headers: h2, request_body: l4, response_body: null }, ...p2 }), t3;
2104
+ }
2105
+ })(e3, i3, l2, d2, u2, o2, c2);
2106
+ } });
2107
+ }
2108
+ async function startRecording({ apiKey: e2, backendApi: t2 = "https://api-service.sailfishqa.com", domainsToPropagateHeaderTo: i2 = [], domainsToNotPropagateHeaderTo: o2 = [], serviceVersion: s2, serviceIdentifier: a2, gitSha: r2, serviceAdditionalMetadata: l2, enableIpTracking: c2, captureStreamingResponseBody: d2 = true, captureResponseBodyMaxMb: u2 = 10, captureStreamPrefixKb: p2 = 64, captureStreamTimeoutMs: f2 = 1e4, enableFiberTracking: g2 = false, deferRecording: h2, deferRecordingStart: y2, chunkSnapshot: b2, useWsWorker: S2 = true }) {
2109
+ var _a, _b;
2110
+ const w2 = h2 ?? y2 ?? true, v2 = getOrSetSessionId(), k2 = window.__sailfish_recorder || (window.__sailfish_recorder = {});
2111
+ if (k2.sessionId = v2, k2.apiKey = e2, k2.backendApi = t2, k2.serviceAdditionalMetadata = l2, k2.initialized && k2.sessionId === v2 && k2.ws && 1 === k2.ws.readyState) return void trackDomainChangesOnce();
2112
+ const x2 = { captureStreamingResponseBody: d2, captureResponseBodyMaxMb: u2, captureStreamPrefixKb: p2, captureStreamTimeoutMs: f2 };
2113
+ k2.xhrPatched || (!(function setupXMLHttpRequestInterceptor(e3 = [], t3 = { captureStreamingResponseBody: true, captureResponseBodyMaxMb: 10, captureStreamPrefixKb: 64, captureStreamTimeoutMs: 1e4 }) {
2114
+ const i3 = XMLHttpRequest.prototype.open, o3 = XMLHttpRequest.prototype.send, s3 = XMLHttpRequest.prototype.setRequestHeader, a3 = getOrSetSessionId(), r3 = createSkipHeadersPropagationChecker(e3);
2115
+ XMLHttpRequest.prototype.setRequestHeader = function(e4, t4) {
2116
+ return this._capturedRequestHeaders || (this._capturedRequestHeaders = {}), this._capturedRequestHeaders[e4] = t4, s3.call(this, e4, t4);
2117
+ }, XMLHttpRequest.prototype.open = function(e4, t4, ...n2) {
2118
+ return this._requestUrl = "string" == typeof t4 && t4.length > 0 ? t4 : null, this._requestMethod = e4, this._capturedRequestHeaders = {}, i3.apply(this, [e4, t4, ...n2]);
2119
+ }, XMLHttpRequest.prototype.send = function(...e4) {
2120
+ const i4 = this._requestUrl;
2121
+ if (!i4) return o3.apply(this, e4);
2122
+ if (r3(i4)) return o3.apply(this, e4);
2123
+ const s4 = sessionStorage.getItem("pageVisitUUID"), l3 = uuidv4(), c3 = `${a3}/${s4}/${l3}`;
2124
+ try {
2125
+ this.setRequestHeader(n, c3);
2126
+ } catch (e5) {
2127
+ console.warn(`Could not set X-Sf3-Rid for ${i4}`, e5);
2128
+ }
2129
+ const d3 = getFuncSpanHeader();
2130
+ if (d3) try {
2131
+ this.setRequestHeader(d3.name, d3.value), Se && console.log("[Sailfish] Added funcspan header to XMLHttpRequest:", { url: i4, header: d3.name });
2132
+ } catch (e5) {
2133
+ Se && console.warn(`[Sailfish] Could not set funcspan header for ${i4}`, e5);
2134
+ }
2135
+ const u3 = Date.now();
2136
+ let p3 = false;
2137
+ const f3 = e4[0], g3 = { ...this._capturedRequestHeaders };
2138
+ maskAuthorizationHeader(g3);
2139
+ const emitFinished = (e5, t4, n2, o4, s5) => {
2140
+ if (p3) return;
2141
+ p3 = true;
2142
+ const r4 = Date.now();
2143
+ sendEvent({ type: 27, timestamp: r4, sessionId: a3, data: { request_id: l3, session_id: a3, timestamp_start: u3, timestamp_end: r4, response_code: t4, success: e5, error: n2, method: this._requestMethod, url: i4, request_headers: g3, request_body: f3, response_headers: s5, response_body: o4 }, ...getUrlAndStoredUuids() });
2144
+ };
2145
+ return this.addEventListener("load", () => {
2146
+ const e5 = this.status || 0;
2147
+ let n2, i5 = null;
2148
+ const o4 = 1024 * t3.captureResponseBodyMaxMb * 1024;
2149
+ try {
2150
+ if (0 === t3.captureResponseBodyMaxMb) n2 = null;
2151
+ else {
2152
+ const e6 = this.responseText || this.response;
2153
+ n2 = "string" == typeof e6 && e6.length > o4 ? null : e6;
2154
+ }
2155
+ } catch (e6) {
2156
+ n2 = null;
2157
+ }
2158
+ try {
2159
+ i5 = {};
2160
+ const e6 = this.getAllResponseHeaders();
2161
+ e6 && e6.split("\r\n").forEach((e7) => {
2162
+ const t4 = e7.split(": ");
2163
+ 2 === t4.length && (i5[t4[0]] = t4[1]);
2164
+ });
2165
+ } catch (e6) {
2166
+ Se && console.warn("[Sailfish] Failed to capture XHR response headers:", e6), i5 = null;
2167
+ }
2168
+ if (e5 >= 200 && e5 < 300) emitFinished(true, e5, "", n2, i5);
2169
+ else {
2170
+ const t4 = this.statusText || `HTTP ${e5}`;
2171
+ emitFinished(false, e5, t4, n2, i5);
2172
+ }
2173
+ }, { once: true }), this.addEventListener("error", () => {
2174
+ const e5 = this.status || 0, t4 = 0 === e5 ? "Network or CORS failure" : this.statusText || `Error ${e5}`;
2175
+ emitFinished(false, e5, t4);
2176
+ }, { once: true }), o3.apply(this, e4);
2177
+ };
2178
+ })(o2, x2), k2.xhrPatched = true), await yieldToMain(), k2.fetchPatched || (setupFetchInterceptor(o2, x2), k2.fetchPatched = true), await yieldToMain(), k2.domEventsInit || (initializeDomContentEvents(v2), k2.domEventsInit = true), await yieldToMain(), k2.consoleInit || (initializeConsolePlugin($e, v2), k2.consoleInit = true), await yieldToMain(), k2.errorInit || (!(function initializeErrorInterceptor() {
2179
+ window.addEventListener("error", (e3) => {
2180
+ captureError(e3.error || e3.message);
2181
+ }), window.addEventListener("unhandledrejection", (e3) => {
2182
+ captureError(e3.reason, true);
2183
+ });
2184
+ })(), k2.errorInit = true), await yieldToMain(), _ensureModuleSideEffects(), (function storeCredentialsAndConnection({ apiKey: e3, backendApi: t3 }) {
2185
+ m && (sessionStorage.setItem("sailfishApiKey", e3), sessionStorage.setItem("sailfishBackendApi", t3));
2186
+ })({ apiKey: e2, backendApi: t2 }), !isFunctionSpanTrackingEnabled() || k2.ws && 1 === k2.ws.readyState || fetchFunctionSpanTrackingEnabled(e2, t2).then((e3) => {
2187
+ var _a2;
2188
+ ((_a2 = e3.data) == null ? void 0 : _a2.isFunctionSpanTrackingEnabledFromApiKey) ?? false ? Se && console.log("[Sailfish] Function span tracking state validated with backend: ACTIVE") : (clearStaleFuncSpanState(), Se && console.log("[Sailfish] Cleared stale function span tracking state - backend validation shows tracking is not active"));
2189
+ }).catch((e3) => {
2190
+ Se && console.warn("[Sailfish] Failed to validate function span tracking status with backend:", e3);
2191
+ }), k2.sentDoNotPropagateOnce || (sendDomainsToNotPropagateHeaderTo(e2, [...o2, ...ke], t2).catch((e3) => console.error("Failed to send domains to not propagate header to:", e3)), k2.sentDoNotPropagateOnce = true), (async function gatherAndCacheDeviceInfo() {
2192
+ sendMessage({ type: "deviceInfo", data: { deviceInfo: { language: navigator.language, userAgent: navigator.userAgent } } });
2193
+ })(), c2 && fetchAndSendIp(v2);
2194
+ try {
2195
+ const n2 = r2 ?? (function readGitSha() {
2196
+ var _a2;
2197
+ try {
2198
+ const e3 = globalThis;
2199
+ if ("string" == typeof e3.__GIT_SHA__ && e3.__GIT_SHA__) return e3.__GIT_SHA__;
2200
+ } catch {
2201
+ }
2202
+ try {
2203
+ const e3 = "undefined" != typeof process ? process : void 0;
2204
+ if ((_a2 = e3 == null ? void 0 : e3.env) == null ? void 0 : _a2.GIT_SHA) return String(e3.env.GIT_SHA);
2205
+ } catch {
2206
+ }
2207
+ try {
2208
+ const e3 = globalThis.__GIT_SHA_DEFINE__;
2209
+ if ("string" == typeof e3 && e3) return e3;
2210
+ } catch {
2211
+ }
2212
+ })(), i3 = a2 ?? "", o3 = s2 ?? "", c3 = "JS/TS", d3 = (function getMapUuidFromWindow() {
2213
+ try {
2214
+ const e3 = window;
2215
+ if (e3 && "string" == typeof e3.sfMapUuid && e3.sfMapUuid) return e3.sfMapUuid;
2216
+ } catch {
2217
+ }
2218
+ })(), u3 = withAppUrlMetadata(l2);
2219
+ await yieldToMain();
2220
+ const [p3, f3] = await Promise.all([fetchCaptureSettings(e2, t2), startRecordingSession(e2, v2, t2, i3, o3, d3, n2, c3, u3)]), m2 = { ...Ce, ...(_a = p3.data) == null ? void 0 : _a.captureSettingsFromApiKey, enableFiberTracking: g2 };
2221
+ if (k2.ws && 1 === k2.ws.readyState) return;
2222
+ if ((_b = f3.data) == null ? void 0 : _b.startRecordingSession) {
2223
+ const n3 = (l2 == null ? void 0 : l2.env) || (l2 == null ? void 0 : l2.environment);
2224
+ await yieldToMain();
2225
+ const i4 = await initializeRecording(m2, t2, e2, v2, n3, w2, S2, b2 ?? false);
2226
+ k2.ws = i4, k2.initialized = true, trackDomainChangesOnce(), k2.sentMapUuidOnce || (!(function sendMapUuidIfAvailable(e3 = "", t3 = "") {
2227
+ window.sfMapUuid && sendMessage({ type: "mapUuid", data: { mapUuid: window.sfMapUuid, serviceIdentifier: e3, serviceVersion: t3 } });
2228
+ })(a2, s2), k2.sentMapUuidOnce = true);
2229
+ } else console.error("Failed to start recording session:", f3.errors || f3);
2230
+ } catch (e3) {
2231
+ console.error("Error starting recording:", e3);
2232
+ }
2233
+ }
2234
+ exports.DEFAULT_CAPTURE_SETTINGS = Ce, exports.DEFAULT_CONSOLE_RECORDING_SETTINGS = $e, exports.STORAGE_VERSION = 1, exports.addOrUpdateMetadata = function addOrUpdateMetadata(e2) {
2235
+ const t2 = { type: "addOrUpdateMetadata", metadata: e2 };
2236
+ z && JSON.stringify(z) === JSON.stringify(e2) || (z = e2, sendMessage(t2));
2237
+ }, exports.buildBatches = buildBatches, exports.clearStaleFuncSpanState = clearStaleFuncSpanState, exports.createTriageAndIssueFromRecorder = createTriageAndIssueFromRecorder, exports.createTriageFromRecorder = createTriageFromRecorder, exports.disableFunctionSpanTracking = disableFunctionSpanTracking, exports.enableFunctionSpanTracking = enableFunctionSpanTracking, exports.ensureHrefCache = ensureHrefCache, exports.eventSize = eventSize, exports.fetchAndSendIp = fetchAndSendIp, exports.fetchCaptureSettings = fetchCaptureSettings, exports.fetchEngineeringTicketPlatformIntegrations = fetchEngineeringTicketPlatformIntegrations, exports.fetchFunctionSpanTrackingEnabled = fetchFunctionSpanTrackingEnabled, exports.flushBufferedEvents = flushBufferedEvents, exports.getCachedHref = getCachedHref, exports.getCachedHrefNoQuery = getCachedHrefNoQuery, exports.getFuncSpanHeader = getFuncSpanHeader, exports.getOrSetSessionId = getOrSetSessionId, exports.getUrlAndStoredUuids = getUrlAndStoredUuids, exports.identify = function identify(e2, t2 = {}, n2 = false) {
2238
+ const i2 = { type: "identify", userId: e2, traits: t2 };
2239
+ O && O.userId === e2 && JSON.stringify(O.traits) === JSON.stringify(t2) || (O = { userId: e2, traits: t2, overwrite: n2 }, sendMessage(i2));
2240
+ }, exports.initRecorder = async (e2) => {
2241
+ if ("undefined" == typeof window) return;
2242
+ const t2 = window.__sailfish_recorder || (window.__sailfish_recorder = {}), n2 = getOrSetSessionId();
2243
+ return clearPageVisitDataFromSessionStorage(), t2.initialized && t2.sessionId === n2 && t2.ws && 1 === t2.ws.readyState ? void 0 : (t2.initPromise || (t2.initPromise = (async () => {
2244
+ if (t2.hasLoggedInitOnce || (console.log("Initializing Sailfish Recorder (first run) …"), t2.hasLoggedInitOnce = true), await startRecording(e2), !t2.issueReportingInit) {
2245
+ const n3 = e2.backendApi ?? "https://api-service.sailfishqa.com", [{ setupIssueReporting: i2 }, { fetchIntegrationData: o2, getIntegrationData: s2 }] = await Promise.all([Promise.resolve().then(() => be), Promise.resolve().then(() => re)]);
2246
+ let a2 = null;
2247
+ try {
2248
+ await o2(e2.apiKey, n3), a2 = s2();
2249
+ } catch (e3) {
2250
+ console.warn("[Sailfish] Failed to fetch integration data for issue reporting:", e3);
2251
+ }
2252
+ i2({ apiKey: e2.apiKey, backendApi: n3, getSessionId: () => getOrSetSessionId(), shortcuts: e2.reportIssueShortcuts, customBaseUrl: e2.customBaseUrl, integrationData: a2 }), t2.issueReportingInit = true;
2253
+ }
2254
+ })().finally(() => {
2255
+ delete t2.initPromise;
2256
+ })), t2.initPromise);
2257
+ }, exports.initializeConsolePlugin = initializeConsolePlugin, exports.initializeDomContentEvents = initializeDomContentEvents, exports.initializeFunctionSpanTrackingFromApi = initializeFunctionSpanTrackingFromApi, exports.initializeRecording = initializeRecording, exports.initializeWebSocket = initializeWebSocket, exports.invalidateUrlCache = invalidateUrlCache, exports.isFunctionSpanTrackingEnabled = isFunctionSpanTrackingEnabled, exports.matchUrlWithWildcard = matchUrlWithWildcard, exports.openReportIssueModal = openReportIssueModal, exports.restoreFuncSpanState = restoreFuncSpanState, exports.sendDomainsToNotPropagateHeaderTo = sendDomainsToNotPropagateHeaderTo, exports.sendEvent = sendEvent, exports.sendGraphQLRequest = sendGraphQLRequest, exports.sendMessage = sendMessage, exports.startRecording = startRecording, exports.startRecordingSession = startRecordingSession, exports.trackingEvent = function trackingEvent(e2) {
2258
+ sendMessage({ type: "trackingEvent", trackingData: e2, timestamp: exports.nowTimestamp() });
2259
+ }, exports.withAppUrlMetadata = withAppUrlMetadata, exports.yieldToMain = yieldToMain;