@firstlook-uat/sdk 0.4.2 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,39 +1,39 @@
1
- const I = [
1
+ const A = [
2
2
  'input[type="password"]',
3
3
  "[data-sensitive]",
4
4
  "[data-mask]",
5
5
  ".uat-mask"
6
6
  ];
7
- function M(a) {
8
- var t, e, s, i, n, o, l, c, h, d;
9
- if (!a.endpoint)
7
+ function R(c) {
8
+ var e, t, s, i, n, o, l, a, h, d;
9
+ if (!c.endpoint)
10
10
  throw new Error("[FirstLook] 'endpoint' is required. Set your Supabase ingest-session URL.");
11
11
  return {
12
- projectId: a.projectId,
13
- apiKey: a.apiKey,
14
- userId: a.userId,
15
- role: a.role,
16
- context: a.context ?? {},
17
- endpoint: a.endpoint,
12
+ projectId: c.projectId,
13
+ apiKey: c.apiKey,
14
+ userId: c.userId,
15
+ role: c.role,
16
+ context: c.context ?? {},
17
+ endpoint: c.endpoint,
18
18
  triggers: {
19
- tapCount: ((t = a.triggers) == null ? void 0 : t.tapCount) ?? 5,
20
- deepLink: ((e = a.triggers) == null ? void 0 : e.deepLink) ?? !0,
21
- keyboard: ((s = a.triggers) == null ? void 0 : s.keyboard) ?? !0,
22
- customCheck: (i = a.triggers) == null ? void 0 : i.customCheck
19
+ tapCount: ((e = c.triggers) == null ? void 0 : e.tapCount) ?? 5,
20
+ deepLink: ((t = c.triggers) == null ? void 0 : t.deepLink) ?? !0,
21
+ keyboard: ((s = c.triggers) == null ? void 0 : s.keyboard) ?? !0,
22
+ customCheck: (i = c.triggers) == null ? void 0 : i.customCheck
23
23
  },
24
24
  security: {
25
- watermark: ((n = a.security) == null ? void 0 : n.watermark) ?? !0,
26
- maskSelectors: ((o = a.security) == null ? void 0 : o.maskSelectors) ?? I
25
+ watermark: ((n = c.security) == null ? void 0 : n.watermark) ?? !0,
26
+ maskSelectors: ((o = c.security) == null ? void 0 : o.maskSelectors) ?? A
27
27
  },
28
28
  recording: {
29
- domSnapshot: ((l = a.recording) == null ? void 0 : l.domSnapshot) ?? !0,
30
- voice: ((c = a.recording) == null ? void 0 : c.voice) ?? !0,
31
- maxDuration: ((h = a.recording) == null ? void 0 : h.maxDuration) ?? 600,
32
- snapshotInterval: ((d = a.recording) == null ? void 0 : d.snapshotInterval) ?? 1e3
29
+ domSnapshot: ((l = c.recording) == null ? void 0 : l.domSnapshot) ?? !0,
30
+ voice: ((a = c.recording) == null ? void 0 : a.voice) ?? !0,
31
+ maxDuration: ((h = c.recording) == null ? void 0 : h.maxDuration) ?? 600,
32
+ snapshotInterval: ((d = c.recording) == null ? void 0 : d.snapshotInterval) ?? 1e3
33
33
  }
34
34
  };
35
35
  }
36
- function y() {
36
+ function q() {
37
37
  return {
38
38
  userAgent: navigator.userAgent,
39
39
  platform: navigator.platform,
@@ -44,28 +44,28 @@ function y() {
44
44
  touchSupport: "ontouchstart" in window || navigator.maxTouchPoints > 0
45
45
  };
46
46
  }
47
- class E {
47
+ class L {
48
48
  constructor() {
49
49
  this.listeners = /* @__PURE__ */ new Map();
50
50
  }
51
- on(t, e) {
52
- return this.listeners.has(t) || this.listeners.set(t, /* @__PURE__ */ new Set()), this.listeners.get(t).add(e), () => this.off(t, e);
51
+ on(e, t) {
52
+ return this.listeners.has(e) || this.listeners.set(e, /* @__PURE__ */ new Set()), this.listeners.get(e).add(t), () => this.off(e, t);
53
53
  }
54
- off(t, e) {
54
+ off(e, t) {
55
55
  var s;
56
- (s = this.listeners.get(t)) == null || s.delete(e);
56
+ (s = this.listeners.get(e)) == null || s.delete(t);
57
57
  }
58
- emit(t) {
59
- var e, s;
60
- (e = this.listeners.get(t.type)) == null || e.forEach((i) => {
58
+ emit(e) {
59
+ var t, s;
60
+ (t = this.listeners.get(e.type)) == null || t.forEach((i) => {
61
61
  try {
62
- i(t);
62
+ i(e);
63
63
  } catch (n) {
64
64
  console.error("[FirstLook] Event listener error:", n);
65
65
  }
66
66
  }), (s = this.listeners.get("*")) == null || s.forEach((i) => {
67
67
  try {
68
- i(t);
68
+ i(e);
69
69
  } catch (n) {
70
70
  console.error("[FirstLook] Event listener error:", n);
71
71
  }
@@ -75,15 +75,15 @@ class E {
75
75
  this.listeners.clear();
76
76
  }
77
77
  }
78
- class R {
79
- constructor(t) {
80
- this.events = t, this.quests = [], this.results = [], this.currentIndex = -1, this.sessionStartTime = 0, this.blocked = !1, this.pendingFeedbacks = [];
78
+ class E {
79
+ constructor(e) {
80
+ this.events = e, this.quests = [], this.results = [], this.currentIndex = -1, this.sessionStartTime = 0, this.blocked = !1, this.pendingFeedbacks = [];
81
81
  }
82
- loadQuests(t) {
83
- this.quests = [...t].sort((e, s) => e.order - s.order), this.results = [], this.currentIndex = -1, this.blocked = !1;
82
+ loadQuests(e) {
83
+ this.quests = [...e].sort((t, s) => t.order - s.order), this.results = [], this.currentIndex = -1, this.blocked = !1;
84
84
  }
85
- startSession(t) {
86
- this.sessionStartTime = t, this.advance();
85
+ startSession(e) {
86
+ this.sessionStartTime = e, this.advance();
87
87
  }
88
88
  getCurrentQuest() {
89
89
  return this.blocked || this.currentIndex < 0 || this.currentIndex >= this.quests.length ? null : this.quests[this.currentIndex];
@@ -91,20 +91,20 @@ class R {
91
91
  getStatus() {
92
92
  return {
93
93
  total: this.quests.length,
94
- completed: this.results.filter((t) => t.status === "COMPLETED").length,
95
- failed: this.results.filter((t) => t.status === "FAILED").length,
94
+ completed: this.results.filter((e) => e.status === "COMPLETED").length,
95
+ failed: this.results.filter((e) => e.status === "FAILED").length,
96
96
  current: this.currentIndex,
97
97
  isBlocked: this.blocked,
98
98
  isFinished: this.currentIndex >= this.quests.length
99
99
  };
100
100
  }
101
101
  getQuestStatuses() {
102
- return this.quests.map((t, e) => {
103
- const s = this.results.find((i) => i.questId === t.id);
104
- return s ? s.status : e === this.currentIndex && !this.blocked ? "ACTIVE" : this.blocked && e >= this.currentIndex ? "BLOCKED" : "PENDING";
102
+ return this.quests.map((e, t) => {
103
+ const s = this.results.find((i) => i.questId === e.id);
104
+ return s ? s.status : t === this.currentIndex && !this.blocked ? "ACTIVE" : this.blocked && t >= this.currentIndex ? "BLOCKED" : "PENDING";
105
105
  });
106
106
  }
107
- completeCurrentQuest(t, e) {
107
+ completeCurrentQuest(e, t) {
108
108
  const s = this.getCurrentQuest();
109
109
  if (!s) return null;
110
110
  const i = {
@@ -112,16 +112,16 @@ class R {
112
112
  status: "COMPLETED",
113
113
  timestamp: Date.now(),
114
114
  relativeTime: Date.now() - this.sessionStartTime,
115
- voiceMemoBlob: e == null ? void 0 : e.voiceMemo,
116
- logs: t,
117
- comment: e == null ? void 0 : e.comment,
118
- concern: (e == null ? void 0 : e.concern) ?? !1,
115
+ voiceMemoBlob: t == null ? void 0 : t.voiceMemo,
116
+ logs: e,
117
+ comment: t == null ? void 0 : t.comment,
118
+ concern: (t == null ? void 0 : t.concern) ?? !1,
119
119
  feedbacks: this.drainFeedbacks(),
120
- checklist: e == null ? void 0 : e.checklist
120
+ checklist: t == null ? void 0 : t.checklist
121
121
  };
122
122
  return this.results.push(i), this.events.emit({ type: "quest:completed", questId: s.id }), this.advance(), i;
123
123
  }
124
- failCurrentQuest(t, e, s, i) {
124
+ failCurrentQuest(e, t, s, i) {
125
125
  const n = this.getCurrentQuest();
126
126
  if (!n) return null;
127
127
  const o = {
@@ -130,113 +130,113 @@ class R {
130
130
  timestamp: Date.now(),
131
131
  relativeTime: Date.now() - this.sessionStartTime,
132
132
  voiceMemoBlob: s,
133
- logs: t,
134
- comment: e,
133
+ logs: e,
134
+ comment: t,
135
135
  concern: !1,
136
136
  feedbacks: this.drainFeedbacks(),
137
137
  checklist: i
138
138
  };
139
139
  return this.results.push(o), this.events.emit({ type: "quest:failed", questId: n.id }), n.blocking ? (this.blocked = !0, this.events.emit({ type: "quest:blocked", questId: n.id })) : this.advance(), o;
140
140
  }
141
- addFeedback(t) {
142
- this.pendingFeedbacks.push(t);
141
+ addFeedback(e) {
142
+ this.pendingFeedbacks.push(e);
143
143
  }
144
144
  getResults() {
145
145
  return [...this.results];
146
146
  }
147
147
  drainFeedbacks() {
148
- const t = this.pendingFeedbacks;
149
- return this.pendingFeedbacks = [], t;
148
+ const e = this.pendingFeedbacks;
149
+ return this.pendingFeedbacks = [], e;
150
150
  }
151
151
  advance() {
152
152
  this.currentIndex++, this.currentIndex < this.quests.length && this.events.emit({ type: "quest:started", questId: this.quests[this.currentIndex].id });
153
153
  }
154
154
  }
155
- function r(a, t, e) {
156
- const s = document.createElement(a);
157
- if (t)
158
- for (const [i, n] of Object.entries(t))
159
- i === "className" ? s.className = n : s.setAttribute(i, n);
155
+ function r(c, e, t) {
156
+ const s = document.createElement(c);
160
157
  if (e)
161
- for (const i of e)
158
+ for (const [i, n] of Object.entries(e))
159
+ i === "className" ? s.className = n : s.setAttribute(i, n);
160
+ if (t)
161
+ for (const i of t)
162
162
  typeof i == "string" ? s.appendChild(document.createTextNode(i)) : s.appendChild(i);
163
163
  return s;
164
164
  }
165
- function L() {
165
+ function D() {
166
166
  return `fl_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
167
167
  }
168
- function A(a) {
169
- const t = Math.floor(a / 60), e = a % 60;
170
- return `${t.toString().padStart(2, "0")}:${e.toString().padStart(2, "0")}`;
168
+ function N(c) {
169
+ const e = Math.floor(c / 60), t = c % 60;
170
+ return `${e.toString().padStart(2, "0")}:${t.toString().padStart(2, "0")}`;
171
171
  }
172
- function D(a) {
173
- const t = a.split(`
174
- `), e = [], s = [];
172
+ function F(c) {
173
+ const e = c.split(`
174
+ `), t = [], s = [];
175
175
  let i = !1;
176
- for (const n of t) {
176
+ for (const n of e) {
177
177
  const o = n.trim(), l = o.match(/^(?:(\d+)[\.\)]\s+|[-*]\s+)(.+)$/);
178
178
  l ? (i = !0, s.push({
179
179
  index: s.length,
180
180
  text: l[2],
181
181
  checked: !1
182
- })) : !i && o && e.push(o);
182
+ })) : !i && o && t.push(o);
183
183
  }
184
184
  return {
185
- preamble: e.join(`
185
+ preamble: t.join(`
186
186
  `),
187
187
  items: s
188
188
  };
189
189
  }
190
- class N {
191
- constructor(t, e) {
192
- this.shadowRoot = t, this.callbacks = e, this.minimized = !1, this.timerInterval = null, this.startTime = 0, this.checklist = [], this.root = document.createElement("div"), this.root.className = "fl-quest-overlay", this.root.style.pointerEvents = "auto";
190
+ class P {
191
+ constructor(e, t) {
192
+ this.shadowRoot = e, this.callbacks = t, this.minimized = !1, this.timerInterval = null, this.startTime = 0, this.checklist = [], this.root = document.createElement("div"), this.root.className = "fl-quest-overlay", this.root.style.pointerEvents = "auto";
193
193
  for (const s of ["click", "mousedown", "mouseup", "pointerdown", "pointerup", "touchstart", "touchend"])
194
194
  this.root.addEventListener(s, (i) => i.stopPropagation());
195
195
  this.shadowRoot.appendChild(this.root);
196
196
  }
197
- renderQuest(t, e, s) {
197
+ renderQuest(e, t, s) {
198
198
  this.minimized = !1, this.root.className = "fl-quest-overlay", this.root.innerHTML = "";
199
- const i = e.indexOf("ACTIVE"), n = r("div", { className: "fl-quest-header" }, [
199
+ const i = t.indexOf("ACTIVE"), n = r("div", { className: "fl-quest-header" }, [
200
200
  r("div", { className: "fl-quest-header-left" }, [
201
- r("span", { className: "fl-quest-badge" }, [`Q${i + 1}/${e.length}`]),
202
- r("span", { className: "fl-quest-title" }, [t.title])
201
+ r("span", { className: "fl-quest-badge" }, [`Q${i + 1}/${t.length}`]),
202
+ r("span", { className: "fl-quest-title" }, [e.title])
203
203
  ]),
204
204
  this.createMinimizeBtn()
205
205
  ]);
206
206
  this.root.appendChild(n);
207
207
  const o = r("div", { className: "fl-quest-content" }), l = r("div", { className: "fl-quest-progress" });
208
- for (const f of e) {
208
+ for (const f of t) {
209
209
  const p = f === "COMPLETED" ? "fl-completed" : f === "FAILED" ? "fl-failed" : f === "ACTIVE" ? "fl-active" : "";
210
210
  l.appendChild(r("div", { className: `fl-quest-progress-dot ${p}` }));
211
211
  }
212
- const c = D(t.description);
213
- this.checklist = c.items;
212
+ const a = F(e.description);
213
+ this.checklist = a.items;
214
214
  const h = r("div", { className: "fl-quest-body" });
215
- if (h.appendChild(l), c.items.length > 0) {
215
+ if (h.appendChild(l), a.items.length > 0) {
216
216
  const f = r("div", { className: "fl-checklist-counter" }), p = () => {
217
217
  const b = this.checklist.filter((k) => k.checked).length;
218
218
  f.textContent = `✓ ${b}/${this.checklist.length} 確認済み`;
219
219
  };
220
- p(), h.appendChild(f), c.preamble && h.appendChild(r("p", { className: "fl-quest-description" }, [c.preamble]));
220
+ p(), h.appendChild(f), a.preamble && h.appendChild(r("p", { className: "fl-quest-description" }, [a.preamble]));
221
221
  const g = r("ul", { className: "fl-checklist" });
222
222
  for (const b of this.checklist) {
223
223
  const k = r("li", { className: "fl-checklist-item" }), v = document.createElement("input");
224
224
  v.type = "checkbox", v.className = "fl-checklist-checkbox", v.checked = b.checked;
225
- const T = r("span", { className: "fl-checklist-text" }, [b.text]);
225
+ const I = r("span", { className: "fl-checklist-text" }, [b.text]);
226
226
  v.onchange = () => {
227
227
  b.checked = v.checked, k.classList.toggle("fl-checked", b.checked), p();
228
- }, k.onclick = (q) => {
229
- q.target !== v && (v.checked = !v.checked, b.checked = v.checked, k.classList.toggle("fl-checked", b.checked), p());
230
- }, k.appendChild(v), k.appendChild(T), g.appendChild(k);
228
+ }, k.onclick = (M) => {
229
+ M.target !== v && (v.checked = !v.checked, b.checked = v.checked, k.classList.toggle("fl-checked", b.checked), p());
230
+ }, k.appendChild(v), k.appendChild(I), g.appendChild(k);
231
231
  }
232
232
  h.appendChild(g);
233
233
  } else
234
- h.appendChild(r("p", { className: "fl-quest-description" }, [t.description]));
234
+ h.appendChild(r("p", { className: "fl-quest-description" }, [e.description]));
235
235
  h.appendChild(r("div", { className: "fl-quest-memo-row" }, [
236
- this.createButton("fl-btn fl-btn-memo", "📝 メモを残す", () => this.renderFeedbackModal(t.title))
236
+ this.createButton("fl-btn fl-btn-memo", "📝 メモを残す", () => this.renderFeedbackModal(e.title))
237
237
  ])), h.appendChild(r("div", { className: "fl-quest-actions" }, [
238
- this.createButton("fl-btn fl-btn-ok", "✓ OK", () => this.renderFeedbackModal(t.title, "ok")),
239
- this.createButton("fl-btn fl-btn-concern", "⚠ 気になる", () => this.renderFeedbackModal(t.title, "concern")),
238
+ this.createButton("fl-btn fl-btn-ok", "✓ OK", () => this.renderFeedbackModal(e.title, "ok")),
239
+ this.createButton("fl-btn fl-btn-concern", "⚠ 気になる", () => this.renderFeedbackModal(e.title, "concern")),
240
240
  this.createButton("fl-btn fl-btn-ng", "✗ NG", this.callbacks.onNg)
241
241
  ])), o.appendChild(h), s && o.appendChild(
242
242
  r("div", { className: "fl-voice-indicator" }, [
@@ -256,7 +256,7 @@ class N {
256
256
  this.minimized && (this.minimized = !1, this.root.className = "fl-quest-overlay", this.root.innerHTML = "", this.root.appendChild(n), this.root.appendChild(o), this.startTimer(m));
257
257
  };
258
258
  }
259
- renderFeedbackModal(t, e = "memo") {
259
+ renderFeedbackModal(e, t = "memo") {
260
260
  const s = r("div", { className: "fl-feedback-modal" }), i = {
261
261
  ng: "fl-quest-header fl-quest-header-ng",
262
262
  ok: "fl-quest-header fl-quest-header-ok",
@@ -272,31 +272,31 @@ class N {
272
272
  ok: "fl-quest-badge fl-badge-ok",
273
273
  concern: "fl-quest-badge fl-badge-concern",
274
274
  memo: "fl-quest-badge"
275
- }, l = r("div", { className: i[e] }, [
275
+ }, l = r("div", { className: i[t] }, [
276
276
  r("div", { className: "fl-quest-header-left" }, [
277
- r("span", { className: o[e] }, [n[e]]),
278
- r("span", { className: "fl-quest-title" }, [t])
277
+ r("span", { className: o[t] }, [n[t]]),
278
+ r("span", { className: "fl-quest-title" }, [e])
279
279
  ])
280
280
  ]);
281
281
  s.appendChild(l);
282
- const c = r("div", { className: "fl-quest-content" }), h = {
282
+ const a = r("div", { className: "fl-quest-content" }), h = {
283
283
  ng: "何がうまくいかなかったか教えてください...",
284
284
  ok: "コメント(任意)",
285
285
  concern: "気になった点を教えてください...",
286
286
  memo: "気づいたことをメモ...📝"
287
287
  }, d = document.createElement("textarea");
288
- d.className = "fl-feedback-textarea fl-feedback-textarea-modal", d.placeholder = h[e], d.rows = 3, c.appendChild(d);
289
- const m = "送信", f = e === "ok" ? "スキップ" : "キャンセル", p = r("div", { className: "fl-quest-actions fl-feedback-modal-actions" }, [
288
+ d.className = "fl-feedback-textarea fl-feedback-textarea-modal", d.placeholder = h[t], d.rows = 3, a.appendChild(d);
289
+ const m = "送信", f = t === "ok" ? "スキップ" : "キャンセル", p = r("div", { className: "fl-quest-actions fl-feedback-modal-actions" }, [
290
290
  this.createButton("fl-btn fl-btn-skip", f, () => {
291
- e === "ng" ? this.callbacks.onNgWithFeedback("") : e === "ok" ? this.callbacks.onOkWithFeedback("") : e === "concern" && this.callbacks.onConcern(""), s.remove();
291
+ t === "ng" ? this.callbacks.onNgWithFeedback("") : t === "ok" ? this.callbacks.onOkWithFeedback("") : t === "concern" && this.callbacks.onConcern(""), s.remove();
292
292
  }),
293
293
  this.createButton("fl-btn fl-btn-finish", m, () => {
294
294
  const g = d.value.trim();
295
- if (e === "ng")
295
+ if (t === "ng")
296
296
  this.callbacks.onNgWithFeedback(g);
297
- else if (e === "ok")
297
+ else if (t === "ok")
298
298
  this.callbacks.onOkWithFeedback(g);
299
- else if (e === "concern")
299
+ else if (t === "concern")
300
300
  this.callbacks.onConcern(g);
301
301
  else {
302
302
  if (!g) {
@@ -308,37 +308,37 @@ class N {
308
308
  s.remove();
309
309
  })
310
310
  ]);
311
- c.appendChild(p), s.appendChild(c), this.root.appendChild(s), d.focus();
311
+ a.appendChild(p), s.appendChild(a), this.root.appendChild(s), d.focus();
312
312
  }
313
- renderSummary(t, e, s) {
313
+ renderSummary(e, t, s) {
314
314
  this.stopTimer(), this.root.className = "fl-quest-overlay", this.root.innerHTML = "";
315
315
  const i = r("div", { className: "fl-summary" }, [
316
- r("div", { className: "fl-summary-icon" }, [t === s ? "🎉" : "📋"]),
316
+ r("div", { className: "fl-summary-icon" }, [e === s ? "🎉" : "📋"]),
317
317
  r("div", { className: "fl-summary-title" }, [
318
- t === s ? "All Quests Complete!" : "Session Complete"
318
+ e === s ? "All Quests Complete!" : "Session Complete"
319
319
  ]),
320
320
  r("div", { className: "fl-summary-subtitle" }, [
321
- `${t + e} of ${s} quests attempted`
321
+ `${e + t} of ${s} quests attempted`
322
322
  ]),
323
323
  r("div", { className: "fl-summary-stats" }, [
324
- this.createStat(t.toString(), "Passed", "fl-ok"),
325
- this.createStat(e.toString(), "Failed", "fl-ng")
324
+ this.createStat(e.toString(), "Passed", "fl-ok"),
325
+ this.createStat(t.toString(), "Failed", "fl-ng")
326
326
  ]),
327
327
  this.createButton("fl-btn fl-btn-finish", "Finish & Upload", this.callbacks.onFinish)
328
328
  ]);
329
329
  this.root.appendChild(i);
330
330
  }
331
- renderBlocked(t) {
331
+ renderBlocked(e) {
332
332
  this.stopTimer(), this.root.className = "fl-quest-overlay", this.root.innerHTML = "";
333
- const e = r("div", { className: "fl-summary" }, [
333
+ const t = r("div", { className: "fl-summary" }, [
334
334
  r("div", { className: "fl-summary-icon" }, ["🛑"]),
335
335
  r("div", { className: "fl-summary-title" }, ["Blocked"]),
336
336
  r("div", { className: "fl-summary-subtitle" }, [
337
- `Quest "${t}" is blocking. Session halted.`
337
+ `Quest "${e}" is blocking. Session halted.`
338
338
  ]),
339
339
  this.createButton("fl-btn fl-btn-finish", "Finish & Upload", this.callbacks.onFinish)
340
340
  ]);
341
- this.root.appendChild(e);
341
+ this.root.appendChild(t);
342
342
  }
343
343
  getChecklist() {
344
344
  return this.checklist.length > 0 ? [...this.checklist] : void 0;
@@ -347,39 +347,39 @@ class N {
347
347
  this.stopTimer(), this.root.remove();
348
348
  }
349
349
  createMinimizeBtn() {
350
- const t = r("button", { className: "fl-quest-minimize-btn" }, ["−"]);
351
- return t.onclick = (e) => {
352
- e.stopPropagation(), this.minimized = !0, this.root.className = "fl-quest-overlay fl-minimized", this.root.innerHTML = "";
350
+ const e = r("button", { className: "fl-quest-minimize-btn" }, ["−"]);
351
+ return e.onclick = (t) => {
352
+ t.stopPropagation(), this.minimized = !0, this.root.className = "fl-quest-overlay fl-minimized", this.root.innerHTML = "";
353
353
  const s = r("span", { className: "fl-minimize-icon" }, ["🔍"]);
354
354
  this.root.appendChild(s), this.callbacks.onMinimize();
355
- }, t;
355
+ }, e;
356
356
  }
357
- createButton(t, e, s) {
358
- const i = r("button", { className: t });
359
- return i.textContent = e, i.onclick = (n) => {
357
+ createButton(e, t, s) {
358
+ const i = r("button", { className: e });
359
+ return i.textContent = t, i.onclick = (n) => {
360
360
  n.stopPropagation(), s();
361
361
  }, i;
362
362
  }
363
- createStat(t, e, s) {
363
+ createStat(e, t, s) {
364
364
  return r("div", { className: "fl-stat" }, [
365
- r("div", { className: `fl-stat-value ${s}` }, [t]),
366
- r("div", { className: "fl-stat-label" }, [e])
365
+ r("div", { className: `fl-stat-value ${s}` }, [e]),
366
+ r("div", { className: "fl-stat-label" }, [t])
367
367
  ]);
368
368
  }
369
- startTimer(t) {
369
+ startTimer(e) {
370
370
  this.stopTimer(), this.startTime || (this.startTime = Date.now()), this.timerInterval = setInterval(() => {
371
- const e = Math.floor((Date.now() - this.startTime) / 1e3);
372
- t.textContent = A(e);
371
+ const t = Math.floor((Date.now() - this.startTime) / 1e3);
372
+ e.textContent = N(t);
373
373
  }, 1e3);
374
374
  }
375
375
  stopTimer() {
376
376
  this.timerInterval && (clearInterval(this.timerInterval), this.timerInterval = null);
377
377
  }
378
378
  }
379
- const F = 100, P = 2 * 1024 * 1024;
380
- class z {
381
- constructor(t, e, s) {
382
- this.config = t, this.events = e, this.maskSelector = s, this.actionLogs = [], this.snapshots = [], this.snapshotTimer = null, this.startTime = 0, this.running = !1, this.handleClick = this.onClick.bind(this), this.handleScroll = this.throttle(this.onScroll.bind(this), 500), this.handleInput = this.onInput.bind(this);
379
+ const z = 100, O = 2 * 1024 * 1024;
380
+ class Q {
381
+ constructor(e, t, s) {
382
+ this.config = e, this.events = t, this.maskSelector = s, this.actionLogs = [], this.snapshots = [], this.snapshotTimer = null, this.startTime = 0, this.running = !1, this.handleClick = this.onClick.bind(this), this.handleScroll = this.throttle(this.onScroll.bind(this), 500), this.handleInput = this.onInput.bind(this);
383
383
  }
384
384
  start() {
385
385
  this.running || (this.running = !0, this.startTime = Date.now(), this.actionLogs = [], this.snapshots = [], document.addEventListener("click", this.handleClick, { capture: !0, passive: !0 }), document.addEventListener("scroll", this.handleScroll, { capture: !0, passive: !0 }), document.addEventListener("input", this.handleInput, { capture: !0, passive: !0 }), this.config.recording.domSnapshot && (this.captureSnapshot(), this.snapshotTimer = setInterval(
@@ -399,17 +399,17 @@ class z {
399
399
  getElapsedMs() {
400
400
  return this.running ? Date.now() - this.startTime : 0;
401
401
  }
402
- addLog(t) {
402
+ addLog(e) {
403
403
  this.actionLogs.push({
404
- ...t,
404
+ ...e,
405
405
  timestamp: Date.now() - this.startTime
406
406
  });
407
407
  }
408
- onClick(t) {
409
- const e = t.target;
408
+ onClick(e) {
409
+ const t = e.target;
410
410
  this.addLog({
411
411
  type: "click",
412
- target: x(e)
412
+ target: w(t)
413
413
  });
414
414
  }
415
415
  onScroll() {
@@ -418,34 +418,34 @@ class z {
418
418
  value: `${window.scrollX},${window.scrollY}`
419
419
  });
420
420
  }
421
- onInput(t) {
422
- const e = t.target;
423
- if (e.hasAttribute("data-fl-masked"))
424
- this.addLog({ type: "input", target: x(e), value: "[MASKED]" });
421
+ onInput(e) {
422
+ const t = e.target;
423
+ if (t.hasAttribute("data-fl-masked"))
424
+ this.addLog({ type: "input", target: w(t), value: "[MASKED]" });
425
425
  else {
426
- const s = e.value;
426
+ const s = t.value;
427
427
  this.addLog({
428
428
  type: "input",
429
- target: x(e),
429
+ target: w(t),
430
430
  value: s == null ? void 0 : s.slice(0, 100)
431
431
  });
432
432
  }
433
433
  }
434
434
  captureSnapshot() {
435
435
  try {
436
- const t = document.documentElement.cloneNode(!0);
436
+ const e = document.documentElement.cloneNode(!0);
437
437
  if (this.maskSelector) {
438
- const n = t.querySelectorAll(this.maskSelector);
438
+ const n = e.querySelectorAll(this.maskSelector);
439
439
  for (const o of n)
440
440
  (o instanceof HTMLInputElement || o instanceof HTMLTextAreaElement) && (o.value = "***"), o.textContent = "***";
441
441
  }
442
- const e = t.querySelectorAll("script");
443
- for (const n of e) n.remove();
444
- const s = t.querySelector("#firstlook-sdk-root");
442
+ const t = e.querySelectorAll("script");
443
+ for (const n of t) n.remove();
444
+ const s = e.querySelector("#firstlook-sdk-root");
445
445
  s == null || s.remove();
446
- const i = t.outerHTML;
447
- if (i.length > P) return;
448
- this.snapshots.length >= F && this.snapshots.shift(), this.snapshots.push({
446
+ const i = e.outerHTML;
447
+ if (i.length > O) return;
448
+ this.snapshots.length >= z && this.snapshots.shift(), this.snapshots.push({
449
449
  type: "dom-snapshot",
450
450
  timestamp: Date.now() - this.startTime,
451
451
  data: i
@@ -453,22 +453,22 @@ class z {
453
453
  } catch {
454
454
  }
455
455
  }
456
- throttle(t, e) {
456
+ throttle(e, t) {
457
457
  let s = 0;
458
458
  return (...i) => {
459
459
  const n = Date.now();
460
- n - s >= e && (s = n, t(...i));
460
+ n - s >= t && (s = n, e(...i));
461
461
  };
462
462
  }
463
463
  }
464
- function x(a) {
464
+ function w(c) {
465
465
  var n;
466
- const t = a.tagName.toLowerCase(), e = a.id ? `#${a.id}` : "", s = a.className && typeof a.className == "string" ? `.${a.className.trim().split(/\s+/).slice(0, 2).join(".")}` : "", i = ((n = a.textContent) == null ? void 0 : n.trim().slice(0, 30)) || "";
467
- return `${t}${e}${s}${i ? ` "${i}"` : ""}`;
466
+ const e = c.tagName.toLowerCase(), t = c.id ? `#${c.id}` : "", s = c.className && typeof c.className == "string" ? `.${c.className.trim().split(/\s+/).slice(0, 2).join(".")}` : "", i = ((n = c.textContent) == null ? void 0 : n.trim().slice(0, 30)) || "";
467
+ return `${e}${t}${s}${i ? ` "${i}"` : ""}`;
468
468
  }
469
- class O {
470
- constructor(t) {
471
- this.events = t, this.mediaRecorder = null, this.stream = null, this.chunks = [], this._recording = !1;
469
+ class B {
470
+ constructor(e) {
471
+ this.events = e, this.mediaRecorder = null, this.stream = null, this.chunks = [], this._recording = !1;
472
472
  }
473
473
  get recording() {
474
474
  return this._recording;
@@ -477,57 +477,57 @@ class O {
477
477
  if (!this._recording)
478
478
  try {
479
479
  this.stream = await navigator.mediaDevices.getUserMedia({ audio: !0 });
480
- const t = this.getSupportedMimeType(), e = t ? { mimeType: t } : {};
481
- this.mediaRecorder = new MediaRecorder(this.stream, e), this.chunks = [], this.mediaRecorder.ondataavailable = (s) => {
480
+ const e = this.getSupportedMimeType(), t = e ? { mimeType: e } : {};
481
+ this.mediaRecorder = new MediaRecorder(this.stream, t), this.chunks = [], this.mediaRecorder.ondataavailable = (s) => {
482
482
  s.data.size > 0 && this.chunks.push(s.data);
483
483
  }, this.mediaRecorder.start(1e3), this._recording = !0;
484
- } catch (t) {
485
- console.warn("[FirstLook] Voice recording unavailable:", t), this.events.emit({
484
+ } catch (e) {
485
+ console.warn("[FirstLook] Voice recording unavailable:", e), this.events.emit({
486
486
  type: "error",
487
- error: new Error(`Voice recording failed: ${t.message}`)
487
+ error: new Error(`Voice recording failed: ${e.message}`)
488
488
  });
489
489
  }
490
490
  }
491
491
  async stopAsync() {
492
- return !this._recording || !this.mediaRecorder ? null : new Promise((t) => {
492
+ return !this._recording || !this.mediaRecorder ? null : new Promise((e) => {
493
493
  this.mediaRecorder.onstop = () => {
494
494
  var s;
495
- const e = this.chunks.length > 0 ? new Blob(this.chunks, { type: ((s = this.mediaRecorder) == null ? void 0 : s.mimeType) || "audio/webm" }) : null;
496
- this.cleanup(), t(e);
495
+ const t = this.chunks.length > 0 ? new Blob(this.chunks, { type: ((s = this.mediaRecorder) == null ? void 0 : s.mimeType) || "audio/webm" }) : null;
496
+ this.cleanup(), e(t);
497
497
  }, this.mediaRecorder.stop();
498
498
  });
499
499
  }
500
- async captureSnippet(t = 1e4) {
501
- return await this.start(), new Promise((e) => {
500
+ async captureSnippet(e = 1e4) {
501
+ return await this.start(), new Promise((t) => {
502
502
  setTimeout(async () => {
503
503
  const s = await this.stopAsync();
504
- e(s);
505
- }, t);
504
+ t(s);
505
+ }, e);
506
506
  });
507
507
  }
508
508
  cleanup() {
509
509
  if (this._recording = !1, this.stream) {
510
- for (const t of this.stream.getTracks())
511
- t.stop();
510
+ for (const e of this.stream.getTracks())
511
+ e.stop();
512
512
  this.stream = null;
513
513
  }
514
514
  this.mediaRecorder = null, this.chunks = [];
515
515
  }
516
516
  getSupportedMimeType() {
517
- const t = [
517
+ const e = [
518
518
  "audio/webm;codecs=opus",
519
519
  "audio/webm",
520
520
  "audio/ogg;codecs=opus",
521
521
  "audio/mp4"
522
522
  ];
523
- for (const e of t)
524
- if (typeof MediaRecorder < "u" && MediaRecorder.isTypeSupported(e)) return e;
523
+ for (const t of e)
524
+ if (typeof MediaRecorder < "u" && MediaRecorder.isTypeSupported(t)) return t;
525
525
  return "";
526
526
  }
527
527
  }
528
- class Q {
529
- constructor(t, e) {
530
- this.shadowRoot = t, this.config = e, this.container = null, this.refreshInterval = null, this.cachedIp = null;
528
+ class U {
529
+ constructor(e, t) {
530
+ this.shadowRoot = e, this.config = t, this.container = null, this.refreshInterval = null, this.cachedIp = null;
531
531
  }
532
532
  show() {
533
533
  this.container || (this.container = document.createElement("div"), this.container.className = "fl-watermark", this.renderTiles(), this.shadowRoot.appendChild(this.container), this.fetchIp().then(() => this.renderTiles()), this.refreshInterval = setInterval(() => this.renderTiles(), 6e4));
@@ -538,8 +538,8 @@ class Q {
538
538
  async fetchIp() {
539
539
  if (!this.cachedIp)
540
540
  try {
541
- const t = await fetch("https://api.ipify.org?format=text");
542
- t.ok && (this.cachedIp = await t.text());
541
+ const e = await fetch("https://api.ipify.org?format=text");
542
+ e.ok && (this.cachedIp = await e.text());
543
543
  } catch {
544
544
  this.cachedIp = "N/A";
545
545
  }
@@ -547,17 +547,17 @@ class Q {
547
547
  renderTiles() {
548
548
  if (!this.container) return;
549
549
  this.container.innerHTML = "";
550
- const t = this.cachedIp ?? "", e = (/* @__PURE__ */ new Date()).toISOString().slice(0, 19), s = t ? `${this.config.userId} | ${e} | ${t}` : `${this.config.userId} | ${e}`, i = 320, n = 80, o = Math.ceil(window.innerWidth / i) + 1, l = Math.ceil(window.innerHeight / n) + 1;
551
- for (let c = 0; c < l; c++)
550
+ const e = this.cachedIp ?? "", t = (/* @__PURE__ */ new Date()).toISOString().slice(0, 19), s = e ? `${this.config.userId} | ${t} | ${e}` : `${this.config.userId} | ${t}`, i = 320, n = 80, o = Math.ceil(window.innerWidth / i) + 1, l = Math.ceil(window.innerHeight / n) + 1;
551
+ for (let a = 0; a < l; a++)
552
552
  for (let h = 0; h < o; h++) {
553
553
  const d = document.createElement("span");
554
- d.className = "fl-watermark-tile", d.textContent = s, d.style.left = `${h * i}px`, d.style.top = `${c * n}px`, this.container.appendChild(d);
554
+ d.className = "fl-watermark-tile", d.textContent = s, d.style.left = `${h * i}px`, d.style.top = `${a * n}px`, this.container.appendChild(d);
555
555
  }
556
556
  }
557
557
  }
558
- class B {
559
- constructor(t) {
560
- this.selectors = t, this.observer = null, this.maskedElements = /* @__PURE__ */ new Set();
558
+ class $ {
559
+ constructor(e) {
560
+ this.selectors = e, this.observer = null, this.maskedElements = /* @__PURE__ */ new Set();
561
561
  }
562
562
  start() {
563
563
  this.scanAndMark(), this.observer = new MutationObserver(() => this.scanAndMark()), this.observer.observe(document.body, {
@@ -568,24 +568,24 @@ class B {
568
568
  });
569
569
  }
570
570
  stop() {
571
- var t;
572
- (t = this.observer) == null || t.disconnect(), this.observer = null;
573
- for (const e of this.maskedElements)
574
- e.removeAttribute("data-fl-masked");
571
+ var e;
572
+ (e = this.observer) == null || e.disconnect(), this.observer = null;
573
+ for (const t of this.maskedElements)
574
+ t.removeAttribute("data-fl-masked");
575
575
  this.maskedElements.clear();
576
576
  }
577
- isMasked(t) {
578
- return t.hasAttribute("data-fl-masked");
577
+ isMasked(e) {
578
+ return e.hasAttribute("data-fl-masked");
579
579
  }
580
580
  getCombinedSelector() {
581
581
  return this.selectors.join(", ");
582
582
  }
583
583
  scanAndMark() {
584
- const t = this.getCombinedSelector();
585
- if (t)
584
+ const e = this.getCombinedSelector();
585
+ if (e)
586
586
  try {
587
- const e = document.querySelectorAll(t);
588
- for (const s of e)
587
+ const t = document.querySelectorAll(e);
588
+ for (const s of t)
589
589
  this.maskedElements.has(s) || (s.setAttribute("data-fl-masked", "true"), this.maskedElements.add(s));
590
590
  for (const s of this.maskedElements)
591
591
  document.contains(s) || this.maskedElements.delete(s);
@@ -593,93 +593,93 @@ class B {
593
593
  }
594
594
  }
595
595
  }
596
- const $ = "firstlook_uat", U = 1, u = {
596
+ const j = "firstlook_uat", K = 1, u = {
597
597
  sessions: "sessions",
598
598
  recordings: "recordings",
599
599
  annotations: "annotations",
600
600
  uploadQueue: "upload_queue"
601
601
  };
602
- class j {
602
+ class H {
603
603
  constructor() {
604
604
  this.db = null;
605
605
  }
606
606
  async open() {
607
607
  if (!this.db)
608
- return new Promise((t, e) => {
609
- const s = indexedDB.open($, U);
608
+ return new Promise((e, t) => {
609
+ const s = indexedDB.open(j, K);
610
610
  s.onupgradeneeded = () => {
611
611
  const i = s.result;
612
612
  i.objectStoreNames.contains(u.sessions) || i.createObjectStore(u.sessions, { keyPath: "sessionId" }), i.objectStoreNames.contains(u.recordings) || i.createObjectStore(u.recordings, { autoIncrement: !0 }).createIndex("sessionId", "sessionId", { unique: !1 }), i.objectStoreNames.contains(u.annotations) || i.createObjectStore(u.annotations, { autoIncrement: !0 }).createIndex("sessionId", "sessionId", { unique: !1 }), i.objectStoreNames.contains(u.uploadQueue) || i.createObjectStore(u.uploadQueue, { autoIncrement: !0 });
613
613
  }, s.onsuccess = () => {
614
- this.db = s.result, t();
615
- }, s.onerror = () => e(s.error);
614
+ this.db = s.result, e();
615
+ }, s.onerror = () => t(s.error);
616
616
  });
617
617
  }
618
- async saveSession(t) {
619
- await this.put(u.sessions, t);
618
+ async saveSession(e) {
619
+ await this.put(u.sessions, e);
620
620
  }
621
- async getSession(t) {
622
- return this.get(u.sessions, t);
621
+ async getSession(e) {
622
+ return this.get(u.sessions, e);
623
623
  }
624
- async saveRecording(t, e) {
625
- await this.put(u.recordings, { sessionId: t, ...e });
624
+ async saveRecording(e, t) {
625
+ await this.put(u.recordings, { sessionId: e, ...t });
626
626
  }
627
- async saveAnnotation(t, e) {
628
- await this.put(u.annotations, { sessionId: t, ...e });
627
+ async saveAnnotation(e, t) {
628
+ await this.put(u.annotations, { sessionId: e, ...t });
629
629
  }
630
- async getAnnotations(t) {
631
- return this.getAllByIndex(u.annotations, "sessionId", t);
630
+ async getAnnotations(e) {
631
+ return this.getAllByIndex(u.annotations, "sessionId", e);
632
632
  }
633
- async enqueueUpload(t) {
633
+ async enqueueUpload(e) {
634
634
  await this.put(u.uploadQueue, {
635
- payload: t,
635
+ payload: e,
636
636
  createdAt: Date.now(),
637
637
  attempts: 0
638
638
  });
639
639
  }
640
640
  async getPendingUploads() {
641
- const t = this.ensureDb();
642
- return new Promise((e, s) => {
643
- const o = t.transaction(u.uploadQueue, "readonly").objectStore(u.uploadQueue).openCursor(), l = [];
641
+ const e = this.ensureDb();
642
+ return new Promise((t, s) => {
643
+ const o = e.transaction(u.uploadQueue, "readonly").objectStore(u.uploadQueue).openCursor(), l = [];
644
644
  o.onsuccess = () => {
645
- const c = o.result;
646
- c ? (l.push({
647
- key: c.key,
648
- payload: c.value.payload,
649
- attempts: c.value.attempts,
650
- lastAttemptAt: c.value.lastAttemptAt
651
- }), c.continue()) : e(l);
645
+ const a = o.result;
646
+ a ? (l.push({
647
+ key: a.key,
648
+ payload: a.value.payload,
649
+ attempts: a.value.attempts,
650
+ lastAttemptAt: a.value.lastAttemptAt
651
+ }), a.continue()) : t(l);
652
652
  }, o.onerror = () => s(o.error);
653
653
  });
654
654
  }
655
- async removeFromQueue(t) {
656
- const e = this.ensureDb();
655
+ async removeFromQueue(e) {
656
+ const t = this.ensureDb();
657
657
  return new Promise((s, i) => {
658
- const o = e.transaction(u.uploadQueue, "readwrite").objectStore(u.uploadQueue).delete(t);
658
+ const o = t.transaction(u.uploadQueue, "readwrite").objectStore(u.uploadQueue).delete(e);
659
659
  o.onsuccess = () => s(), o.onerror = () => i(o.error);
660
660
  });
661
661
  }
662
- async incrementAttempts(t) {
663
- const e = this.ensureDb();
662
+ async incrementAttempts(e) {
663
+ const t = this.ensureDb();
664
664
  return new Promise((s, i) => {
665
- const n = e.transaction(u.uploadQueue, "readwrite"), o = n.objectStore(u.uploadQueue), l = o.get(t);
665
+ const n = t.transaction(u.uploadQueue, "readwrite"), o = n.objectStore(u.uploadQueue), l = o.get(e);
666
666
  l.onsuccess = () => {
667
- const c = l.result;
668
- c && (c.attempts = (c.attempts ?? 0) + 1, c.lastAttemptAt = Date.now(), o.put(c, t));
667
+ const a = l.result;
668
+ a && (a.attempts = (a.attempts ?? 0) + 1, a.lastAttemptAt = Date.now(), o.put(a, e));
669
669
  }, n.oncomplete = () => s(), n.onerror = () => i(n.error);
670
670
  });
671
671
  }
672
- async clearSession(t) {
672
+ async clearSession(e) {
673
673
  const s = this.ensureDb().transaction(
674
674
  [u.sessions, u.recordings, u.annotations],
675
675
  "readwrite"
676
676
  );
677
- s.objectStore(u.sessions).delete(t);
677
+ s.objectStore(u.sessions).delete(e);
678
678
  for (const i of [u.recordings, u.annotations]) {
679
- const l = s.objectStore(i).index("sessionId").openCursor(IDBKeyRange.only(t));
679
+ const l = s.objectStore(i).index("sessionId").openCursor(IDBKeyRange.only(e));
680
680
  l.onsuccess = () => {
681
- const c = l.result;
682
- c && (c.delete(), c.continue());
681
+ const a = l.result;
682
+ a && (a.delete(), a.continue());
683
683
  };
684
684
  }
685
685
  return new Promise((i, n) => {
@@ -687,69 +687,69 @@ class j {
687
687
  });
688
688
  }
689
689
  close() {
690
- var t;
691
- (t = this.db) == null || t.close(), this.db = null;
690
+ var e;
691
+ (e = this.db) == null || e.close(), this.db = null;
692
692
  }
693
693
  ensureDb() {
694
694
  if (!this.db) throw new Error("[FirstLook] Storage not opened. Call open() first.");
695
695
  return this.db;
696
696
  }
697
- async put(t, e) {
697
+ async put(e, t) {
698
698
  const s = this.ensureDb();
699
699
  return new Promise((i, n) => {
700
- const o = s.transaction(t, "readwrite");
701
- o.objectStore(t).put(e), o.oncomplete = () => i(), o.onerror = () => n(o.error);
700
+ const o = s.transaction(e, "readwrite");
701
+ o.objectStore(e).put(t), o.oncomplete = () => i(), o.onerror = () => n(o.error);
702
702
  });
703
703
  }
704
- async get(t, e) {
704
+ async get(e, t) {
705
705
  const s = this.ensureDb();
706
706
  return new Promise((i, n) => {
707
- const l = s.transaction(t, "readonly").objectStore(t).get(e);
707
+ const l = s.transaction(e, "readonly").objectStore(e).get(t);
708
708
  l.onsuccess = () => i(l.result), l.onerror = () => n(l.error);
709
709
  });
710
710
  }
711
- async getAllByIndex(t, e, s) {
711
+ async getAllByIndex(e, t, s) {
712
712
  const i = this.ensureDb();
713
713
  return new Promise((n, o) => {
714
- const h = i.transaction(t, "readonly").objectStore(t).index(e).getAll(s);
714
+ const h = i.transaction(e, "readonly").objectStore(e).index(t).getAll(s);
715
715
  h.onsuccess = () => n(h.result), h.onerror = () => o(h.error);
716
716
  });
717
717
  }
718
718
  }
719
- const S = ["#e17055", "#6c5ce7", "#00b894", "#fdcb6e", "#ffffff"];
720
- class K {
721
- constructor(t) {
722
- this.shadowRoot = t, this.overlay = null, this.canvas = null, this.ctx = null, this.drawing = !1, this.currentPath = [], this.paths = [], this.selectedColor = S[0], this.screenshotDataUrl = "";
719
+ const T = ["#e17055", "#6c5ce7", "#00b894", "#fdcb6e", "#ffffff"];
720
+ class _ {
721
+ constructor(e) {
722
+ this.shadowRoot = e, this.overlay = null, this.canvas = null, this.ctx = null, this.drawing = !1, this.currentPath = [], this.paths = [], this.selectedColor = T[0], this.screenshotDataUrl = "";
723
723
  }
724
724
  async open() {
725
- return this.screenshotDataUrl = await this.captureScreenshot(), new Promise((t) => {
725
+ return this.screenshotDataUrl = await this.captureScreenshot(), new Promise((e) => {
726
726
  this.overlay = r("div", { className: "fl-annotation-overlay" });
727
- const e = r("div", { className: "fl-annotation-canvas-wrap" });
728
- this.canvas = document.createElement("canvas"), this.canvas.className = "fl-annotation-canvas", e.appendChild(this.canvas), this.overlay.appendChild(e);
727
+ const t = r("div", { className: "fl-annotation-canvas-wrap" });
728
+ this.canvas = document.createElement("canvas"), this.canvas.className = "fl-annotation-canvas", t.appendChild(this.canvas), this.overlay.appendChild(t);
729
729
  const s = r("input", {
730
730
  className: "fl-annotation-comment",
731
731
  type: "text",
732
732
  placeholder: "Add a comment..."
733
733
  }), i = r("div", { className: "fl-color-picker" });
734
- for (const c of S) {
735
- const h = r("div", { className: `fl-color-swatch ${c === this.selectedColor ? "fl-selected" : ""}` });
736
- h.style.background = c, h.onclick = () => {
737
- this.selectedColor = c, i.querySelectorAll(".fl-color-swatch").forEach((d) => d.classList.remove("fl-selected")), h.classList.add("fl-selected");
734
+ for (const a of T) {
735
+ const h = r("div", { className: `fl-color-swatch ${a === this.selectedColor ? "fl-selected" : ""}` });
736
+ h.style.background = a, h.onclick = () => {
737
+ this.selectedColor = a, i.querySelectorAll(".fl-color-swatch").forEach((d) => d.classList.remove("fl-selected")), h.classList.add("fl-selected");
738
738
  }, i.appendChild(h);
739
739
  }
740
740
  const n = r("button", { className: "fl-btn fl-btn-ok" }, ["Submit"]);
741
741
  n.onclick = () => {
742
- const c = {
742
+ const a = {
743
743
  screenshotDataUrl: this.getAnnotatedImage(),
744
744
  drawings: [...this.paths],
745
745
  comment: s.value,
746
746
  timestamp: Date.now()
747
747
  };
748
- this.close(), t(c);
748
+ this.close(), e(a);
749
749
  };
750
750
  const o = r("button", { className: "fl-btn fl-btn-ng" }, ["Cancel"]);
751
751
  o.onclick = () => {
752
- this.close(), t(null);
752
+ this.close(), e(null);
753
753
  };
754
754
  const l = r("div", { className: "fl-annotation-toolbar" }, [
755
755
  i,
@@ -761,12 +761,12 @@ class K {
761
761
  });
762
762
  }
763
763
  close() {
764
- var t;
765
- (t = this.overlay) == null || t.remove(), this.overlay = null, this.canvas = null, this.ctx = null, this.paths = [], this.currentPath = [];
764
+ var e;
765
+ (e = this.overlay) == null || e.remove(), this.overlay = null, this.canvas = null, this.ctx = null, this.paths = [], this.currentPath = [];
766
766
  }
767
767
  async captureScreenshot() {
768
768
  try {
769
- const t = window.innerWidth, e = window.innerHeight, s = document.documentElement.cloneNode(!0), i = s.querySelector("#firstlook-sdk-root");
769
+ const e = window.innerWidth, t = window.innerHeight, s = document.documentElement.cloneNode(!0), i = s.querySelector("#firstlook-sdk-root");
770
770
  i == null || i.remove();
771
771
  const n = s.querySelectorAll('[data-fl-masked], input[type="password"]');
772
772
  for (const p of n)
@@ -777,47 +777,47 @@ class K {
777
777
  const p = window.getComputedStyle(document.body);
778
778
  o.style.backgroundColor = p.backgroundColor, o.style.color = p.color, o.style.fontFamily = p.fontFamily, o.style.margin = "0", o.style.overflow = "hidden";
779
779
  }
780
- const l = new XMLSerializer().serializeToString(s), c = `<svg xmlns="http://www.w3.org/2000/svg" width="${t}" height="${e}">
780
+ const l = new XMLSerializer().serializeToString(s), a = `<svg xmlns="http://www.w3.org/2000/svg" width="${e}" height="${t}">
781
781
  <foreignObject width="100%" height="100%">
782
782
  ${l}
783
783
  </foreignObject>
784
- </svg>`, h = new Blob([c], { type: "image/svg+xml;charset=utf-8" }), d = URL.createObjectURL(h), m = document.createElement("canvas");
785
- m.width = t * window.devicePixelRatio, m.height = e * window.devicePixelRatio;
784
+ </svg>`, h = new Blob([a], { type: "image/svg+xml;charset=utf-8" }), d = URL.createObjectURL(h), m = document.createElement("canvas");
785
+ m.width = e * window.devicePixelRatio, m.height = t * window.devicePixelRatio;
786
786
  const f = m.getContext("2d");
787
787
  return f.scale(window.devicePixelRatio, window.devicePixelRatio), new Promise((p) => {
788
788
  const g = new Image();
789
789
  g.onload = () => {
790
- f.drawImage(g, 0, 0, t, e), URL.revokeObjectURL(d), p(m.toDataURL("image/png"));
790
+ f.drawImage(g, 0, 0, e, t), URL.revokeObjectURL(d), p(m.toDataURL("image/png"));
791
791
  }, g.onerror = () => {
792
- URL.revokeObjectURL(d), p(this.captureScreenshotFallback(t, e));
792
+ URL.revokeObjectURL(d), p(this.captureScreenshotFallback(e, t));
793
793
  }, g.src = d;
794
794
  });
795
795
  } catch {
796
796
  return this.captureScreenshotFallback(window.innerWidth, window.innerHeight);
797
797
  }
798
798
  }
799
- captureScreenshotFallback(t, e) {
799
+ captureScreenshotFallback(e, t) {
800
800
  const s = document.createElement("canvas");
801
- s.width = t, s.height = e;
801
+ s.width = e, s.height = t;
802
802
  const i = s.getContext("2d"), n = window.getComputedStyle(document.body);
803
- return i.fillStyle = n.backgroundColor || "#ffffff", i.fillRect(0, 0, t, e), i.fillStyle = "#333", i.font = "14px sans-serif", i.fillText(`URL: ${window.location.href}`, 20, 30), i.fillText(`Time: ${(/* @__PURE__ */ new Date()).toISOString()}`, 20, 50), i.fillText("(SVG capture unavailable — metadata view)", 20, 70), s.toDataURL("image/png");
803
+ return i.fillStyle = n.backgroundColor || "#ffffff", i.fillRect(0, 0, e, t), i.fillStyle = "#333", i.font = "14px sans-serif", i.fillText(`URL: ${window.location.href}`, 20, 30), i.fillText(`Time: ${(/* @__PURE__ */ new Date()).toISOString()}`, 20, 50), i.fillText("(SVG capture unavailable — metadata view)", 20, 70), s.toDataURL("image/png");
804
804
  }
805
805
  initCanvas() {
806
806
  if (!this.canvas) return;
807
- const t = new Image();
808
- t.onload = () => {
809
- const e = window.innerWidth * 0.9, s = window.innerHeight * 0.7, i = Math.min(e / t.width, s / t.height, 1);
810
- this.canvas.width = t.width * i, this.canvas.height = t.height * i, this.ctx = this.canvas.getContext("2d"), this.ctx.drawImage(t, 0, 0, this.canvas.width, this.canvas.height), this.canvas.addEventListener("pointerdown", this.onDrawStart.bind(this)), this.canvas.addEventListener("pointermove", this.onDrawMove.bind(this)), this.canvas.addEventListener("pointerup", this.onDrawEnd.bind(this)), this.canvas.addEventListener("pointerleave", this.onDrawEnd.bind(this));
811
- }, t.src = this.screenshotDataUrl;
807
+ const e = new Image();
808
+ e.onload = () => {
809
+ const t = window.innerWidth * 0.9, s = window.innerHeight * 0.7, i = Math.min(t / e.width, s / e.height, 1);
810
+ this.canvas.width = e.width * i, this.canvas.height = e.height * i, this.ctx = this.canvas.getContext("2d"), this.ctx.drawImage(e, 0, 0, this.canvas.width, this.canvas.height), this.canvas.addEventListener("pointerdown", this.onDrawStart.bind(this)), this.canvas.addEventListener("pointermove", this.onDrawMove.bind(this)), this.canvas.addEventListener("pointerup", this.onDrawEnd.bind(this)), this.canvas.addEventListener("pointerleave", this.onDrawEnd.bind(this));
811
+ }, e.src = this.screenshotDataUrl;
812
812
  }
813
- onDrawStart(t) {
813
+ onDrawStart(e) {
814
814
  this.drawing = !0;
815
- const e = this.canvas.getBoundingClientRect();
816
- this.currentPath = [{ x: t.clientX - e.left, y: t.clientY - e.top }];
815
+ const t = this.canvas.getBoundingClientRect();
816
+ this.currentPath = [{ x: e.clientX - t.left, y: e.clientY - t.top }];
817
817
  }
818
- onDrawMove(t) {
818
+ onDrawMove(e) {
819
819
  if (!this.drawing || !this.ctx) return;
820
- const e = this.canvas.getBoundingClientRect(), s = { x: t.clientX - e.left, y: t.clientY - e.top };
820
+ const t = this.canvas.getBoundingClientRect(), s = { x: e.clientX - t.left, y: e.clientY - t.top };
821
821
  if (this.currentPath.push(s), this.ctx.strokeStyle = this.selectedColor, this.ctx.lineWidth = 3, this.ctx.lineCap = "round", this.ctx.lineJoin = "round", this.currentPath.length >= 2) {
822
822
  const i = this.currentPath[this.currentPath.length - 2];
823
823
  this.ctx.beginPath(), this.ctx.moveTo(i.x, i.y), this.ctx.lineTo(s.x, s.y), this.ctx.stroke();
@@ -831,15 +831,15 @@ class K {
831
831
  }), this.drawing = !1, this.currentPath = [];
832
832
  }
833
833
  getAnnotatedImage() {
834
- var t;
835
- return ((t = this.canvas) == null ? void 0 : t.toDataURL("image/png")) || this.screenshotDataUrl;
834
+ var e;
835
+ return ((e = this.canvas) == null ? void 0 : e.toDataURL("image/png")) || this.screenshotDataUrl;
836
836
  }
837
837
  }
838
- class H {
839
- constructor(t, e) {
840
- this.shadowRoot = t, this.events = e, this.annotations = [], this.active = !1, this.onKeydown = (s) => {
838
+ class W {
839
+ constructor(e, t) {
840
+ this.shadowRoot = e, this.events = t, this.annotations = [], this.active = !1, this.onKeydown = (s) => {
841
841
  s.ctrlKey && s.shiftKey && s.key === "R" && (s.preventDefault(), this.trigger());
842
- }, this.annotationCanvas = new K(t);
842
+ }, this.annotationCanvas = new _(e);
843
843
  }
844
844
  start() {
845
845
  document.addEventListener("keydown", this.onKeydown);
@@ -854,17 +854,17 @@ class H {
854
854
  if (!this.active) {
855
855
  this.active = !0;
856
856
  try {
857
- const t = await this.annotationCanvas.open();
858
- t && (this.annotations.push(t), this.events.emit({ type: "report:submitted" }));
857
+ const e = await this.annotationCanvas.open();
858
+ e && (this.annotations.push(e), this.events.emit({ type: "report:submitted" }));
859
859
  } finally {
860
860
  this.active = !1;
861
861
  }
862
862
  }
863
863
  }
864
864
  }
865
- class _ {
866
- constructor(t, e) {
867
- this.requiredTaps = t, this.onActivate = e, this.tapCount = 0, this.tapTimer = null, this.handler = null;
865
+ class V {
866
+ constructor(e, t) {
867
+ this.requiredTaps = e, this.onActivate = t, this.tapCount = 0, this.tapTimer = null, this.handler = null;
868
868
  }
869
869
  start() {
870
870
  this.handler = this.onTap.bind(this), document.addEventListener("pointerdown", this.handler, { passive: !0 });
@@ -872,17 +872,17 @@ class _ {
872
872
  stop() {
873
873
  this.handler && (document.removeEventListener("pointerdown", this.handler), this.handler = null), this.reset();
874
874
  }
875
- onTap(t) {
875
+ onTap(e) {
876
876
  this.tapCount++, this.tapTimer && clearTimeout(this.tapTimer), this.tapCount >= this.requiredTaps ? (this.reset(), this.onActivate()) : this.tapTimer = setTimeout(() => this.reset(), 800);
877
877
  }
878
878
  reset() {
879
879
  this.tapCount = 0, this.tapTimer && (clearTimeout(this.tapTimer), this.tapTimer = null);
880
880
  }
881
881
  }
882
- const w = "firstlook:uat-active";
882
+ const y = "firstlook:uat-active";
883
883
  class C {
884
- constructor(t) {
885
- this.onActivate = t, this.handlers = [];
884
+ constructor(e) {
885
+ this.onActivate = e, this.handlers = [];
886
886
  }
887
887
  start() {
888
888
  if (this.checkUrl()) {
@@ -893,29 +893,29 @@ class C {
893
893
  this.onActivate();
894
894
  return;
895
895
  }
896
- const t = () => {
896
+ const e = () => {
897
897
  this.checkUrl() && (this.persist(), this.onActivate());
898
898
  };
899
- window.addEventListener("hashchange", t), this.handlers.push(["hashchange", t]), window.addEventListener("popstate", t), this.handlers.push(["popstate", t]);
899
+ window.addEventListener("hashchange", e), this.handlers.push(["hashchange", e]), window.addEventListener("popstate", e), this.handlers.push(["popstate", e]);
900
900
  }
901
901
  stop() {
902
- for (const [t, e] of this.handlers)
903
- window.removeEventListener(t, e);
902
+ for (const [e, t] of this.handlers)
903
+ window.removeEventListener(e, t);
904
904
  this.handlers = [];
905
905
  }
906
906
  static clearPersisted() {
907
907
  try {
908
- sessionStorage.removeItem(w);
908
+ sessionStorage.removeItem(y);
909
909
  } catch {
910
910
  }
911
911
  }
912
912
  checkUrl() {
913
- const t = new URLSearchParams(window.location.search);
914
- if (t.has("firstlook") || t.has("uat-mode") || t.get("uat") === "1")
913
+ const e = new URLSearchParams(window.location.search);
914
+ if (e.has("firstlook") || e.has("uat-mode") || e.get("uat") === "1")
915
915
  return !0;
916
- const e = window.location.hash, s = e.indexOf("?");
916
+ const t = window.location.hash, s = t.indexOf("?");
917
917
  if (s !== -1) {
918
- const i = new URLSearchParams(e.substring(s));
918
+ const i = new URLSearchParams(t.substring(s));
919
919
  if (i.has("firstlook") || i.has("uat-mode") || i.get("uat") === "1")
920
920
  return !0;
921
921
  }
@@ -923,69 +923,90 @@ class C {
923
923
  }
924
924
  persist() {
925
925
  try {
926
- sessionStorage.setItem(w, "1");
926
+ sessionStorage.setItem(y, "1");
927
927
  } catch {
928
928
  }
929
929
  }
930
930
  hasPersisted() {
931
931
  try {
932
- return sessionStorage.getItem(w) === "1";
932
+ return sessionStorage.getItem(y) === "1";
933
933
  } catch {
934
934
  return !1;
935
935
  }
936
936
  }
937
937
  }
938
- class W {
939
- constructor(t) {
940
- this.onActivate = t, this.handler = null;
938
+ const x = class x {
939
+ constructor(e) {
940
+ this.onActivate = e, this.handler = null, this.sequence = [], this.sequenceTimer = null;
941
941
  }
942
942
  start() {
943
- this.handler = (t) => {
944
- t.code === "KeyU" && t.shiftKey && (t.ctrlKey || t.metaKey) && (t.preventDefault(), this.onActivate());
943
+ this.handler = (e) => {
944
+ if ((e.key === "u" || e.key === "U") && e.shiftKey && (e.ctrlKey || e.metaKey)) {
945
+ e.preventDefault(), this.onActivate();
946
+ return;
947
+ }
948
+ if (e.key.startsWith("Arrow")) {
949
+ this.sequence.push(e.key), this.sequenceTimer && clearTimeout(this.sequenceTimer), this.sequenceTimer = setTimeout(() => {
950
+ this.sequence = [];
951
+ }, 3e3);
952
+ const t = x.KONAMI;
953
+ this.sequence.length > t.length && (this.sequence = this.sequence.slice(-t.length)), this.sequence.length === t.length && this.sequence.every((s, i) => s === t[i]) && (this.sequence = [], this.onActivate());
954
+ }
945
955
  }, window.addEventListener("keydown", this.handler);
946
956
  }
947
957
  stop() {
948
- this.handler && (window.removeEventListener("keydown", this.handler), this.handler = null);
958
+ this.handler && (window.removeEventListener("keydown", this.handler), this.handler = null), this.sequenceTimer && (clearTimeout(this.sequenceTimer), this.sequenceTimer = null);
949
959
  }
950
- }
951
- class V {
952
- constructor(t, e) {
953
- this.shadowRoot = t, this.callbacks = e, this.root = null, this.outsideClickHandler = null;
960
+ };
961
+ x.KONAMI = [
962
+ "ArrowUp",
963
+ "ArrowUp",
964
+ "ArrowDown",
965
+ "ArrowDown",
966
+ "ArrowLeft",
967
+ "ArrowRight",
968
+ "ArrowLeft",
969
+ "ArrowRight"
970
+ ];
971
+ let S = x;
972
+ class X {
973
+ constructor(e, t) {
974
+ this.shadowRoot = e, this.callbacks = t, this.root = null, this.outsideClickHandler = null;
954
975
  }
955
976
  show() {
956
977
  if (this.root) return;
957
978
  this.root = r("div", { className: "fl-debug-menu" }), this.root.style.pointerEvents = "auto";
958
- for (const e of ["click", "mousedown", "mouseup", "pointerdown", "pointerup", "touchstart", "touchend"])
959
- this.root.addEventListener(e, (s) => s.stopPropagation());
960
- const t = [
979
+ for (const t of ["click", "mousedown", "mouseup", "pointerdown", "pointerup", "touchstart", "touchend"])
980
+ this.root.addEventListener(t, (s) => s.stopPropagation());
981
+ const e = [
961
982
  { icon: "▶", label: "Start Session", action: this.callbacks.onStartSession },
962
983
  { icon: "📸", label: "Report Issue", action: this.callbacks.onReportIssue },
963
984
  { icon: "✖", label: "Close SDK", action: this.callbacks.onClose }
964
985
  ];
965
- for (const e of t) {
986
+ for (const t of e) {
966
987
  const s = r("button", { className: "fl-debug-menu-item" }, [
967
- r("span", { className: "fl-debug-menu-item-icon" }, [e.icon]),
968
- e.label
988
+ r("span", { className: "fl-debug-menu-item-icon" }, [t.icon]),
989
+ t.label
969
990
  ]);
970
991
  s.onclick = (i) => {
971
- i.stopPropagation(), this.hide(), e.action();
992
+ i.stopPropagation(), this.hide(), t.action();
972
993
  }, this.root.appendChild(s);
973
994
  }
974
995
  this.shadowRoot.appendChild(this.root), setTimeout(() => {
975
- this.outsideClickHandler = (e) => {
976
- this.root && !this.root.contains(e.target) && this.hide();
996
+ this.outsideClickHandler = (t) => {
997
+ this.root && !this.root.contains(t.target) && this.hide();
977
998
  }, document.addEventListener("click", this.outsideClickHandler, { capture: !0 });
978
999
  }, 100);
979
1000
  }
980
1001
  hide() {
981
- var t;
982
- (t = this.root) == null || t.remove(), this.root = null, this.outsideClickHandler && (document.removeEventListener("click", this.outsideClickHandler, { capture: !0 }), this.outsideClickHandler = null);
1002
+ var e;
1003
+ (e = this.root) == null || e.remove(), this.root = null, this.outsideClickHandler && (document.removeEventListener("click", this.outsideClickHandler, { capture: !0 }), this.outsideClickHandler = null);
983
1004
  }
984
1005
  get visible() {
985
1006
  return this.root !== null;
986
1007
  }
987
1008
  }
988
- const X = (
1009
+ const Y = (
989
1010
  /* css */
990
1011
  `
991
1012
  :host {
@@ -1486,10 +1507,10 @@ const X = (
1486
1507
  }
1487
1508
  .fl-feedback-modal-actions { padding: 0 16px 16px; }
1488
1509
  `
1489
- ), Y = 5;
1490
- class G {
1510
+ ), G = 5;
1511
+ class J {
1491
1512
  constructor() {
1492
- this.config = null, this.events = new E(), this.state = "idle", this.hostElement = null, this.shadowRoot = null, this.questManager = null, this.questOverlay = null, this.sessionRecorder = null, this.voiceRecorder = null, this.watermark = null, this.fieldMasker = null, this.storage = null, this.issueReporter = null, this.debugMenu = null, this.tapTrigger = null, this.deepLinkTrigger = null, this.keyboardTrigger = null, this.sessionId = null, this.sessionStartTime = 0, this.maxDurationTimer = null, this.backupTimer = null, this.isFlushing = !1;
1513
+ this.config = null, this.events = new L(), this.state = "idle", this.hostElement = null, this.shadowRoot = null, this.questManager = null, this.questOverlay = null, this.sessionRecorder = null, this.voiceRecorder = null, this.watermark = null, this.fieldMasker = null, this.storage = null, this.issueReporter = null, this.debugMenu = null, this.tapTrigger = null, this.deepLinkTrigger = null, this.keyboardTrigger = null, this.sessionId = null, this.sessionStartTime = 0, this.maxDurationTimer = null, this.backupTimer = null, this.isFlushing = !1;
1493
1514
  }
1494
1515
  // ----------------------------------------------------------------
1495
1516
  // Public API
@@ -1498,12 +1519,12 @@ class G {
1498
1519
  * Initialize the SDK with configuration.
1499
1520
  * This does NOT activate the UI — it only sets up triggers.
1500
1521
  */
1501
- async init(t) {
1522
+ async init(e) {
1502
1523
  if (this.state !== "idle") {
1503
1524
  console.warn("[FirstLook] SDK already initialized.");
1504
1525
  return;
1505
1526
  }
1506
- this.config = M(t), this.storage = new j(), await this.storage.open(), this.createShadowHost(), this.setupTriggers(), this.fieldMasker = new B(this.config.security.maskSelectors), this.state = "initialized", this.events.emit({ type: "sdk:initialized" }), this.flushUploadQueue(!0);
1527
+ this.config = R(e), this.storage = new H(), await this.storage.open(), this.createShadowHost(), this.setupTriggers(), this.fieldMasker = new $(this.config.security.maskSelectors), this.state = "initialized", this.events.emit({ type: "sdk:initialized" }), this.flushUploadQueue(!0);
1507
1528
  }
1508
1529
  /**
1509
1530
  * Manually activate the SDK UI (bypassing triggers).
@@ -1518,15 +1539,15 @@ class G {
1518
1539
  /**
1519
1540
  * Start a UAT session with a list of quests.
1520
1541
  */
1521
- async startSession(t) {
1542
+ async startSession(e) {
1522
1543
  var s;
1523
1544
  if (this.state !== "active")
1524
1545
  throw new Error("[FirstLook] Cannot start session: SDK not active. Call activate() first.");
1525
- (s = this.debugMenu) == null || s.hide(), this.sessionId = L(), this.sessionStartTime = Date.now(), this.questManager = new R(this.events), this.questManager.loadQuests(t), this.sessionRecorder = new z(
1546
+ (s = this.debugMenu) == null || s.hide(), this.sessionId = D(), this.sessionStartTime = Date.now(), this.questManager = new E(this.events), this.questManager.loadQuests(e), this.sessionRecorder = new Q(
1526
1547
  this.config,
1527
1548
  this.events,
1528
1549
  this.fieldMasker.getCombinedSelector()
1529
- ), this.voiceRecorder = new O(this.events), this.issueReporter = new H(this.shadowRoot, this.events), this.issueReporter.start(), this.sessionRecorder.start(), this.fieldMasker.start(), this.config.recording.voice && await this.voiceRecorder.start(), this.config.security.watermark && (this.watermark = new Q(this.shadowRoot, this.config), this.watermark.show()), this.questOverlay = new N(this.shadowRoot, {
1550
+ ), this.voiceRecorder = new B(this.events), this.issueReporter = new W(this.shadowRoot, this.events), this.issueReporter.start(), this.sessionRecorder.start(), this.fieldMasker.start(), this.config.recording.voice && await this.voiceRecorder.start(), this.config.security.watermark && (this.watermark = new U(this.shadowRoot, this.config), this.watermark.show()), this.questOverlay = new P(this.shadowRoot, {
1530
1551
  onOkWithFeedback: (i) => this.handleQuestOk(i),
1531
1552
  onConcern: (i) => this.handleConcern(i),
1532
1553
  onNg: () => this.handleQuestNg(),
@@ -1536,18 +1557,18 @@ class G {
1536
1557
  onMinimize: () => {
1537
1558
  }
1538
1559
  }), this.questManager.startSession(this.sessionStartTime), this.renderCurrentQuest();
1539
- const e = this.config.recording.maxDuration;
1540
- return e > 0 && (this.maxDurationTimer = setTimeout(() => this.endSession(), e * 1e3)), this.backupTimer = setInterval(() => this.backupSession(), 3e4), this.state = "recording", this.events.emit({ type: "session:started", sessionId: this.sessionId }), this.sessionId;
1560
+ const t = this.config.recording.maxDuration;
1561
+ return t > 0 && (this.maxDurationTimer = setTimeout(() => this.endSession(), t * 1e3)), this.backupTimer = setInterval(() => this.backupSession(), 3e4), this.state = "recording", this.events.emit({ type: "session:started", sessionId: this.sessionId }), this.sessionId;
1541
1562
  }
1542
1563
  /**
1543
1564
  * Fetch quest definitions from the API and start a session.
1544
1565
  */
1545
- async startSessionFromRemote(t) {
1566
+ async startSessionFromRemote(e) {
1546
1567
  if (this.state !== "active")
1547
1568
  throw new Error("[FirstLook] Cannot start session: SDK not active. Call activate() first.");
1548
1569
  if (!this.config)
1549
1570
  throw new Error("[FirstLook] SDK not initialized.");
1550
- const e = this.config.endpoint.replace(/\/ingest-session$/, ""), s = await fetch(`${e}/export-quests?id=${encodeURIComponent(t)}`, {
1571
+ const t = this.config.endpoint.replace(/\/ingest-session$/, ""), s = await fetch(`${t}/export-quests?id=${encodeURIComponent(e)}`, {
1551
1572
  headers: { "X-API-Key": this.config.apiKey }
1552
1573
  });
1553
1574
  if (!s.ok)
@@ -1559,12 +1580,12 @@ class G {
1559
1580
  * End the current session, persist data, and trigger upload.
1560
1581
  */
1561
1582
  async endSession() {
1562
- var i, n, o, l, c, h, d, m, f, p, g;
1583
+ var i, n, o, l, a, h, d, m, f, p, g;
1563
1584
  if (this.state !== "recording" || !this.sessionId) return null;
1564
- this.maxDurationTimer && (clearTimeout(this.maxDurationTimer), this.maxDurationTimer = null), this.backupTimer && (clearInterval(this.backupTimer), this.backupTimer = null), (i = this.sessionRecorder) == null || i.stop(), await ((n = this.voiceRecorder) == null ? void 0 : n.stopAsync()), (o = this.issueReporter) == null || o.stop(), (l = this.fieldMasker) == null || l.stop(), (c = this.watermark) == null || c.hide();
1565
- const t = this.questManager.getResults();
1585
+ this.maxDurationTimer && (clearTimeout(this.maxDurationTimer), this.maxDurationTimer = null), this.backupTimer && (clearInterval(this.backupTimer), this.backupTimer = null), (i = this.sessionRecorder) == null || i.stop(), await ((n = this.voiceRecorder) == null ? void 0 : n.stopAsync()), (o = this.issueReporter) == null || o.stop(), (l = this.fieldMasker) == null || l.stop(), (a = this.watermark) == null || a.hide();
1586
+ const e = this.questManager.getResults();
1566
1587
  await Promise.allSettled(
1567
- t.map(async (b) => {
1588
+ e.map(async (b) => {
1568
1589
  if (b.voiceMemoBlob) {
1569
1590
  try {
1570
1591
  b.voiceMemoBase64 = await this.blobToBase64(b.voiceMemoBlob);
@@ -1585,29 +1606,29 @@ class G {
1585
1606
  );
1586
1607
  })
1587
1608
  );
1588
- const e = {
1609
+ const t = {
1589
1610
  sessionId: this.sessionId,
1590
1611
  projectId: this.config.projectId,
1591
1612
  userId: this.config.userId,
1592
1613
  role: this.config.role,
1593
- deviceInfo: y(),
1614
+ deviceInfo: q(),
1594
1615
  startedAt: new Date(this.sessionStartTime).toISOString(),
1595
1616
  endedAt: (/* @__PURE__ */ new Date()).toISOString(),
1596
1617
  duration: Math.floor((Date.now() - this.sessionStartTime) / 1e3),
1597
- quests: t,
1618
+ quests: e,
1598
1619
  recordings: ((h = this.sessionRecorder) == null ? void 0 : h.getSnapshots()) ?? []
1599
1620
  };
1600
- await ((d = this.storage) == null ? void 0 : d.saveSession(e));
1621
+ await ((d = this.storage) == null ? void 0 : d.saveSession(t));
1601
1622
  const s = ((m = this.issueReporter) == null ? void 0 : m.getAnnotations()) ?? [];
1602
1623
  for (const b of s)
1603
1624
  await ((f = this.storage) == null ? void 0 : f.saveAnnotation(this.sessionId, b));
1604
- return await ((p = this.storage) == null ? void 0 : p.enqueueUpload({ session: e, annotations: s })), (g = this.questOverlay) == null || g.destroy(), this.questOverlay = null, this.state = "finished", this.events.emit({ type: "session:ended", sessionId: this.sessionId }), this.flushUploadQueue(!1), e;
1625
+ return await ((p = this.storage) == null ? void 0 : p.enqueueUpload({ session: t, annotations: s })), (g = this.questOverlay) == null || g.destroy(), this.questOverlay = null, this.state = "finished", this.events.emit({ type: "session:ended", sessionId: this.sessionId }), this.flushUploadQueue(!1), t;
1605
1626
  }
1606
1627
  /**
1607
1628
  * Subscribe to SDK events.
1608
1629
  */
1609
- on(t, e) {
1610
- return this.events.on(t, e);
1630
+ on(e, t) {
1631
+ return this.events.on(e, t);
1611
1632
  }
1612
1633
  /**
1613
1634
  * Get current SDK state.
@@ -1619,26 +1640,26 @@ class G {
1619
1640
  * Completely destroy the SDK instance and clean up all resources.
1620
1641
  */
1621
1642
  destroy() {
1622
- var t, e, s, i, n, o, l, c, h, d, m, f;
1623
- this.maxDurationTimer && (clearTimeout(this.maxDurationTimer), this.maxDurationTimer = null), this.backupTimer && (clearInterval(this.backupTimer), this.backupTimer = null), (t = this.tapTrigger) == null || t.stop(), (e = this.deepLinkTrigger) == null || e.stop(), (s = this.keyboardTrigger) == null || s.stop(), C.clearPersisted(), (i = this.sessionRecorder) == null || i.stop(), (n = this.voiceRecorder) == null || n.stopAsync().catch(() => {
1624
- }), (o = this.issueReporter) == null || o.stop(), (l = this.fieldMasker) == null || l.stop(), (c = this.watermark) == null || c.hide(), (h = this.questOverlay) == null || h.destroy(), (d = this.debugMenu) == null || d.hide(), (m = this.hostElement) == null || m.remove(), (f = this.storage) == null || f.close(), this.events.removeAll(), this.config = null, this.questManager = null, this.questOverlay = null, this.sessionRecorder = null, this.voiceRecorder = null, this.issueReporter = null, this.fieldMasker = null, this.debugMenu = null, this.tapTrigger = null, this.deepLinkTrigger = null, this.keyboardTrigger = null, this.storage = null, this.hostElement = null, this.shadowRoot = null, this.sessionId = null, this.state = "idle";
1643
+ var e, t, s, i, n, o, l, a, h, d, m, f;
1644
+ this.maxDurationTimer && (clearTimeout(this.maxDurationTimer), this.maxDurationTimer = null), this.backupTimer && (clearInterval(this.backupTimer), this.backupTimer = null), (e = this.tapTrigger) == null || e.stop(), (t = this.deepLinkTrigger) == null || t.stop(), (s = this.keyboardTrigger) == null || s.stop(), C.clearPersisted(), (i = this.sessionRecorder) == null || i.stop(), (n = this.voiceRecorder) == null || n.stopAsync().catch(() => {
1645
+ }), (o = this.issueReporter) == null || o.stop(), (l = this.fieldMasker) == null || l.stop(), (a = this.watermark) == null || a.hide(), (h = this.questOverlay) == null || h.destroy(), (d = this.debugMenu) == null || d.hide(), (m = this.hostElement) == null || m.remove(), (f = this.storage) == null || f.close(), this.events.removeAll(), this.config = null, this.questManager = null, this.questOverlay = null, this.sessionRecorder = null, this.voiceRecorder = null, this.issueReporter = null, this.fieldMasker = null, this.debugMenu = null, this.tapTrigger = null, this.deepLinkTrigger = null, this.keyboardTrigger = null, this.storage = null, this.hostElement = null, this.shadowRoot = null, this.sessionId = null, this.state = "idle";
1625
1646
  }
1626
1647
  // ----------------------------------------------------------------
1627
1648
  // Private methods
1628
1649
  // ----------------------------------------------------------------
1629
1650
  createShadowHost() {
1630
- var e;
1631
- (e = document.getElementById("firstlook-sdk-root")) == null || e.remove(), this.hostElement = document.createElement("div"), this.hostElement.id = "firstlook-sdk-root", this.hostElement.style.cssText = "position:fixed;inset:0;z-index:2147483647;pointer-events:none;", document.body.appendChild(this.hostElement), this.shadowRoot = this.hostElement.attachShadow({ mode: "closed" });
1632
- const t = document.createElement("style");
1633
- t.textContent = X, this.shadowRoot.appendChild(t);
1651
+ var t;
1652
+ (t = document.getElementById("firstlook-sdk-root")) == null || t.remove(), this.hostElement = document.createElement("div"), this.hostElement.id = "firstlook-sdk-root", this.hostElement.style.cssText = "position:fixed;inset:0;z-index:2147483647;pointer-events:none;", document.body.appendChild(this.hostElement), this.shadowRoot = this.hostElement.attachShadow({ mode: "closed" });
1653
+ const e = document.createElement("style");
1654
+ e.textContent = Y, this.shadowRoot.appendChild(e);
1634
1655
  }
1635
1656
  setupTriggers() {
1636
- const t = this.config.triggers;
1637
- this.tapTrigger = new _(t.tapCount, () => this.onActivate()), this.tapTrigger.start(), t.deepLink && (this.deepLinkTrigger = new C(() => this.onActivate()), this.deepLinkTrigger.start()), t.keyboard && (this.keyboardTrigger = new W(() => this.onActivate()), this.keyboardTrigger.start()), t.customCheck && t.customCheck() && this.onActivate();
1657
+ const e = this.config.triggers;
1658
+ this.tapTrigger = new V(e.tapCount, () => this.onActivate()), this.tapTrigger.start(), e.deepLink && (this.deepLinkTrigger = new C(() => this.onActivate()), this.deepLinkTrigger.start()), e.keyboard && (this.keyboardTrigger = new S(() => this.onActivate()), this.keyboardTrigger.start()), e.customCheck && e.customCheck() && this.onActivate();
1638
1659
  }
1639
1660
  onActivate() {
1640
- var t, e, s;
1641
- this.state === "initialized" && (this.state = "active", (t = this.tapTrigger) == null || t.stop(), (e = this.deepLinkTrigger) == null || e.stop(), (s = this.keyboardTrigger) == null || s.stop(), this.events.emit({ type: "sdk:activated" }), this.debugMenu = new V(this.shadowRoot, {
1661
+ var e, t, s;
1662
+ this.state === "initialized" && (this.state = "active", (e = this.tapTrigger) == null || e.stop(), (t = this.deepLinkTrigger) == null || t.stop(), (s = this.keyboardTrigger) == null || s.stop(), this.events.emit({ type: "sdk:activated" }), this.debugMenu = new X(this.shadowRoot, {
1642
1663
  onStartSession: () => {
1643
1664
  this.events.emit({ type: "sdk:activated" });
1644
1665
  },
@@ -1651,77 +1672,77 @@ class G {
1651
1672
  }
1652
1673
  }), this.debugMenu.show());
1653
1674
  }
1654
- handleQuestOk(t) {
1675
+ handleQuestOk(e) {
1655
1676
  var i;
1656
1677
  if (!this.questManager || !this.sessionRecorder) return;
1657
- const e = this.sessionRecorder.getActionLogs(), s = (i = this.questOverlay) == null ? void 0 : i.getChecklist();
1658
- this.questManager.completeCurrentQuest(e, {
1659
- comment: t || void 0,
1678
+ const t = this.sessionRecorder.getActionLogs(), s = (i = this.questOverlay) == null ? void 0 : i.getChecklist();
1679
+ this.questManager.completeCurrentQuest(t, {
1680
+ comment: e || void 0,
1660
1681
  checklist: s
1661
1682
  }), this.renderCurrentQuest();
1662
1683
  }
1663
- handleConcern(t) {
1684
+ handleConcern(e) {
1664
1685
  var i;
1665
1686
  if (!this.questManager || !this.sessionRecorder) return;
1666
- const e = this.sessionRecorder.getActionLogs(), s = (i = this.questOverlay) == null ? void 0 : i.getChecklist();
1667
- this.questManager.completeCurrentQuest(e, {
1668
- comment: t,
1687
+ const t = this.sessionRecorder.getActionLogs(), s = (i = this.questOverlay) == null ? void 0 : i.getChecklist();
1688
+ this.questManager.completeCurrentQuest(t, {
1689
+ comment: e,
1669
1690
  concern: !0,
1670
1691
  checklist: s
1671
1692
  }), this.renderCurrentQuest();
1672
1693
  }
1673
1694
  handleQuestNg() {
1674
1695
  if (!this.questManager || !this.questOverlay) return;
1675
- const t = this.questManager.getCurrentQuest();
1676
- t && this.questOverlay.renderFeedbackModal(t.title, "ng");
1696
+ const e = this.questManager.getCurrentQuest();
1697
+ e && this.questOverlay.renderFeedbackModal(e.title, "ng");
1677
1698
  }
1678
- handleNgFeedbackSubmit(t) {
1699
+ handleNgFeedbackSubmit(e) {
1679
1700
  var i;
1680
1701
  if (!this.questManager || !this.sessionRecorder) return;
1681
- const e = this.sessionRecorder.getActionLogs(), s = (i = this.questOverlay) == null ? void 0 : i.getChecklist();
1682
- this.questManager.failCurrentQuest(e, t || void 0, void 0, s), this.renderCurrentQuest();
1702
+ const t = this.sessionRecorder.getActionLogs(), s = (i = this.questOverlay) == null ? void 0 : i.getChecklist();
1703
+ this.questManager.failCurrentQuest(t, e || void 0, void 0, s), this.renderCurrentQuest();
1683
1704
  }
1684
- handleMemo(t) {
1685
- if (!this.questManager || !t) return;
1686
- const e = {
1687
- comment: t,
1705
+ handleMemo(e) {
1706
+ if (!this.questManager || !e) return;
1707
+ const t = {
1708
+ comment: e,
1688
1709
  timestamp: Date.now(),
1689
1710
  relativeTime: Date.now() - this.sessionStartTime
1690
1711
  };
1691
- this.questManager.addFeedback(e);
1712
+ this.questManager.addFeedback(t);
1692
1713
  }
1693
1714
  renderCurrentQuest() {
1694
1715
  var s;
1695
1716
  if (!this.questManager || !this.questOverlay) return;
1696
- const t = this.questManager.getStatus();
1697
- if (t.isBlocked) {
1717
+ const e = this.questManager.getStatus();
1718
+ if (e.isBlocked) {
1698
1719
  const n = this.questManager.getResults().find((l) => l.status === "FAILED"), o = n ? n.questId : "Unknown";
1699
1720
  this.questOverlay.renderBlocked(o);
1700
1721
  return;
1701
1722
  }
1702
- if (t.isFinished) {
1703
- this.questOverlay.renderSummary(t.completed, t.failed, t.total);
1723
+ if (e.isFinished) {
1724
+ this.questOverlay.renderSummary(e.completed, e.failed, e.total);
1704
1725
  return;
1705
1726
  }
1706
- const e = this.questManager.getCurrentQuest();
1707
- e && this.questOverlay.renderQuest(
1708
- e,
1727
+ const t = this.questManager.getCurrentQuest();
1728
+ t && this.questOverlay.renderQuest(
1729
+ t,
1709
1730
  this.questManager.getQuestStatuses(),
1710
1731
  ((s = this.voiceRecorder) == null ? void 0 : s.recording) ?? !1
1711
1732
  );
1712
1733
  }
1713
- async flushUploadQueue(t) {
1734
+ async flushUploadQueue(e) {
1714
1735
  if (!(!this.storage || !this.config || this.isFlushing)) {
1715
1736
  this.isFlushing = !0;
1716
1737
  try {
1717
- if (t) {
1738
+ if (e) {
1718
1739
  const s = navigator.connection;
1719
1740
  if (s && s.type && s.type !== "wifi" && s.effectiveType !== "4g")
1720
1741
  return;
1721
1742
  }
1722
- const e = await this.storage.getPendingUploads();
1723
- for (const s of e) {
1724
- if (s.attempts >= Y) {
1743
+ const t = await this.storage.getPendingUploads();
1744
+ for (const s of t) {
1745
+ if (s.attempts >= G) {
1725
1746
  await this.storage.removeFromQueue(s.key);
1726
1747
  continue;
1727
1748
  }
@@ -1749,32 +1770,32 @@ class G {
1749
1770
  }
1750
1771
  }
1751
1772
  async backupSession() {
1752
- var t;
1773
+ var e;
1753
1774
  if (!(!this.storage || !this.sessionId || !this.config || !this.sessionRecorder))
1754
1775
  try {
1755
- const e = {
1776
+ const t = {
1756
1777
  sessionId: this.sessionId,
1757
1778
  projectId: this.config.projectId,
1758
1779
  userId: this.config.userId,
1759
1780
  role: this.config.role,
1760
- deviceInfo: y(),
1781
+ deviceInfo: q(),
1761
1782
  startedAt: new Date(this.sessionStartTime).toISOString(),
1762
1783
  duration: Math.floor((Date.now() - this.sessionStartTime) / 1e3),
1763
- quests: ((t = this.questManager) == null ? void 0 : t.getResults()) ?? [],
1784
+ quests: ((e = this.questManager) == null ? void 0 : e.getResults()) ?? [],
1764
1785
  recordings: this.sessionRecorder.getSnapshots()
1765
1786
  };
1766
- await this.storage.saveSession(e);
1787
+ await this.storage.saveSession(t);
1767
1788
  } catch {
1768
1789
  }
1769
1790
  }
1770
- blobToBase64(t) {
1771
- return new Promise((e, s) => {
1791
+ blobToBase64(e) {
1792
+ return new Promise((t, s) => {
1772
1793
  const i = new FileReader();
1773
- i.onloadend = () => e(i.result), i.onerror = () => s(i.error), i.readAsDataURL(t);
1794
+ i.onloadend = () => t(i.result), i.onerror = () => s(i.error), i.readAsDataURL(e);
1774
1795
  });
1775
1796
  }
1776
1797
  }
1777
1798
  export {
1778
- G as FirstLookSDK
1799
+ J as FirstLookSDK
1779
1800
  };
1780
1801
  //# sourceMappingURL=firstlook.es.js.map