@firstlook-uat/sdk 0.4.1 → 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]));
221
- const m = r("ul", { className: "fl-checklist" });
220
+ p(), h.appendChild(f), a.preamble && h.appendChild(r("p", { className: "fl-quest-description" }, [a.preamble]));
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), m.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
- h.appendChild(m);
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" }, [
@@ -251,12 +251,12 @@ class N {
251
251
  "REC"
252
252
  ])
253
253
  );
254
- const g = r("span", { className: "fl-status-timer" }, ["00:00"]);
255
- d.appendChild(g), o.appendChild(d), this.root.appendChild(o), this.startTimer(g), this.root.onclick = () => {
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(g));
254
+ const m = r("span", { className: "fl-status-timer" }, ["00:00"]);
255
+ d.appendChild(m), o.appendChild(d), this.root.appendChild(o), this.startTimer(m), this.root.onclick = () => {
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,74 +272,73 @@ 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 g = "送信", 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(""), s.remove();
291
+ t === "ng" ? this.callbacks.onNgWithFeedback("") : t === "ok" ? this.callbacks.onOkWithFeedback("") : t === "concern" && this.callbacks.onConcern(""), s.remove();
292
292
  }),
293
- this.createButton("fl-btn fl-btn-finish", g, () => {
294
- const m = d.value.trim();
295
- if (e === "ng")
296
- this.callbacks.onNgWithFeedback(m);
297
- else if (e === "ok")
298
- this.callbacks.onOkWithFeedback(m);
299
- else if (e === "concern") {
300
- if (!m) return;
301
- this.callbacks.onConcern(m);
302
- } else {
303
- if (!m) {
293
+ this.createButton("fl-btn fl-btn-finish", m, () => {
294
+ const g = d.value.trim();
295
+ if (t === "ng")
296
+ this.callbacks.onNgWithFeedback(g);
297
+ else if (t === "ok")
298
+ this.callbacks.onOkWithFeedback(g);
299
+ else if (t === "concern")
300
+ this.callbacks.onConcern(g);
301
+ else {
302
+ if (!g) {
304
303
  s.remove();
305
304
  return;
306
305
  }
307
- this.callbacks.onMemo(m);
306
+ this.callbacks.onMemo(g);
308
307
  }
309
308
  s.remove();
310
309
  })
311
310
  ]);
312
- 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();
313
312
  }
314
- renderSummary(t, e, s) {
313
+ renderSummary(e, t, s) {
315
314
  this.stopTimer(), this.root.className = "fl-quest-overlay", this.root.innerHTML = "";
316
315
  const i = r("div", { className: "fl-summary" }, [
317
- r("div", { className: "fl-summary-icon" }, [t === s ? "🎉" : "📋"]),
316
+ r("div", { className: "fl-summary-icon" }, [e === s ? "🎉" : "📋"]),
318
317
  r("div", { className: "fl-summary-title" }, [
319
- t === s ? "All Quests Complete!" : "Session Complete"
318
+ e === s ? "All Quests Complete!" : "Session Complete"
320
319
  ]),
321
320
  r("div", { className: "fl-summary-subtitle" }, [
322
- `${t + e} of ${s} quests attempted`
321
+ `${e + t} of ${s} quests attempted`
323
322
  ]),
324
323
  r("div", { className: "fl-summary-stats" }, [
325
- this.createStat(t.toString(), "Passed", "fl-ok"),
326
- this.createStat(e.toString(), "Failed", "fl-ng")
324
+ this.createStat(e.toString(), "Passed", "fl-ok"),
325
+ this.createStat(t.toString(), "Failed", "fl-ng")
327
326
  ]),
328
327
  this.createButton("fl-btn fl-btn-finish", "Finish & Upload", this.callbacks.onFinish)
329
328
  ]);
330
329
  this.root.appendChild(i);
331
330
  }
332
- renderBlocked(t) {
331
+ renderBlocked(e) {
333
332
  this.stopTimer(), this.root.className = "fl-quest-overlay", this.root.innerHTML = "";
334
- const e = r("div", { className: "fl-summary" }, [
333
+ const t = r("div", { className: "fl-summary" }, [
335
334
  r("div", { className: "fl-summary-icon" }, ["🛑"]),
336
335
  r("div", { className: "fl-summary-title" }, ["Blocked"]),
337
336
  r("div", { className: "fl-summary-subtitle" }, [
338
- `Quest "${t}" is blocking. Session halted.`
337
+ `Quest "${e}" is blocking. Session halted.`
339
338
  ]),
340
339
  this.createButton("fl-btn fl-btn-finish", "Finish & Upload", this.callbacks.onFinish)
341
340
  ]);
342
- this.root.appendChild(e);
341
+ this.root.appendChild(t);
343
342
  }
344
343
  getChecklist() {
345
344
  return this.checklist.length > 0 ? [...this.checklist] : void 0;
@@ -348,39 +347,39 @@ class N {
348
347
  this.stopTimer(), this.root.remove();
349
348
  }
350
349
  createMinimizeBtn() {
351
- const t = r("button", { className: "fl-quest-minimize-btn" }, ["−"]);
352
- return t.onclick = (e) => {
353
- 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 = "";
354
353
  const s = r("span", { className: "fl-minimize-icon" }, ["🔍"]);
355
354
  this.root.appendChild(s), this.callbacks.onMinimize();
356
- }, t;
355
+ }, e;
357
356
  }
358
- createButton(t, e, s) {
359
- const i = r("button", { className: t });
360
- 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) => {
361
360
  n.stopPropagation(), s();
362
361
  }, i;
363
362
  }
364
- createStat(t, e, s) {
363
+ createStat(e, t, s) {
365
364
  return r("div", { className: "fl-stat" }, [
366
- r("div", { className: `fl-stat-value ${s}` }, [t]),
367
- r("div", { className: "fl-stat-label" }, [e])
365
+ r("div", { className: `fl-stat-value ${s}` }, [e]),
366
+ r("div", { className: "fl-stat-label" }, [t])
368
367
  ]);
369
368
  }
370
- startTimer(t) {
369
+ startTimer(e) {
371
370
  this.stopTimer(), this.startTime || (this.startTime = Date.now()), this.timerInterval = setInterval(() => {
372
- const e = Math.floor((Date.now() - this.startTime) / 1e3);
373
- t.textContent = A(e);
371
+ const t = Math.floor((Date.now() - this.startTime) / 1e3);
372
+ e.textContent = N(t);
374
373
  }, 1e3);
375
374
  }
376
375
  stopTimer() {
377
376
  this.timerInterval && (clearInterval(this.timerInterval), this.timerInterval = null);
378
377
  }
379
378
  }
380
- const F = 100, P = 2 * 1024 * 1024;
381
- class z {
382
- constructor(t, e, s) {
383
- 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);
384
383
  }
385
384
  start() {
386
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(
@@ -400,17 +399,17 @@ class z {
400
399
  getElapsedMs() {
401
400
  return this.running ? Date.now() - this.startTime : 0;
402
401
  }
403
- addLog(t) {
402
+ addLog(e) {
404
403
  this.actionLogs.push({
405
- ...t,
404
+ ...e,
406
405
  timestamp: Date.now() - this.startTime
407
406
  });
408
407
  }
409
- onClick(t) {
410
- const e = t.target;
408
+ onClick(e) {
409
+ const t = e.target;
411
410
  this.addLog({
412
411
  type: "click",
413
- target: x(e)
412
+ target: w(t)
414
413
  });
415
414
  }
416
415
  onScroll() {
@@ -419,34 +418,34 @@ class z {
419
418
  value: `${window.scrollX},${window.scrollY}`
420
419
  });
421
420
  }
422
- onInput(t) {
423
- const e = t.target;
424
- if (e.hasAttribute("data-fl-masked"))
425
- 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]" });
426
425
  else {
427
- const s = e.value;
426
+ const s = t.value;
428
427
  this.addLog({
429
428
  type: "input",
430
- target: x(e),
429
+ target: w(t),
431
430
  value: s == null ? void 0 : s.slice(0, 100)
432
431
  });
433
432
  }
434
433
  }
435
434
  captureSnapshot() {
436
435
  try {
437
- const t = document.documentElement.cloneNode(!0);
436
+ const e = document.documentElement.cloneNode(!0);
438
437
  if (this.maskSelector) {
439
- const n = t.querySelectorAll(this.maskSelector);
438
+ const n = e.querySelectorAll(this.maskSelector);
440
439
  for (const o of n)
441
440
  (o instanceof HTMLInputElement || o instanceof HTMLTextAreaElement) && (o.value = "***"), o.textContent = "***";
442
441
  }
443
- const e = t.querySelectorAll("script");
444
- for (const n of e) n.remove();
445
- 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");
446
445
  s == null || s.remove();
447
- const i = t.outerHTML;
448
- if (i.length > P) return;
449
- 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({
450
449
  type: "dom-snapshot",
451
450
  timestamp: Date.now() - this.startTime,
452
451
  data: i
@@ -454,22 +453,22 @@ class z {
454
453
  } catch {
455
454
  }
456
455
  }
457
- throttle(t, e) {
456
+ throttle(e, t) {
458
457
  let s = 0;
459
458
  return (...i) => {
460
459
  const n = Date.now();
461
- n - s >= e && (s = n, t(...i));
460
+ n - s >= t && (s = n, e(...i));
462
461
  };
463
462
  }
464
463
  }
465
- function x(a) {
464
+ function w(c) {
466
465
  var n;
467
- 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)) || "";
468
- 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}"` : ""}`;
469
468
  }
470
- class O {
471
- constructor(t) {
472
- 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;
473
472
  }
474
473
  get recording() {
475
474
  return this._recording;
@@ -478,57 +477,57 @@ class O {
478
477
  if (!this._recording)
479
478
  try {
480
479
  this.stream = await navigator.mediaDevices.getUserMedia({ audio: !0 });
481
- const t = this.getSupportedMimeType(), e = t ? { mimeType: t } : {};
482
- 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) => {
483
482
  s.data.size > 0 && this.chunks.push(s.data);
484
483
  }, this.mediaRecorder.start(1e3), this._recording = !0;
485
- } catch (t) {
486
- console.warn("[FirstLook] Voice recording unavailable:", t), this.events.emit({
484
+ } catch (e) {
485
+ console.warn("[FirstLook] Voice recording unavailable:", e), this.events.emit({
487
486
  type: "error",
488
- error: new Error(`Voice recording failed: ${t.message}`)
487
+ error: new Error(`Voice recording failed: ${e.message}`)
489
488
  });
490
489
  }
491
490
  }
492
491
  async stopAsync() {
493
- return !this._recording || !this.mediaRecorder ? null : new Promise((t) => {
492
+ return !this._recording || !this.mediaRecorder ? null : new Promise((e) => {
494
493
  this.mediaRecorder.onstop = () => {
495
494
  var s;
496
- const e = this.chunks.length > 0 ? new Blob(this.chunks, { type: ((s = this.mediaRecorder) == null ? void 0 : s.mimeType) || "audio/webm" }) : null;
497
- 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);
498
497
  }, this.mediaRecorder.stop();
499
498
  });
500
499
  }
501
- async captureSnippet(t = 1e4) {
502
- return await this.start(), new Promise((e) => {
500
+ async captureSnippet(e = 1e4) {
501
+ return await this.start(), new Promise((t) => {
503
502
  setTimeout(async () => {
504
503
  const s = await this.stopAsync();
505
- e(s);
506
- }, t);
504
+ t(s);
505
+ }, e);
507
506
  });
508
507
  }
509
508
  cleanup() {
510
509
  if (this._recording = !1, this.stream) {
511
- for (const t of this.stream.getTracks())
512
- t.stop();
510
+ for (const e of this.stream.getTracks())
511
+ e.stop();
513
512
  this.stream = null;
514
513
  }
515
514
  this.mediaRecorder = null, this.chunks = [];
516
515
  }
517
516
  getSupportedMimeType() {
518
- const t = [
517
+ const e = [
519
518
  "audio/webm;codecs=opus",
520
519
  "audio/webm",
521
520
  "audio/ogg;codecs=opus",
522
521
  "audio/mp4"
523
522
  ];
524
- for (const e of t)
525
- 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;
526
525
  return "";
527
526
  }
528
527
  }
529
- class Q {
530
- constructor(t, e) {
531
- 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;
532
531
  }
533
532
  show() {
534
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));
@@ -539,8 +538,8 @@ class Q {
539
538
  async fetchIp() {
540
539
  if (!this.cachedIp)
541
540
  try {
542
- const t = await fetch("https://api.ipify.org?format=text");
543
- 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());
544
543
  } catch {
545
544
  this.cachedIp = "N/A";
546
545
  }
@@ -548,17 +547,17 @@ class Q {
548
547
  renderTiles() {
549
548
  if (!this.container) return;
550
549
  this.container.innerHTML = "";
551
- 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;
552
- 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++)
553
552
  for (let h = 0; h < o; h++) {
554
553
  const d = document.createElement("span");
555
- 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);
556
555
  }
557
556
  }
558
557
  }
559
- class B {
560
- constructor(t) {
561
- 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();
562
561
  }
563
562
  start() {
564
563
  this.scanAndMark(), this.observer = new MutationObserver(() => this.scanAndMark()), this.observer.observe(document.body, {
@@ -569,24 +568,24 @@ class B {
569
568
  });
570
569
  }
571
570
  stop() {
572
- var t;
573
- (t = this.observer) == null || t.disconnect(), this.observer = null;
574
- for (const e of this.maskedElements)
575
- 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");
576
575
  this.maskedElements.clear();
577
576
  }
578
- isMasked(t) {
579
- return t.hasAttribute("data-fl-masked");
577
+ isMasked(e) {
578
+ return e.hasAttribute("data-fl-masked");
580
579
  }
581
580
  getCombinedSelector() {
582
581
  return this.selectors.join(", ");
583
582
  }
584
583
  scanAndMark() {
585
- const t = this.getCombinedSelector();
586
- if (t)
584
+ const e = this.getCombinedSelector();
585
+ if (e)
587
586
  try {
588
- const e = document.querySelectorAll(t);
589
- for (const s of e)
587
+ const t = document.querySelectorAll(e);
588
+ for (const s of t)
590
589
  this.maskedElements.has(s) || (s.setAttribute("data-fl-masked", "true"), this.maskedElements.add(s));
591
590
  for (const s of this.maskedElements)
592
591
  document.contains(s) || this.maskedElements.delete(s);
@@ -594,93 +593,93 @@ class B {
594
593
  }
595
594
  }
596
595
  }
597
- const $ = "firstlook_uat", U = 1, u = {
596
+ const j = "firstlook_uat", K = 1, u = {
598
597
  sessions: "sessions",
599
598
  recordings: "recordings",
600
599
  annotations: "annotations",
601
600
  uploadQueue: "upload_queue"
602
601
  };
603
- class j {
602
+ class H {
604
603
  constructor() {
605
604
  this.db = null;
606
605
  }
607
606
  async open() {
608
607
  if (!this.db)
609
- return new Promise((t, e) => {
610
- const s = indexedDB.open($, U);
608
+ return new Promise((e, t) => {
609
+ const s = indexedDB.open(j, K);
611
610
  s.onupgradeneeded = () => {
612
611
  const i = s.result;
613
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 });
614
613
  }, s.onsuccess = () => {
615
- this.db = s.result, t();
616
- }, s.onerror = () => e(s.error);
614
+ this.db = s.result, e();
615
+ }, s.onerror = () => t(s.error);
617
616
  });
618
617
  }
619
- async saveSession(t) {
620
- await this.put(u.sessions, t);
618
+ async saveSession(e) {
619
+ await this.put(u.sessions, e);
621
620
  }
622
- async getSession(t) {
623
- return this.get(u.sessions, t);
621
+ async getSession(e) {
622
+ return this.get(u.sessions, e);
624
623
  }
625
- async saveRecording(t, e) {
626
- await this.put(u.recordings, { sessionId: t, ...e });
624
+ async saveRecording(e, t) {
625
+ await this.put(u.recordings, { sessionId: e, ...t });
627
626
  }
628
- async saveAnnotation(t, e) {
629
- await this.put(u.annotations, { sessionId: t, ...e });
627
+ async saveAnnotation(e, t) {
628
+ await this.put(u.annotations, { sessionId: e, ...t });
630
629
  }
631
- async getAnnotations(t) {
632
- return this.getAllByIndex(u.annotations, "sessionId", t);
630
+ async getAnnotations(e) {
631
+ return this.getAllByIndex(u.annotations, "sessionId", e);
633
632
  }
634
- async enqueueUpload(t) {
633
+ async enqueueUpload(e) {
635
634
  await this.put(u.uploadQueue, {
636
- payload: t,
635
+ payload: e,
637
636
  createdAt: Date.now(),
638
637
  attempts: 0
639
638
  });
640
639
  }
641
640
  async getPendingUploads() {
642
- const t = this.ensureDb();
643
- return new Promise((e, s) => {
644
- 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 = [];
645
644
  o.onsuccess = () => {
646
- const c = o.result;
647
- c ? (l.push({
648
- key: c.key,
649
- payload: c.value.payload,
650
- attempts: c.value.attempts,
651
- lastAttemptAt: c.value.lastAttemptAt
652
- }), 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);
653
652
  }, o.onerror = () => s(o.error);
654
653
  });
655
654
  }
656
- async removeFromQueue(t) {
657
- const e = this.ensureDb();
655
+ async removeFromQueue(e) {
656
+ const t = this.ensureDb();
658
657
  return new Promise((s, i) => {
659
- 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);
660
659
  o.onsuccess = () => s(), o.onerror = () => i(o.error);
661
660
  });
662
661
  }
663
- async incrementAttempts(t) {
664
- const e = this.ensureDb();
662
+ async incrementAttempts(e) {
663
+ const t = this.ensureDb();
665
664
  return new Promise((s, i) => {
666
- 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);
667
666
  l.onsuccess = () => {
668
- const c = l.result;
669
- 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));
670
669
  }, n.oncomplete = () => s(), n.onerror = () => i(n.error);
671
670
  });
672
671
  }
673
- async clearSession(t) {
672
+ async clearSession(e) {
674
673
  const s = this.ensureDb().transaction(
675
674
  [u.sessions, u.recordings, u.annotations],
676
675
  "readwrite"
677
676
  );
678
- s.objectStore(u.sessions).delete(t);
677
+ s.objectStore(u.sessions).delete(e);
679
678
  for (const i of [u.recordings, u.annotations]) {
680
- const l = s.objectStore(i).index("sessionId").openCursor(IDBKeyRange.only(t));
679
+ const l = s.objectStore(i).index("sessionId").openCursor(IDBKeyRange.only(e));
681
680
  l.onsuccess = () => {
682
- const c = l.result;
683
- c && (c.delete(), c.continue());
681
+ const a = l.result;
682
+ a && (a.delete(), a.continue());
684
683
  };
685
684
  }
686
685
  return new Promise((i, n) => {
@@ -688,69 +687,69 @@ class j {
688
687
  });
689
688
  }
690
689
  close() {
691
- var t;
692
- (t = this.db) == null || t.close(), this.db = null;
690
+ var e;
691
+ (e = this.db) == null || e.close(), this.db = null;
693
692
  }
694
693
  ensureDb() {
695
694
  if (!this.db) throw new Error("[FirstLook] Storage not opened. Call open() first.");
696
695
  return this.db;
697
696
  }
698
- async put(t, e) {
697
+ async put(e, t) {
699
698
  const s = this.ensureDb();
700
699
  return new Promise((i, n) => {
701
- const o = s.transaction(t, "readwrite");
702
- 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);
703
702
  });
704
703
  }
705
- async get(t, e) {
704
+ async get(e, t) {
706
705
  const s = this.ensureDb();
707
706
  return new Promise((i, n) => {
708
- const l = s.transaction(t, "readonly").objectStore(t).get(e);
707
+ const l = s.transaction(e, "readonly").objectStore(e).get(t);
709
708
  l.onsuccess = () => i(l.result), l.onerror = () => n(l.error);
710
709
  });
711
710
  }
712
- async getAllByIndex(t, e, s) {
711
+ async getAllByIndex(e, t, s) {
713
712
  const i = this.ensureDb();
714
713
  return new Promise((n, o) => {
715
- 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);
716
715
  h.onsuccess = () => n(h.result), h.onerror = () => o(h.error);
717
716
  });
718
717
  }
719
718
  }
720
- const S = ["#e17055", "#6c5ce7", "#00b894", "#fdcb6e", "#ffffff"];
721
- class K {
722
- constructor(t) {
723
- 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 = "";
724
723
  }
725
724
  async open() {
726
- return this.screenshotDataUrl = await this.captureScreenshot(), new Promise((t) => {
725
+ return this.screenshotDataUrl = await this.captureScreenshot(), new Promise((e) => {
727
726
  this.overlay = r("div", { className: "fl-annotation-overlay" });
728
- const e = r("div", { className: "fl-annotation-canvas-wrap" });
729
- 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);
730
729
  const s = r("input", {
731
730
  className: "fl-annotation-comment",
732
731
  type: "text",
733
732
  placeholder: "Add a comment..."
734
733
  }), i = r("div", { className: "fl-color-picker" });
735
- for (const c of S) {
736
- const h = r("div", { className: `fl-color-swatch ${c === this.selectedColor ? "fl-selected" : ""}` });
737
- h.style.background = c, h.onclick = () => {
738
- 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");
739
738
  }, i.appendChild(h);
740
739
  }
741
740
  const n = r("button", { className: "fl-btn fl-btn-ok" }, ["Submit"]);
742
741
  n.onclick = () => {
743
- const c = {
742
+ const a = {
744
743
  screenshotDataUrl: this.getAnnotatedImage(),
745
744
  drawings: [...this.paths],
746
745
  comment: s.value,
747
746
  timestamp: Date.now()
748
747
  };
749
- this.close(), t(c);
748
+ this.close(), e(a);
750
749
  };
751
750
  const o = r("button", { className: "fl-btn fl-btn-ng" }, ["Cancel"]);
752
751
  o.onclick = () => {
753
- this.close(), t(null);
752
+ this.close(), e(null);
754
753
  };
755
754
  const l = r("div", { className: "fl-annotation-toolbar" }, [
756
755
  i,
@@ -762,12 +761,12 @@ class K {
762
761
  });
763
762
  }
764
763
  close() {
765
- var t;
766
- (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 = [];
767
766
  }
768
767
  async captureScreenshot() {
769
768
  try {
770
- 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");
771
770
  i == null || i.remove();
772
771
  const n = s.querySelectorAll('[data-fl-masked], input[type="password"]');
773
772
  for (const p of n)
@@ -778,47 +777,47 @@ class K {
778
777
  const p = window.getComputedStyle(document.body);
779
778
  o.style.backgroundColor = p.backgroundColor, o.style.color = p.color, o.style.fontFamily = p.fontFamily, o.style.margin = "0", o.style.overflow = "hidden";
780
779
  }
781
- 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}">
782
781
  <foreignObject width="100%" height="100%">
783
782
  ${l}
784
783
  </foreignObject>
785
- </svg>`, h = new Blob([c], { type: "image/svg+xml;charset=utf-8" }), d = URL.createObjectURL(h), g = document.createElement("canvas");
786
- g.width = t * window.devicePixelRatio, g.height = e * window.devicePixelRatio;
787
- const f = g.getContext("2d");
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
+ const f = m.getContext("2d");
788
787
  return f.scale(window.devicePixelRatio, window.devicePixelRatio), new Promise((p) => {
789
- const m = new Image();
790
- m.onload = () => {
791
- f.drawImage(m, 0, 0, t, e), URL.revokeObjectURL(d), p(g.toDataURL("image/png"));
792
- }, m.onerror = () => {
793
- URL.revokeObjectURL(d), p(this.captureScreenshotFallback(t, e));
794
- }, m.src = d;
788
+ const g = new Image();
789
+ g.onload = () => {
790
+ f.drawImage(g, 0, 0, e, t), URL.revokeObjectURL(d), p(m.toDataURL("image/png"));
791
+ }, g.onerror = () => {
792
+ URL.revokeObjectURL(d), p(this.captureScreenshotFallback(e, t));
793
+ }, g.src = d;
795
794
  });
796
795
  } catch {
797
796
  return this.captureScreenshotFallback(window.innerWidth, window.innerHeight);
798
797
  }
799
798
  }
800
- captureScreenshotFallback(t, e) {
799
+ captureScreenshotFallback(e, t) {
801
800
  const s = document.createElement("canvas");
802
- s.width = t, s.height = e;
801
+ s.width = e, s.height = t;
803
802
  const i = s.getContext("2d"), n = window.getComputedStyle(document.body);
804
- 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");
805
804
  }
806
805
  initCanvas() {
807
806
  if (!this.canvas) return;
808
- const t = new Image();
809
- t.onload = () => {
810
- const e = window.innerWidth * 0.9, s = window.innerHeight * 0.7, i = Math.min(e / t.width, s / t.height, 1);
811
- 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));
812
- }, 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;
813
812
  }
814
- onDrawStart(t) {
813
+ onDrawStart(e) {
815
814
  this.drawing = !0;
816
- const e = this.canvas.getBoundingClientRect();
817
- 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 }];
818
817
  }
819
- onDrawMove(t) {
818
+ onDrawMove(e) {
820
819
  if (!this.drawing || !this.ctx) return;
821
- 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 };
822
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) {
823
822
  const i = this.currentPath[this.currentPath.length - 2];
824
823
  this.ctx.beginPath(), this.ctx.moveTo(i.x, i.y), this.ctx.lineTo(s.x, s.y), this.ctx.stroke();
@@ -832,15 +831,15 @@ class K {
832
831
  }), this.drawing = !1, this.currentPath = [];
833
832
  }
834
833
  getAnnotatedImage() {
835
- var t;
836
- 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;
837
836
  }
838
837
  }
839
- class H {
840
- constructor(t, e) {
841
- 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) => {
842
841
  s.ctrlKey && s.shiftKey && s.key === "R" && (s.preventDefault(), this.trigger());
843
- }, this.annotationCanvas = new K(t);
842
+ }, this.annotationCanvas = new _(e);
844
843
  }
845
844
  start() {
846
845
  document.addEventListener("keydown", this.onKeydown);
@@ -855,17 +854,17 @@ class H {
855
854
  if (!this.active) {
856
855
  this.active = !0;
857
856
  try {
858
- const t = await this.annotationCanvas.open();
859
- 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" }));
860
859
  } finally {
861
860
  this.active = !1;
862
861
  }
863
862
  }
864
863
  }
865
864
  }
866
- class _ {
867
- constructor(t, e) {
868
- 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;
869
868
  }
870
869
  start() {
871
870
  this.handler = this.onTap.bind(this), document.addEventListener("pointerdown", this.handler, { passive: !0 });
@@ -873,17 +872,17 @@ class _ {
873
872
  stop() {
874
873
  this.handler && (document.removeEventListener("pointerdown", this.handler), this.handler = null), this.reset();
875
874
  }
876
- onTap(t) {
875
+ onTap(e) {
877
876
  this.tapCount++, this.tapTimer && clearTimeout(this.tapTimer), this.tapCount >= this.requiredTaps ? (this.reset(), this.onActivate()) : this.tapTimer = setTimeout(() => this.reset(), 800);
878
877
  }
879
878
  reset() {
880
879
  this.tapCount = 0, this.tapTimer && (clearTimeout(this.tapTimer), this.tapTimer = null);
881
880
  }
882
881
  }
883
- const w = "firstlook:uat-active";
882
+ const y = "firstlook:uat-active";
884
883
  class C {
885
- constructor(t) {
886
- this.onActivate = t, this.handlers = [];
884
+ constructor(e) {
885
+ this.onActivate = e, this.handlers = [];
887
886
  }
888
887
  start() {
889
888
  if (this.checkUrl()) {
@@ -894,29 +893,29 @@ class C {
894
893
  this.onActivate();
895
894
  return;
896
895
  }
897
- const t = () => {
896
+ const e = () => {
898
897
  this.checkUrl() && (this.persist(), this.onActivate());
899
898
  };
900
- 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]);
901
900
  }
902
901
  stop() {
903
- for (const [t, e] of this.handlers)
904
- window.removeEventListener(t, e);
902
+ for (const [e, t] of this.handlers)
903
+ window.removeEventListener(e, t);
905
904
  this.handlers = [];
906
905
  }
907
906
  static clearPersisted() {
908
907
  try {
909
- sessionStorage.removeItem(w);
908
+ sessionStorage.removeItem(y);
910
909
  } catch {
911
910
  }
912
911
  }
913
912
  checkUrl() {
914
- const t = new URLSearchParams(window.location.search);
915
- 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")
916
915
  return !0;
917
- const e = window.location.hash, s = e.indexOf("?");
916
+ const t = window.location.hash, s = t.indexOf("?");
918
917
  if (s !== -1) {
919
- const i = new URLSearchParams(e.substring(s));
918
+ const i = new URLSearchParams(t.substring(s));
920
919
  if (i.has("firstlook") || i.has("uat-mode") || i.get("uat") === "1")
921
920
  return !0;
922
921
  }
@@ -924,69 +923,90 @@ class C {
924
923
  }
925
924
  persist() {
926
925
  try {
927
- sessionStorage.setItem(w, "1");
926
+ sessionStorage.setItem(y, "1");
928
927
  } catch {
929
928
  }
930
929
  }
931
930
  hasPersisted() {
932
931
  try {
933
- return sessionStorage.getItem(w) === "1";
932
+ return sessionStorage.getItem(y) === "1";
934
933
  } catch {
935
934
  return !1;
936
935
  }
937
936
  }
938
937
  }
939
- class W {
940
- constructor(t) {
941
- 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;
942
941
  }
943
942
  start() {
944
- this.handler = (t) => {
945
- 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
+ }
946
955
  }, window.addEventListener("keydown", this.handler);
947
956
  }
948
957
  stop() {
949
- 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);
950
959
  }
951
- }
952
- class V {
953
- constructor(t, e) {
954
- 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;
955
975
  }
956
976
  show() {
957
977
  if (this.root) return;
958
978
  this.root = r("div", { className: "fl-debug-menu" }), this.root.style.pointerEvents = "auto";
959
- for (const e of ["click", "mousedown", "mouseup", "pointerdown", "pointerup", "touchstart", "touchend"])
960
- this.root.addEventListener(e, (s) => s.stopPropagation());
961
- 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 = [
962
982
  { icon: "▶", label: "Start Session", action: this.callbacks.onStartSession },
963
983
  { icon: "📸", label: "Report Issue", action: this.callbacks.onReportIssue },
964
984
  { icon: "✖", label: "Close SDK", action: this.callbacks.onClose }
965
985
  ];
966
- for (const e of t) {
986
+ for (const t of e) {
967
987
  const s = r("button", { className: "fl-debug-menu-item" }, [
968
- r("span", { className: "fl-debug-menu-item-icon" }, [e.icon]),
969
- e.label
988
+ r("span", { className: "fl-debug-menu-item-icon" }, [t.icon]),
989
+ t.label
970
990
  ]);
971
991
  s.onclick = (i) => {
972
- i.stopPropagation(), this.hide(), e.action();
992
+ i.stopPropagation(), this.hide(), t.action();
973
993
  }, this.root.appendChild(s);
974
994
  }
975
995
  this.shadowRoot.appendChild(this.root), setTimeout(() => {
976
- this.outsideClickHandler = (e) => {
977
- this.root && !this.root.contains(e.target) && this.hide();
996
+ this.outsideClickHandler = (t) => {
997
+ this.root && !this.root.contains(t.target) && this.hide();
978
998
  }, document.addEventListener("click", this.outsideClickHandler, { capture: !0 });
979
999
  }, 100);
980
1000
  }
981
1001
  hide() {
982
- var t;
983
- (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);
984
1004
  }
985
1005
  get visible() {
986
1006
  return this.root !== null;
987
1007
  }
988
1008
  }
989
- const X = (
1009
+ const Y = (
990
1010
  /* css */
991
1011
  `
992
1012
  :host {
@@ -1487,10 +1507,10 @@ const X = (
1487
1507
  }
1488
1508
  .fl-feedback-modal-actions { padding: 0 16px 16px; }
1489
1509
  `
1490
- ), Y = 5;
1491
- class G {
1510
+ ), G = 5;
1511
+ class J {
1492
1512
  constructor() {
1493
- 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;
1494
1514
  }
1495
1515
  // ----------------------------------------------------------------
1496
1516
  // Public API
@@ -1499,12 +1519,12 @@ class G {
1499
1519
  * Initialize the SDK with configuration.
1500
1520
  * This does NOT activate the UI — it only sets up triggers.
1501
1521
  */
1502
- async init(t) {
1522
+ async init(e) {
1503
1523
  if (this.state !== "idle") {
1504
1524
  console.warn("[FirstLook] SDK already initialized.");
1505
1525
  return;
1506
1526
  }
1507
- 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);
1508
1528
  }
1509
1529
  /**
1510
1530
  * Manually activate the SDK UI (bypassing triggers).
@@ -1519,15 +1539,15 @@ class G {
1519
1539
  /**
1520
1540
  * Start a UAT session with a list of quests.
1521
1541
  */
1522
- async startSession(t) {
1542
+ async startSession(e) {
1523
1543
  var s;
1524
1544
  if (this.state !== "active")
1525
1545
  throw new Error("[FirstLook] Cannot start session: SDK not active. Call activate() first.");
1526
- (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(
1527
1547
  this.config,
1528
1548
  this.events,
1529
1549
  this.fieldMasker.getCombinedSelector()
1530
- ), 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, {
1531
1551
  onOkWithFeedback: (i) => this.handleQuestOk(i),
1532
1552
  onConcern: (i) => this.handleConcern(i),
1533
1553
  onNg: () => this.handleQuestNg(),
@@ -1537,18 +1557,18 @@ class G {
1537
1557
  onMinimize: () => {
1538
1558
  }
1539
1559
  }), this.questManager.startSession(this.sessionStartTime), this.renderCurrentQuest();
1540
- const e = this.config.recording.maxDuration;
1541
- 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;
1542
1562
  }
1543
1563
  /**
1544
1564
  * Fetch quest definitions from the API and start a session.
1545
1565
  */
1546
- async startSessionFromRemote(t) {
1566
+ async startSessionFromRemote(e) {
1547
1567
  if (this.state !== "active")
1548
1568
  throw new Error("[FirstLook] Cannot start session: SDK not active. Call activate() first.");
1549
1569
  if (!this.config)
1550
1570
  throw new Error("[FirstLook] SDK not initialized.");
1551
- 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)}`, {
1552
1572
  headers: { "X-API-Key": this.config.apiKey }
1553
1573
  });
1554
1574
  if (!s.ok)
@@ -1560,12 +1580,12 @@ class G {
1560
1580
  * End the current session, persist data, and trigger upload.
1561
1581
  */
1562
1582
  async endSession() {
1563
- var i, n, o, l, c, h, d, g, f, p, m;
1583
+ var i, n, o, l, a, h, d, m, f, p, g;
1564
1584
  if (this.state !== "recording" || !this.sessionId) return null;
1565
- 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();
1566
- 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();
1567
1587
  await Promise.allSettled(
1568
- t.map(async (b) => {
1588
+ e.map(async (b) => {
1569
1589
  if (b.voiceMemoBlob) {
1570
1590
  try {
1571
1591
  b.voiceMemoBase64 = await this.blobToBase64(b.voiceMemoBlob);
@@ -1586,29 +1606,29 @@ class G {
1586
1606
  );
1587
1607
  })
1588
1608
  );
1589
- const e = {
1609
+ const t = {
1590
1610
  sessionId: this.sessionId,
1591
1611
  projectId: this.config.projectId,
1592
1612
  userId: this.config.userId,
1593
1613
  role: this.config.role,
1594
- deviceInfo: y(),
1614
+ deviceInfo: q(),
1595
1615
  startedAt: new Date(this.sessionStartTime).toISOString(),
1596
1616
  endedAt: (/* @__PURE__ */ new Date()).toISOString(),
1597
1617
  duration: Math.floor((Date.now() - this.sessionStartTime) / 1e3),
1598
- quests: t,
1618
+ quests: e,
1599
1619
  recordings: ((h = this.sessionRecorder) == null ? void 0 : h.getSnapshots()) ?? []
1600
1620
  };
1601
- await ((d = this.storage) == null ? void 0 : d.saveSession(e));
1602
- const s = ((g = this.issueReporter) == null ? void 0 : g.getAnnotations()) ?? [];
1621
+ await ((d = this.storage) == null ? void 0 : d.saveSession(t));
1622
+ const s = ((m = this.issueReporter) == null ? void 0 : m.getAnnotations()) ?? [];
1603
1623
  for (const b of s)
1604
1624
  await ((f = this.storage) == null ? void 0 : f.saveAnnotation(this.sessionId, b));
1605
- return await ((p = this.storage) == null ? void 0 : p.enqueueUpload({ session: e, annotations: s })), (m = this.questOverlay) == null || m.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;
1606
1626
  }
1607
1627
  /**
1608
1628
  * Subscribe to SDK events.
1609
1629
  */
1610
- on(t, e) {
1611
- return this.events.on(t, e);
1630
+ on(e, t) {
1631
+ return this.events.on(e, t);
1612
1632
  }
1613
1633
  /**
1614
1634
  * Get current SDK state.
@@ -1620,26 +1640,26 @@ class G {
1620
1640
  * Completely destroy the SDK instance and clean up all resources.
1621
1641
  */
1622
1642
  destroy() {
1623
- var t, e, s, i, n, o, l, c, h, d, g, f;
1624
- 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(() => {
1625
- }), (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(), (g = this.hostElement) == null || g.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";
1626
1646
  }
1627
1647
  // ----------------------------------------------------------------
1628
1648
  // Private methods
1629
1649
  // ----------------------------------------------------------------
1630
1650
  createShadowHost() {
1631
- var e;
1632
- (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" });
1633
- const t = document.createElement("style");
1634
- 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);
1635
1655
  }
1636
1656
  setupTriggers() {
1637
- const t = this.config.triggers;
1638
- 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();
1639
1659
  }
1640
1660
  onActivate() {
1641
- var t, e, s;
1642
- 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, {
1643
1663
  onStartSession: () => {
1644
1664
  this.events.emit({ type: "sdk:activated" });
1645
1665
  },
@@ -1652,77 +1672,77 @@ class G {
1652
1672
  }
1653
1673
  }), this.debugMenu.show());
1654
1674
  }
1655
- handleQuestOk(t) {
1675
+ handleQuestOk(e) {
1656
1676
  var i;
1657
1677
  if (!this.questManager || !this.sessionRecorder) return;
1658
- const e = this.sessionRecorder.getActionLogs(), s = (i = this.questOverlay) == null ? void 0 : i.getChecklist();
1659
- this.questManager.completeCurrentQuest(e, {
1660
- 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,
1661
1681
  checklist: s
1662
1682
  }), this.renderCurrentQuest();
1663
1683
  }
1664
- handleConcern(t) {
1684
+ handleConcern(e) {
1665
1685
  var i;
1666
1686
  if (!this.questManager || !this.sessionRecorder) return;
1667
- const e = this.sessionRecorder.getActionLogs(), s = (i = this.questOverlay) == null ? void 0 : i.getChecklist();
1668
- this.questManager.completeCurrentQuest(e, {
1669
- 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,
1670
1690
  concern: !0,
1671
1691
  checklist: s
1672
1692
  }), this.renderCurrentQuest();
1673
1693
  }
1674
1694
  handleQuestNg() {
1675
1695
  if (!this.questManager || !this.questOverlay) return;
1676
- const t = this.questManager.getCurrentQuest();
1677
- t && this.questOverlay.renderFeedbackModal(t.title, "ng");
1696
+ const e = this.questManager.getCurrentQuest();
1697
+ e && this.questOverlay.renderFeedbackModal(e.title, "ng");
1678
1698
  }
1679
- handleNgFeedbackSubmit(t) {
1699
+ handleNgFeedbackSubmit(e) {
1680
1700
  var i;
1681
1701
  if (!this.questManager || !this.sessionRecorder) return;
1682
- const e = this.sessionRecorder.getActionLogs(), s = (i = this.questOverlay) == null ? void 0 : i.getChecklist();
1683
- 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();
1684
1704
  }
1685
- handleMemo(t) {
1686
- if (!this.questManager || !t) return;
1687
- const e = {
1688
- comment: t,
1705
+ handleMemo(e) {
1706
+ if (!this.questManager || !e) return;
1707
+ const t = {
1708
+ comment: e,
1689
1709
  timestamp: Date.now(),
1690
1710
  relativeTime: Date.now() - this.sessionStartTime
1691
1711
  };
1692
- this.questManager.addFeedback(e);
1712
+ this.questManager.addFeedback(t);
1693
1713
  }
1694
1714
  renderCurrentQuest() {
1695
1715
  var s;
1696
1716
  if (!this.questManager || !this.questOverlay) return;
1697
- const t = this.questManager.getStatus();
1698
- if (t.isBlocked) {
1699
- const i = this.questManager.getCurrentQuest();
1700
- this.questOverlay.renderBlocked((i == null ? void 0 : i.title) ?? "Unknown");
1717
+ const e = this.questManager.getStatus();
1718
+ if (e.isBlocked) {
1719
+ const n = this.questManager.getResults().find((l) => l.status === "FAILED"), o = n ? n.questId : "Unknown";
1720
+ this.questOverlay.renderBlocked(o);
1701
1721
  return;
1702
1722
  }
1703
- if (t.isFinished) {
1704
- this.questOverlay.renderSummary(t.completed, t.failed, t.total);
1723
+ if (e.isFinished) {
1724
+ this.questOverlay.renderSummary(e.completed, e.failed, e.total);
1705
1725
  return;
1706
1726
  }
1707
- const e = this.questManager.getCurrentQuest();
1708
- e && this.questOverlay.renderQuest(
1709
- e,
1727
+ const t = this.questManager.getCurrentQuest();
1728
+ t && this.questOverlay.renderQuest(
1729
+ t,
1710
1730
  this.questManager.getQuestStatuses(),
1711
1731
  ((s = this.voiceRecorder) == null ? void 0 : s.recording) ?? !1
1712
1732
  );
1713
1733
  }
1714
- async flushUploadQueue(t) {
1734
+ async flushUploadQueue(e) {
1715
1735
  if (!(!this.storage || !this.config || this.isFlushing)) {
1716
1736
  this.isFlushing = !0;
1717
1737
  try {
1718
- if (t) {
1738
+ if (e) {
1719
1739
  const s = navigator.connection;
1720
1740
  if (s && s.type && s.type !== "wifi" && s.effectiveType !== "4g")
1721
1741
  return;
1722
1742
  }
1723
- const e = await this.storage.getPendingUploads();
1724
- for (const s of e) {
1725
- if (s.attempts >= Y) {
1743
+ const t = await this.storage.getPendingUploads();
1744
+ for (const s of t) {
1745
+ if (s.attempts >= G) {
1726
1746
  await this.storage.removeFromQueue(s.key);
1727
1747
  continue;
1728
1748
  }
@@ -1750,32 +1770,32 @@ class G {
1750
1770
  }
1751
1771
  }
1752
1772
  async backupSession() {
1753
- var t;
1773
+ var e;
1754
1774
  if (!(!this.storage || !this.sessionId || !this.config || !this.sessionRecorder))
1755
1775
  try {
1756
- const e = {
1776
+ const t = {
1757
1777
  sessionId: this.sessionId,
1758
1778
  projectId: this.config.projectId,
1759
1779
  userId: this.config.userId,
1760
1780
  role: this.config.role,
1761
- deviceInfo: y(),
1781
+ deviceInfo: q(),
1762
1782
  startedAt: new Date(this.sessionStartTime).toISOString(),
1763
1783
  duration: Math.floor((Date.now() - this.sessionStartTime) / 1e3),
1764
- quests: ((t = this.questManager) == null ? void 0 : t.getResults()) ?? [],
1784
+ quests: ((e = this.questManager) == null ? void 0 : e.getResults()) ?? [],
1765
1785
  recordings: this.sessionRecorder.getSnapshots()
1766
1786
  };
1767
- await this.storage.saveSession(e);
1787
+ await this.storage.saveSession(t);
1768
1788
  } catch {
1769
1789
  }
1770
1790
  }
1771
- blobToBase64(t) {
1772
- return new Promise((e, s) => {
1791
+ blobToBase64(e) {
1792
+ return new Promise((t, s) => {
1773
1793
  const i = new FileReader();
1774
- 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);
1775
1795
  });
1776
1796
  }
1777
1797
  }
1778
1798
  export {
1779
- G as FirstLookSDK
1799
+ J as FirstLookSDK
1780
1800
  };
1781
1801
  //# sourceMappingURL=firstlook.es.js.map