@firstlook-uat/sdk 0.4.0 โ†’ 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,10 +1,10 @@
1
- const T = [
1
+ const I = [
2
2
  'input[type="password"]',
3
3
  "[data-sensitive]",
4
4
  "[data-mask]",
5
5
  ".uat-mask"
6
6
  ];
7
- function q(a) {
7
+ function M(a) {
8
8
  var t, e, s, i, n, o, l, c, h, d;
9
9
  if (!a.endpoint)
10
10
  throw new Error("[FirstLook] 'endpoint' is required. Set your Supabase ingest-session URL.");
@@ -23,7 +23,7 @@ function q(a) {
23
23
  },
24
24
  security: {
25
25
  watermark: ((n = a.security) == null ? void 0 : n.watermark) ?? !0,
26
- maskSelectors: ((o = a.security) == null ? void 0 : o.maskSelectors) ?? T
26
+ maskSelectors: ((o = a.security) == null ? void 0 : o.maskSelectors) ?? I
27
27
  },
28
28
  recording: {
29
29
  domSnapshot: ((l = a.recording) == null ? void 0 : l.domSnapshot) ?? !0,
@@ -33,7 +33,7 @@ function q(a) {
33
33
  }
34
34
  };
35
35
  }
36
- function w() {
36
+ function y() {
37
37
  return {
38
38
  userAgent: navigator.userAgent,
39
39
  platform: navigator.platform,
@@ -44,7 +44,7 @@ function w() {
44
44
  touchSupport: "ontouchstart" in window || navigator.maxTouchPoints > 0
45
45
  };
46
46
  }
47
- class C {
47
+ class E {
48
48
  constructor() {
49
49
  this.listeners = /* @__PURE__ */ new Map();
50
50
  }
@@ -75,7 +75,7 @@ class C {
75
75
  this.listeners.clear();
76
76
  }
77
77
  }
78
- class I {
78
+ class R {
79
79
  constructor(t) {
80
80
  this.events = t, this.quests = [], this.results = [], this.currentIndex = -1, this.sessionStartTime = 0, this.blocked = !1, this.pendingFeedbacks = [];
81
81
  }
@@ -116,15 +116,16 @@ class I {
116
116
  logs: t,
117
117
  comment: e == null ? void 0 : e.comment,
118
118
  concern: (e == null ? void 0 : e.concern) ?? !1,
119
- feedbacks: this.drainFeedbacks()
119
+ feedbacks: this.drainFeedbacks(),
120
+ checklist: e == null ? void 0 : e.checklist
120
121
  };
121
122
  return this.results.push(i), this.events.emit({ type: "quest:completed", questId: s.id }), this.advance(), i;
122
123
  }
123
- failCurrentQuest(t, e, s) {
124
- const i = this.getCurrentQuest();
125
- if (!i) return null;
126
- const n = {
127
- questId: i.id,
124
+ failCurrentQuest(t, e, s, i) {
125
+ const n = this.getCurrentQuest();
126
+ if (!n) return null;
127
+ const o = {
128
+ questId: n.id,
128
129
  status: "FAILED",
129
130
  timestamp: Date.now(),
130
131
  relativeTime: Date.now() - this.sessionStartTime,
@@ -132,9 +133,10 @@ class I {
132
133
  logs: t,
133
134
  comment: e,
134
135
  concern: !1,
135
- feedbacks: this.drainFeedbacks()
136
+ feedbacks: this.drainFeedbacks(),
137
+ checklist: i
136
138
  };
137
- return this.results.push(n), this.events.emit({ type: "quest:failed", questId: i.id }), i.blocking ? (this.blocked = !0, this.events.emit({ type: "quest:blocked", questId: i.id })) : this.advance(), n;
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;
138
140
  }
139
141
  addFeedback(t) {
140
142
  this.pendingFeedbacks.push(t);
@@ -160,16 +162,34 @@ function r(a, t, e) {
160
162
  typeof i == "string" ? s.appendChild(document.createTextNode(i)) : s.appendChild(i);
161
163
  return s;
162
164
  }
163
- function M() {
165
+ function L() {
164
166
  return `fl_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
165
167
  }
166
- function R(a) {
168
+ function A(a) {
167
169
  const t = Math.floor(a / 60), e = a % 60;
168
170
  return `${t.toString().padStart(2, "0")}:${e.toString().padStart(2, "0")}`;
169
171
  }
170
- class E {
172
+ function D(a) {
173
+ const t = a.split(`
174
+ `), e = [], s = [];
175
+ let i = !1;
176
+ for (const n of t) {
177
+ const o = n.trim(), l = o.match(/^(?:(\d+)[\.\)]\s+|[-*]\s+)(.+)$/);
178
+ l ? (i = !0, s.push({
179
+ index: s.length,
180
+ text: l[2],
181
+ checked: !1
182
+ })) : !i && o && e.push(o);
183
+ }
184
+ return {
185
+ preamble: e.join(`
186
+ `),
187
+ items: s
188
+ };
189
+ }
190
+ class N {
171
191
  constructor(t, e) {
172
- this.shadowRoot = t, this.callbacks = e, this.minimized = !1, this.timerInterval = null, this.startTime = 0, this.root = document.createElement("div"), this.root.className = "fl-quest-overlay", this.root.style.pointerEvents = "auto";
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";
173
193
  for (const s of ["click", "mousedown", "mouseup", "pointerdown", "pointerup", "touchstart", "touchend"])
174
194
  this.root.addEventListener(s, (i) => i.stopPropagation());
175
195
  this.shadowRoot.appendChild(this.root);
@@ -186,37 +206,54 @@ class E {
186
206
  this.root.appendChild(n);
187
207
  const o = r("div", { className: "fl-quest-content" }), l = r("div", { className: "fl-quest-progress" });
188
208
  for (const f of e) {
189
- const g = f === "COMPLETED" ? "fl-completed" : f === "FAILED" ? "fl-failed" : f === "ACTIVE" ? "fl-active" : "";
190
- l.appendChild(r("div", { className: `fl-quest-progress-dot ${g}` }));
209
+ const p = f === "COMPLETED" ? "fl-completed" : f === "FAILED" ? "fl-failed" : f === "ACTIVE" ? "fl-active" : "";
210
+ l.appendChild(r("div", { className: `fl-quest-progress-dot ${p}` }));
191
211
  }
192
- const c = r("div", { className: "fl-quest-body" }, [
193
- l,
194
- r("p", { className: "fl-quest-description" }, [t.description]),
195
- r("div", { className: "fl-quest-memo-row" }, [
196
- this.createButton("fl-btn fl-btn-memo", "๐Ÿ“ ใƒกใƒขใ‚’ๆฎ‹ใ™", () => this.renderFeedbackModal(t.title))
197
- ]),
198
- r("div", { className: "fl-quest-actions" }, [
199
- this.createButton("fl-btn fl-btn-ok", "โœ“ OK", () => this.renderFeedbackModal(t.title, "ok")),
200
- this.createButton("fl-btn fl-btn-concern", "โš  ๆฐ—ใซใชใ‚‹", () => this.renderFeedbackModal(t.title, "concern")),
201
- this.createButton("fl-btn fl-btn-ng", "โœ— NG", this.callbacks.onNg)
202
- ])
203
- ]);
204
- o.appendChild(c), s && o.appendChild(
212
+ const c = D(t.description);
213
+ this.checklist = c.items;
214
+ const h = r("div", { className: "fl-quest-body" });
215
+ if (h.appendChild(l), c.items.length > 0) {
216
+ const f = r("div", { className: "fl-checklist-counter" }), p = () => {
217
+ const b = this.checklist.filter((k) => k.checked).length;
218
+ f.textContent = `โœ“ ${b}/${this.checklist.length} ็ขบ่ชๆธˆใฟ`;
219
+ };
220
+ p(), h.appendChild(f), c.preamble && h.appendChild(r("p", { className: "fl-quest-description" }, [c.preamble]));
221
+ const g = r("ul", { className: "fl-checklist" });
222
+ for (const b of this.checklist) {
223
+ const k = r("li", { className: "fl-checklist-item" }), v = document.createElement("input");
224
+ v.type = "checkbox", v.className = "fl-checklist-checkbox", v.checked = b.checked;
225
+ const T = r("span", { className: "fl-checklist-text" }, [b.text]);
226
+ v.onchange = () => {
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);
231
+ }
232
+ h.appendChild(g);
233
+ } else
234
+ h.appendChild(r("p", { className: "fl-quest-description" }, [t.description]));
235
+ h.appendChild(r("div", { className: "fl-quest-memo-row" }, [
236
+ this.createButton("fl-btn fl-btn-memo", "๐Ÿ“ ใƒกใƒขใ‚’ๆฎ‹ใ™", () => this.renderFeedbackModal(t.title))
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")),
240
+ this.createButton("fl-btn fl-btn-ng", "โœ— NG", this.callbacks.onNg)
241
+ ])), o.appendChild(h), s && o.appendChild(
205
242
  r("div", { className: "fl-voice-indicator" }, [
206
243
  r("span", { className: "fl-voice-dot" }),
207
244
  "Recording..."
208
245
  ])
209
246
  );
210
- const h = r("div", { className: "fl-status-bar" });
211
- s && h.appendChild(
247
+ const d = r("div", { className: "fl-status-bar" });
248
+ s && d.appendChild(
212
249
  r("span", { className: "fl-status-recording" }, [
213
250
  r("span", { className: "fl-voice-dot" }),
214
251
  "REC"
215
252
  ])
216
253
  );
217
- const d = r("span", { className: "fl-status-timer" }, ["00:00"]);
218
- h.appendChild(d), o.appendChild(h), this.root.appendChild(o), this.startTimer(d), this.root.onclick = () => {
219
- this.minimized && (this.minimized = !1, this.root.className = "fl-quest-overlay", this.root.innerHTML = "", this.root.appendChild(n), this.root.appendChild(o), this.startTimer(d));
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));
220
257
  };
221
258
  }
222
259
  renderFeedbackModal(t, e = "memo") {
@@ -249,25 +286,24 @@ class E {
249
286
  memo: "ๆฐ—ใฅใ„ใŸใ“ใจใ‚’ใƒกใƒข...๐Ÿ“"
250
287
  }, d = document.createElement("textarea");
251
288
  d.className = "fl-feedback-textarea fl-feedback-textarea-modal", d.placeholder = h[e], d.rows = 3, c.appendChild(d);
252
- const f = "้€ไฟก", g = e === "ok" ? "ใ‚นใ‚ญใƒƒใƒ—" : "ใ‚ญใƒฃใƒณใ‚ปใƒซ", p = r("div", { className: "fl-quest-actions fl-feedback-modal-actions" }, [
253
- this.createButton("fl-btn fl-btn-skip", g, () => {
254
- e === "ng" ? this.callbacks.onNgWithFeedback("") : e === "ok" && this.callbacks.onOkWithFeedback(""), s.remove();
289
+ const m = "้€ไฟก", f = e === "ok" ? "ใ‚นใ‚ญใƒƒใƒ—" : "ใ‚ญใƒฃใƒณใ‚ปใƒซ", p = r("div", { className: "fl-quest-actions fl-feedback-modal-actions" }, [
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();
255
292
  }),
256
- this.createButton("fl-btn fl-btn-finish", f, () => {
257
- const m = d.value.trim();
293
+ this.createButton("fl-btn fl-btn-finish", m, () => {
294
+ const g = d.value.trim();
258
295
  if (e === "ng")
259
- this.callbacks.onNgWithFeedback(m);
296
+ this.callbacks.onNgWithFeedback(g);
260
297
  else if (e === "ok")
261
- this.callbacks.onOkWithFeedback(m);
262
- else if (e === "concern") {
263
- if (!m) return;
264
- this.callbacks.onConcern(m);
265
- } else {
266
- if (!m) {
298
+ this.callbacks.onOkWithFeedback(g);
299
+ else if (e === "concern")
300
+ this.callbacks.onConcern(g);
301
+ else {
302
+ if (!g) {
267
303
  s.remove();
268
304
  return;
269
305
  }
270
- this.callbacks.onMemo(m);
306
+ this.callbacks.onMemo(g);
271
307
  }
272
308
  s.remove();
273
309
  })
@@ -304,6 +340,9 @@ class E {
304
340
  ]);
305
341
  this.root.appendChild(e);
306
342
  }
343
+ getChecklist() {
344
+ return this.checklist.length > 0 ? [...this.checklist] : void 0;
345
+ }
307
346
  destroy() {
308
347
  this.stopTimer(), this.root.remove();
309
348
  }
@@ -330,15 +369,15 @@ class E {
330
369
  startTimer(t) {
331
370
  this.stopTimer(), this.startTime || (this.startTime = Date.now()), this.timerInterval = setInterval(() => {
332
371
  const e = Math.floor((Date.now() - this.startTime) / 1e3);
333
- t.textContent = R(e);
372
+ t.textContent = A(e);
334
373
  }, 1e3);
335
374
  }
336
375
  stopTimer() {
337
376
  this.timerInterval && (clearInterval(this.timerInterval), this.timerInterval = null);
338
377
  }
339
378
  }
340
- const L = 100, A = 2 * 1024 * 1024;
341
- class D {
379
+ const F = 100, P = 2 * 1024 * 1024;
380
+ class z {
342
381
  constructor(t, e, s) {
343
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);
344
383
  }
@@ -405,8 +444,8 @@ class D {
405
444
  const s = t.querySelector("#firstlook-sdk-root");
406
445
  s == null || s.remove();
407
446
  const i = t.outerHTML;
408
- if (i.length > A) return;
409
- this.snapshots.length >= L && this.snapshots.shift(), this.snapshots.push({
447
+ if (i.length > P) return;
448
+ this.snapshots.length >= F && this.snapshots.shift(), this.snapshots.push({
410
449
  type: "dom-snapshot",
411
450
  timestamp: Date.now() - this.startTime,
412
451
  data: i
@@ -427,7 +466,7 @@ function x(a) {
427
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)) || "";
428
467
  return `${t}${e}${s}${i ? ` "${i}"` : ""}`;
429
468
  }
430
- class N {
469
+ class O {
431
470
  constructor(t) {
432
471
  this.events = t, this.mediaRecorder = null, this.stream = null, this.chunks = [], this._recording = !1;
433
472
  }
@@ -486,7 +525,7 @@ class N {
486
525
  return "";
487
526
  }
488
527
  }
489
- class F {
528
+ class Q {
490
529
  constructor(t, e) {
491
530
  this.shadowRoot = t, this.config = e, this.container = null, this.refreshInterval = null, this.cachedIp = null;
492
531
  }
@@ -516,7 +555,7 @@ class F {
516
555
  }
517
556
  }
518
557
  }
519
- class P {
558
+ class B {
520
559
  constructor(t) {
521
560
  this.selectors = t, this.observer = null, this.maskedElements = /* @__PURE__ */ new Set();
522
561
  }
@@ -554,20 +593,20 @@ class P {
554
593
  }
555
594
  }
556
595
  }
557
- const z = "firstlook_uat", O = 1, u = {
596
+ const $ = "firstlook_uat", U = 1, u = {
558
597
  sessions: "sessions",
559
598
  recordings: "recordings",
560
599
  annotations: "annotations",
561
600
  uploadQueue: "upload_queue"
562
601
  };
563
- class Q {
602
+ class j {
564
603
  constructor() {
565
604
  this.db = null;
566
605
  }
567
606
  async open() {
568
607
  if (!this.db)
569
608
  return new Promise((t, e) => {
570
- const s = indexedDB.open(z, O);
609
+ const s = indexedDB.open($, U);
571
610
  s.onupgradeneeded = () => {
572
611
  const i = s.result;
573
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 });
@@ -677,10 +716,10 @@ class Q {
677
716
  });
678
717
  }
679
718
  }
680
- const y = ["#e17055", "#6c5ce7", "#00b894", "#fdcb6e", "#ffffff"];
681
- class B {
719
+ const S = ["#e17055", "#6c5ce7", "#00b894", "#fdcb6e", "#ffffff"];
720
+ class K {
682
721
  constructor(t) {
683
- this.shadowRoot = t, this.overlay = null, this.canvas = null, this.ctx = null, this.drawing = !1, this.currentPath = [], this.paths = [], this.selectedColor = y[0], this.screenshotDataUrl = "";
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 = "";
684
723
  }
685
724
  async open() {
686
725
  return this.screenshotDataUrl = await this.captureScreenshot(), new Promise((t) => {
@@ -692,7 +731,7 @@ class B {
692
731
  type: "text",
693
732
  placeholder: "Add a comment..."
694
733
  }), i = r("div", { className: "fl-color-picker" });
695
- for (const c of y) {
734
+ for (const c of S) {
696
735
  const h = r("div", { className: `fl-color-swatch ${c === this.selectedColor ? "fl-selected" : ""}` });
697
736
  h.style.background = c, h.onclick = () => {
698
737
  this.selectedColor = c, i.querySelectorAll(".fl-color-swatch").forEach((d) => d.classList.remove("fl-selected")), h.classList.add("fl-selected");
@@ -742,16 +781,16 @@ class B {
742
781
  <foreignObject width="100%" height="100%">
743
782
  ${l}
744
783
  </foreignObject>
745
- </svg>`, h = new Blob([c], { type: "image/svg+xml;charset=utf-8" }), d = URL.createObjectURL(h), f = document.createElement("canvas");
746
- f.width = t * window.devicePixelRatio, f.height = e * window.devicePixelRatio;
747
- const g = f.getContext("2d");
748
- return g.scale(window.devicePixelRatio, window.devicePixelRatio), new Promise((p) => {
749
- const m = new Image();
750
- m.onload = () => {
751
- g.drawImage(m, 0, 0, t, e), URL.revokeObjectURL(d), p(f.toDataURL("image/png"));
752
- }, m.onerror = () => {
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;
786
+ const f = m.getContext("2d");
787
+ return f.scale(window.devicePixelRatio, window.devicePixelRatio), new Promise((p) => {
788
+ const g = new Image();
789
+ g.onload = () => {
790
+ f.drawImage(g, 0, 0, t, e), URL.revokeObjectURL(d), p(m.toDataURL("image/png"));
791
+ }, g.onerror = () => {
753
792
  URL.revokeObjectURL(d), p(this.captureScreenshotFallback(t, e));
754
- }, m.src = d;
793
+ }, g.src = d;
755
794
  });
756
795
  } catch {
757
796
  return this.captureScreenshotFallback(window.innerWidth, window.innerHeight);
@@ -796,11 +835,11 @@ class B {
796
835
  return ((t = this.canvas) == null ? void 0 : t.toDataURL("image/png")) || this.screenshotDataUrl;
797
836
  }
798
837
  }
799
- class U {
838
+ class H {
800
839
  constructor(t, e) {
801
840
  this.shadowRoot = t, this.events = e, this.annotations = [], this.active = !1, this.onKeydown = (s) => {
802
841
  s.ctrlKey && s.shiftKey && s.key === "R" && (s.preventDefault(), this.trigger());
803
- }, this.annotationCanvas = new B(t);
842
+ }, this.annotationCanvas = new K(t);
804
843
  }
805
844
  start() {
806
845
  document.addEventListener("keydown", this.onKeydown);
@@ -823,7 +862,7 @@ class U {
823
862
  }
824
863
  }
825
864
  }
826
- class j {
865
+ class _ {
827
866
  constructor(t, e) {
828
867
  this.requiredTaps = t, this.onActivate = e, this.tapCount = 0, this.tapTimer = null, this.handler = null;
829
868
  }
@@ -840,8 +879,8 @@ class j {
840
879
  this.tapCount = 0, this.tapTimer && (clearTimeout(this.tapTimer), this.tapTimer = null);
841
880
  }
842
881
  }
843
- const k = "firstlook:uat-active";
844
- class S {
882
+ const w = "firstlook:uat-active";
883
+ class C {
845
884
  constructor(t) {
846
885
  this.onActivate = t, this.handlers = [];
847
886
  }
@@ -866,7 +905,7 @@ class S {
866
905
  }
867
906
  static clearPersisted() {
868
907
  try {
869
- sessionStorage.removeItem(k);
908
+ sessionStorage.removeItem(w);
870
909
  } catch {
871
910
  }
872
911
  }
@@ -884,19 +923,19 @@ class S {
884
923
  }
885
924
  persist() {
886
925
  try {
887
- sessionStorage.setItem(k, "1");
926
+ sessionStorage.setItem(w, "1");
888
927
  } catch {
889
928
  }
890
929
  }
891
930
  hasPersisted() {
892
931
  try {
893
- return sessionStorage.getItem(k) === "1";
932
+ return sessionStorage.getItem(w) === "1";
894
933
  } catch {
895
934
  return !1;
896
935
  }
897
936
  }
898
937
  }
899
- class $ {
938
+ class W {
900
939
  constructor(t) {
901
940
  this.onActivate = t, this.handler = null;
902
941
  }
@@ -909,7 +948,7 @@ class $ {
909
948
  this.handler && (window.removeEventListener("keydown", this.handler), this.handler = null);
910
949
  }
911
950
  }
912
- class K {
951
+ class V {
913
952
  constructor(t, e) {
914
953
  this.shadowRoot = t, this.callbacks = e, this.root = null, this.outsideClickHandler = null;
915
954
  }
@@ -946,7 +985,7 @@ class K {
946
985
  return this.root !== null;
947
986
  }
948
987
  }
949
- const H = (
988
+ const X = (
950
989
  /* css */
951
990
  `
952
991
  :host {
@@ -1157,6 +1196,51 @@ const H = (
1157
1196
  50% { opacity: 0.3; }
1158
1197
  }
1159
1198
 
1199
+ /* === Checklist === */
1200
+ .fl-checklist-counter {
1201
+ font-size: 13px;
1202
+ font-weight: 600;
1203
+ color: #6c5ce7;
1204
+ margin-bottom: 8px;
1205
+ }
1206
+ .fl-checklist {
1207
+ list-style: none;
1208
+ padding: 0;
1209
+ margin: 0 0 12px;
1210
+ max-height: 240px;
1211
+ overflow-y: auto;
1212
+ -webkit-overflow-scrolling: touch;
1213
+ }
1214
+ .fl-checklist-item {
1215
+ display: flex;
1216
+ align-items: flex-start;
1217
+ gap: 8px;
1218
+ padding: 8px 4px;
1219
+ border-bottom: 1px solid rgba(0,0,0,.06);
1220
+ font-size: 13px;
1221
+ color: #4a4a5a;
1222
+ cursor: pointer;
1223
+ min-height: 40px;
1224
+ transition: background .2s;
1225
+ }
1226
+ .fl-checklist-item:last-child { border-bottom: none; }
1227
+ .fl-checklist-item:active { background: rgba(108,92,231,.05); }
1228
+ .fl-checklist-item.fl-checked { color: #aaa; }
1229
+ .fl-checklist-item.fl-checked .fl-checklist-text { text-decoration: line-through; }
1230
+ .fl-checklist-checkbox {
1231
+ margin-top: 2px;
1232
+ width: 18px;
1233
+ height: 18px;
1234
+ accent-color: #6c5ce7;
1235
+ flex-shrink: 0;
1236
+ cursor: pointer;
1237
+ }
1238
+ .fl-checklist-text {
1239
+ flex: 1;
1240
+ line-height: 1.4;
1241
+ word-break: break-word;
1242
+ }
1243
+
1160
1244
  /* === Annotation overlay === */
1161
1245
  .fl-annotation-overlay {
1162
1246
  position: fixed;
@@ -1402,10 +1486,10 @@ const H = (
1402
1486
  }
1403
1487
  .fl-feedback-modal-actions { padding: 0 16px 16px; }
1404
1488
  `
1405
- ), _ = 5;
1406
- class W {
1489
+ ), Y = 5;
1490
+ class G {
1407
1491
  constructor() {
1408
- this.config = null, this.events = new C(), 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;
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;
1409
1493
  }
1410
1494
  // ----------------------------------------------------------------
1411
1495
  // Public API
@@ -1419,7 +1503,7 @@ class W {
1419
1503
  console.warn("[FirstLook] SDK already initialized.");
1420
1504
  return;
1421
1505
  }
1422
- this.config = q(t), this.storage = new Q(), await this.storage.open(), this.createShadowHost(), this.setupTriggers(), this.fieldMasker = new P(this.config.security.maskSelectors), this.state = "initialized", this.events.emit({ type: "sdk:initialized" }), this.flushUploadQueue(!0);
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);
1423
1507
  }
1424
1508
  /**
1425
1509
  * Manually activate the SDK UI (bypassing triggers).
@@ -1438,11 +1522,11 @@ class W {
1438
1522
  var s;
1439
1523
  if (this.state !== "active")
1440
1524
  throw new Error("[FirstLook] Cannot start session: SDK not active. Call activate() first.");
1441
- (s = this.debugMenu) == null || s.hide(), this.sessionId = M(), this.sessionStartTime = Date.now(), this.questManager = new I(this.events), this.questManager.loadQuests(t), this.sessionRecorder = new D(
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(
1442
1526
  this.config,
1443
1527
  this.events,
1444
1528
  this.fieldMasker.getCombinedSelector()
1445
- ), this.voiceRecorder = new N(this.events), this.issueReporter = new U(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 F(this.shadowRoot, this.config), this.watermark.show()), this.questOverlay = new E(this.shadowRoot, {
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, {
1446
1530
  onOkWithFeedback: (i) => this.handleQuestOk(i),
1447
1531
  onConcern: (i) => this.handleConcern(i),
1448
1532
  onNg: () => this.handleQuestNg(),
@@ -1475,7 +1559,7 @@ class W {
1475
1559
  * End the current session, persist data, and trigger upload.
1476
1560
  */
1477
1561
  async endSession() {
1478
- var i, n, o, l, c, h, d, f, g, p, m;
1562
+ var i, n, o, l, c, h, d, m, f, p, g;
1479
1563
  if (this.state !== "recording" || !this.sessionId) return null;
1480
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();
1481
1565
  const t = this.questManager.getResults();
@@ -1489,13 +1573,13 @@ class W {
1489
1573
  delete b.voiceMemoBlob;
1490
1574
  }
1491
1575
  await Promise.allSettled(
1492
- b.feedbacks.map(async (v) => {
1493
- if (v.voiceMemoBlob) {
1576
+ b.feedbacks.map(async (k) => {
1577
+ if (k.voiceMemoBlob) {
1494
1578
  try {
1495
- v.voiceMemoBase64 = await this.blobToBase64(v.voiceMemoBlob);
1579
+ k.voiceMemoBase64 = await this.blobToBase64(k.voiceMemoBlob);
1496
1580
  } catch {
1497
1581
  }
1498
- delete v.voiceMemoBlob;
1582
+ delete k.voiceMemoBlob;
1499
1583
  }
1500
1584
  })
1501
1585
  );
@@ -1506,7 +1590,7 @@ class W {
1506
1590
  projectId: this.config.projectId,
1507
1591
  userId: this.config.userId,
1508
1592
  role: this.config.role,
1509
- deviceInfo: w(),
1593
+ deviceInfo: y(),
1510
1594
  startedAt: new Date(this.sessionStartTime).toISOString(),
1511
1595
  endedAt: (/* @__PURE__ */ new Date()).toISOString(),
1512
1596
  duration: Math.floor((Date.now() - this.sessionStartTime) / 1e3),
@@ -1514,10 +1598,10 @@ class W {
1514
1598
  recordings: ((h = this.sessionRecorder) == null ? void 0 : h.getSnapshots()) ?? []
1515
1599
  };
1516
1600
  await ((d = this.storage) == null ? void 0 : d.saveSession(e));
1517
- const s = ((f = this.issueReporter) == null ? void 0 : f.getAnnotations()) ?? [];
1601
+ const s = ((m = this.issueReporter) == null ? void 0 : m.getAnnotations()) ?? [];
1518
1602
  for (const b of s)
1519
- await ((g = this.storage) == null ? void 0 : g.saveAnnotation(this.sessionId, b));
1520
- 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;
1603
+ 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;
1521
1605
  }
1522
1606
  /**
1523
1607
  * Subscribe to SDK events.
@@ -1535,9 +1619,9 @@ class W {
1535
1619
  * Completely destroy the SDK instance and clean up all resources.
1536
1620
  */
1537
1621
  destroy() {
1538
- var t, e, s, i, n, o, l, c, h, d, f, g;
1539
- 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(), S.clearPersisted(), (i = this.sessionRecorder) == null || i.stop(), (n = this.voiceRecorder) == null || n.stopAsync().catch(() => {
1540
- }), (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(), (f = this.hostElement) == null || f.remove(), (g = this.storage) == null || g.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";
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";
1541
1625
  }
1542
1626
  // ----------------------------------------------------------------
1543
1627
  // Private methods
@@ -1546,15 +1630,15 @@ class W {
1546
1630
  var e;
1547
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" });
1548
1632
  const t = document.createElement("style");
1549
- t.textContent = H, this.shadowRoot.appendChild(t);
1633
+ t.textContent = X, this.shadowRoot.appendChild(t);
1550
1634
  }
1551
1635
  setupTriggers() {
1552
1636
  const t = this.config.triggers;
1553
- this.tapTrigger = new j(t.tapCount, () => this.onActivate()), this.tapTrigger.start(), t.deepLink && (this.deepLinkTrigger = new S(() => this.onActivate()), this.deepLinkTrigger.start()), t.keyboard && (this.keyboardTrigger = new $(() => this.onActivate()), this.keyboardTrigger.start()), t.customCheck && t.customCheck() && this.onActivate();
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();
1554
1638
  }
1555
1639
  onActivate() {
1556
1640
  var t, e, s;
1557
- 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 K(this.shadowRoot, {
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, {
1558
1642
  onStartSession: () => {
1559
1643
  this.events.emit({ type: "sdk:activated" });
1560
1644
  },
@@ -1568,18 +1652,22 @@ class W {
1568
1652
  }), this.debugMenu.show());
1569
1653
  }
1570
1654
  handleQuestOk(t) {
1655
+ var i;
1571
1656
  if (!this.questManager || !this.sessionRecorder) return;
1572
- const e = this.sessionRecorder.getActionLogs();
1657
+ const e = this.sessionRecorder.getActionLogs(), s = (i = this.questOverlay) == null ? void 0 : i.getChecklist();
1573
1658
  this.questManager.completeCurrentQuest(e, {
1574
- comment: t || void 0
1659
+ comment: t || void 0,
1660
+ checklist: s
1575
1661
  }), this.renderCurrentQuest();
1576
1662
  }
1577
1663
  handleConcern(t) {
1664
+ var i;
1578
1665
  if (!this.questManager || !this.sessionRecorder) return;
1579
- const e = this.sessionRecorder.getActionLogs();
1666
+ const e = this.sessionRecorder.getActionLogs(), s = (i = this.questOverlay) == null ? void 0 : i.getChecklist();
1580
1667
  this.questManager.completeCurrentQuest(e, {
1581
1668
  comment: t,
1582
- concern: !0
1669
+ concern: !0,
1670
+ checklist: s
1583
1671
  }), this.renderCurrentQuest();
1584
1672
  }
1585
1673
  handleQuestNg() {
@@ -1588,9 +1676,10 @@ class W {
1588
1676
  t && this.questOverlay.renderFeedbackModal(t.title, "ng");
1589
1677
  }
1590
1678
  handleNgFeedbackSubmit(t) {
1679
+ var i;
1591
1680
  if (!this.questManager || !this.sessionRecorder) return;
1592
- const e = this.sessionRecorder.getActionLogs();
1593
- this.questManager.failCurrentQuest(e, t || void 0), this.renderCurrentQuest();
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();
1594
1683
  }
1595
1684
  handleMemo(t) {
1596
1685
  if (!this.questManager || !t) return;
@@ -1606,8 +1695,8 @@ class W {
1606
1695
  if (!this.questManager || !this.questOverlay) return;
1607
1696
  const t = this.questManager.getStatus();
1608
1697
  if (t.isBlocked) {
1609
- const i = this.questManager.getCurrentQuest();
1610
- this.questOverlay.renderBlocked((i == null ? void 0 : i.title) ?? "Unknown");
1698
+ const n = this.questManager.getResults().find((l) => l.status === "FAILED"), o = n ? n.questId : "Unknown";
1699
+ this.questOverlay.renderBlocked(o);
1611
1700
  return;
1612
1701
  }
1613
1702
  if (t.isFinished) {
@@ -1632,7 +1721,7 @@ class W {
1632
1721
  }
1633
1722
  const e = await this.storage.getPendingUploads();
1634
1723
  for (const s of e) {
1635
- if (s.attempts >= _) {
1724
+ if (s.attempts >= Y) {
1636
1725
  await this.storage.removeFromQueue(s.key);
1637
1726
  continue;
1638
1727
  }
@@ -1668,7 +1757,7 @@ class W {
1668
1757
  projectId: this.config.projectId,
1669
1758
  userId: this.config.userId,
1670
1759
  role: this.config.role,
1671
- deviceInfo: w(),
1760
+ deviceInfo: y(),
1672
1761
  startedAt: new Date(this.sessionStartTime).toISOString(),
1673
1762
  duration: Math.floor((Date.now() - this.sessionStartTime) / 1e3),
1674
1763
  quests: ((t = this.questManager) == null ? void 0 : t.getResults()) ?? [],
@@ -1686,6 +1775,6 @@ class W {
1686
1775
  }
1687
1776
  }
1688
1777
  export {
1689
- W as FirstLookSDK
1778
+ G as FirstLookSDK
1690
1779
  };
1691
1780
  //# sourceMappingURL=firstlook.es.js.map