@checkflow/sdk 1.1.0 → 1.1.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.
Files changed (45) hide show
  1. package/README.md +63 -219
  2. package/dist/chunk-CD33QAA6.mjs +131 -0
  3. package/dist/chunk-CQ56DMFR.mjs +83 -0
  4. package/dist/highlighter-D_wZWHlS.d.mts +71 -0
  5. package/dist/highlighter-D_wZWHlS.d.ts +71 -0
  6. package/dist/highlighter-W4XDALRE.mjs +8 -0
  7. package/dist/index.d.mts +41 -0
  8. package/dist/index.d.ts +38 -20
  9. package/dist/index.js +607 -17221
  10. package/dist/index.mjs +411 -0
  11. package/dist/react.d.mts +28 -0
  12. package/dist/react.d.ts +28 -0
  13. package/dist/react.js +743 -0
  14. package/dist/react.mjs +51 -0
  15. package/dist/screenshot-CUMBPE2T.mjs +12 -0
  16. package/dist/vue.d.mts +26 -0
  17. package/dist/vue.d.ts +26 -0
  18. package/dist/vue.js +744 -0
  19. package/dist/vue.mjs +53 -0
  20. package/package.json +38 -51
  21. package/dist/analytics-tracker.d.ts +0 -112
  22. package/dist/annotation/editor.d.ts +0 -72
  23. package/dist/annotation/index.d.ts +0 -9
  24. package/dist/annotation/styles.d.ts +0 -6
  25. package/dist/annotation/toolbar.d.ts +0 -32
  26. package/dist/annotation/types.d.ts +0 -85
  27. package/dist/api-client.d.ts +0 -76
  28. package/dist/checkflow.css +0 -1
  29. package/dist/checkflow.d.ts +0 -112
  30. package/dist/context-capture.d.ts +0 -42
  31. package/dist/error-capture.d.ts +0 -60
  32. package/dist/index.esm.js +0 -17210
  33. package/dist/index.esm.js.map +0 -1
  34. package/dist/index.js.map +0 -1
  35. package/dist/privacy/detector.d.ts +0 -56
  36. package/dist/privacy/index.d.ts +0 -8
  37. package/dist/privacy/masker.d.ts +0 -43
  38. package/dist/privacy/types.d.ts +0 -54
  39. package/dist/react/index.d.ts +0 -77
  40. package/dist/session-recording-rrweb.d.ts +0 -100
  41. package/dist/session-recording.d.ts +0 -74
  42. package/dist/types.d.ts +0 -299
  43. package/dist/vue/index.d.ts +0 -55
  44. package/dist/widget/Widget.d.ts +0 -98
  45. package/dist/widget/index.d.ts +0 -2
package/dist/react.js ADDED
@@ -0,0 +1,743 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __esm = (fn, res) => function __init() {
7
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
8
+ };
9
+ var __export = (target, all) => {
10
+ for (var name in all)
11
+ __defProp(target, name, { get: all[name], enumerable: true });
12
+ };
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from))
16
+ if (!__hasOwnProp.call(to, key) && key !== except)
17
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
+ }
19
+ return to;
20
+ };
21
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
22
+
23
+ // src/collector.ts
24
+ function collectContext() {
25
+ const ua = navigator.userAgent;
26
+ return {
27
+ url: window.location.href,
28
+ viewport: {
29
+ width: window.innerWidth,
30
+ height: window.innerHeight,
31
+ device: window.innerWidth < 768 ? "mobile" : window.innerWidth < 1024 ? "tablet" : "desktop"
32
+ },
33
+ user_agent: ua,
34
+ browser: detectBrowser(ua),
35
+ os: detectOS(ua),
36
+ locale: navigator.language,
37
+ timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
38
+ };
39
+ }
40
+ function collectPerformance() {
41
+ try {
42
+ const entries = performance.getEntriesByType("paint");
43
+ const metrics = {};
44
+ entries.forEach((e) => {
45
+ if (e.name === "first-contentful-paint") metrics.fcp = Math.round(e.startTime);
46
+ });
47
+ const nav = performance.getEntriesByType("navigation")[0];
48
+ if (nav) {
49
+ metrics.dom_load = Math.round(nav.domContentLoadedEventEnd - nav.startTime);
50
+ metrics.load = Math.round(nav.loadEventEnd - nav.startTime);
51
+ }
52
+ return Object.keys(metrics).length > 0 ? metrics : void 0;
53
+ } catch {
54
+ return void 0;
55
+ }
56
+ }
57
+ function detectBrowser(ua) {
58
+ if (ua.includes("Firefox/")) return "Firefox";
59
+ if (ua.includes("Edg/")) return "Edge";
60
+ if (ua.includes("Chrome/")) return "Chrome";
61
+ if (ua.includes("Safari/")) return "Safari";
62
+ return "Unknown";
63
+ }
64
+ function detectOS(ua) {
65
+ if (ua.includes("Windows")) return "Windows";
66
+ if (ua.includes("Mac OS")) return "macOS";
67
+ if (ua.includes("Linux")) return "Linux";
68
+ if (ua.includes("Android")) return "Android";
69
+ if (ua.includes("iPhone") || ua.includes("iPad")) return "iOS";
70
+ return "Unknown";
71
+ }
72
+ var init_collector = __esm({
73
+ "src/collector.ts"() {
74
+ "use strict";
75
+ }
76
+ });
77
+
78
+ // src/console-interceptor.ts
79
+ function installInterceptors() {
80
+ if (installed) return;
81
+ installed = true;
82
+ const origConsole = {
83
+ log: console.log,
84
+ warn: console.warn,
85
+ error: console.error
86
+ };
87
+ ["log", "warn", "error"].forEach((level) => {
88
+ console[level] = (...args) => {
89
+ logs.push({
90
+ level,
91
+ message: args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" "),
92
+ timestamp: Date.now()
93
+ });
94
+ if (logs.length > MAX_LOGS) logs.shift();
95
+ origConsole[level](...args);
96
+ };
97
+ });
98
+ window.addEventListener("error", (event) => {
99
+ errorsCapture.push({
100
+ message: event.message,
101
+ filename: event.filename,
102
+ lineno: event.lineno,
103
+ colno: event.colno,
104
+ timestamp: Date.now()
105
+ });
106
+ if (errorsCapture.length > MAX_LOGS) errorsCapture.shift();
107
+ });
108
+ window.addEventListener("unhandledrejection", (event) => {
109
+ errorsCapture.push({
110
+ message: String(event.reason),
111
+ type: "unhandledrejection",
112
+ timestamp: Date.now()
113
+ });
114
+ if (errorsCapture.length > MAX_LOGS) errorsCapture.shift();
115
+ });
116
+ }
117
+ function getConsoleLogs() {
118
+ return [...logs];
119
+ }
120
+ function getJavascriptErrors() {
121
+ return [...errorsCapture];
122
+ }
123
+ function clearLogs() {
124
+ logs = [];
125
+ errorsCapture = [];
126
+ }
127
+ var MAX_LOGS, logs, errorsCapture, installed;
128
+ var init_console_interceptor = __esm({
129
+ "src/console-interceptor.ts"() {
130
+ "use strict";
131
+ MAX_LOGS = 50;
132
+ logs = [];
133
+ errorsCapture = [];
134
+ installed = false;
135
+ }
136
+ });
137
+
138
+ // src/widget.ts
139
+ function mountWidget(config2 = {}, onSubmit, opts) {
140
+ if (container) return;
141
+ onSubmitCallback = onSubmit;
142
+ const cfg = { ...DEFAULT_CONFIG, ...config2 };
143
+ container = document.createElement("div");
144
+ container.id = "checkflow-widget";
145
+ container.innerHTML = getWidgetHTML(cfg);
146
+ document.body.appendChild(container);
147
+ const btn = container.querySelector("#cf-trigger");
148
+ const form = container.querySelector("#cf-form");
149
+ const closeBtn = container.querySelector("#cf-close");
150
+ const submitBtn = container.querySelector("#cf-submit");
151
+ const screenshotBtn = container.querySelector("#cf-screenshot");
152
+ const highlightBtn = container.querySelector("#cf-highlight");
153
+ const screenshotPreview = container.querySelector("#cf-screenshot-preview");
154
+ btn?.addEventListener("click", () => {
155
+ form.style.display = form.style.display === "none" ? "flex" : "none";
156
+ screenshotDataUrl = null;
157
+ annotationsData = [];
158
+ if (screenshotPreview) screenshotPreview.style.display = "none";
159
+ });
160
+ closeBtn?.addEventListener("click", () => {
161
+ form.style.display = "none";
162
+ });
163
+ screenshotBtn?.addEventListener("click", async () => {
164
+ if (!opts?.onScreenshot) return;
165
+ screenshotBtn.textContent = "Capturing...";
166
+ form.style.display = "none";
167
+ try {
168
+ const data = await opts.onScreenshot();
169
+ if (data) {
170
+ screenshotDataUrl = data;
171
+ if (screenshotPreview) {
172
+ screenshotPreview.querySelector("img").src = data;
173
+ screenshotPreview.style.display = "block";
174
+ }
175
+ }
176
+ } catch {
177
+ }
178
+ form.style.display = "flex";
179
+ screenshotBtn.innerHTML = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><path d="m21 15-5-5L5 21"/></svg> Screenshot';
180
+ });
181
+ highlightBtn?.addEventListener("click", async () => {
182
+ if (!opts?.onHighlight) return;
183
+ form.style.display = "none";
184
+ try {
185
+ const annotations = await opts.onHighlight();
186
+ if (annotations && annotations.length > 0) {
187
+ annotationsData = annotations;
188
+ highlightBtn.innerHTML = `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 20h9"/><path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z"/></svg> ${annotations.length} highlighted`;
189
+ }
190
+ } catch {
191
+ }
192
+ form.style.display = "flex";
193
+ });
194
+ submitBtn?.addEventListener("click", () => {
195
+ const title = container.querySelector("#cf-title")?.value;
196
+ const desc = container.querySelector("#cf-desc")?.value;
197
+ const type = container.querySelector("#cf-type")?.value;
198
+ const priority = container.querySelector("#cf-priority")?.value;
199
+ if (!title?.trim()) return;
200
+ onSubmitCallback?.({ title, description: desc, type, priority, screenshot: screenshotDataUrl || void 0, annotations: annotationsData.length > 0 ? annotationsData : void 0 });
201
+ container.querySelector("#cf-title").value = "";
202
+ container.querySelector("#cf-desc").value = "";
203
+ screenshotDataUrl = null;
204
+ annotationsData = [];
205
+ if (screenshotPreview) screenshotPreview.style.display = "none";
206
+ form.style.display = "none";
207
+ showToast("Feedback sent!");
208
+ });
209
+ }
210
+ function unmountWidget() {
211
+ if (container) {
212
+ container.remove();
213
+ container = null;
214
+ }
215
+ }
216
+ function showToast(msg) {
217
+ const toast = document.createElement("div");
218
+ toast.textContent = msg;
219
+ toast.style.cssText = "position:fixed;bottom:80px;right:20px;background:#10b981;color:#fff;padding:8px 16px;border-radius:8px;font-size:13px;z-index:100001;font-family:system-ui;box-shadow:0 2px 8px rgba(0,0,0,.15);";
220
+ document.body.appendChild(toast);
221
+ setTimeout(() => toast.remove(), 3e3);
222
+ }
223
+ function getPositionCSS(pos) {
224
+ switch (pos) {
225
+ case "bottom-left":
226
+ return "bottom:20px;left:20px;";
227
+ case "top-right":
228
+ return "top:20px;right:20px;";
229
+ case "top-left":
230
+ return "top:20px;left:20px;";
231
+ default:
232
+ return "bottom:20px;right:20px;";
233
+ }
234
+ }
235
+ function getFormPositionCSS(pos) {
236
+ switch (pos) {
237
+ case "bottom-left":
238
+ return "bottom:70px;left:20px;";
239
+ case "top-right":
240
+ return "top:70px;right:20px;";
241
+ case "top-left":
242
+ return "top:70px;left:20px;";
243
+ default:
244
+ return "bottom:70px;right:20px;";
245
+ }
246
+ }
247
+ function getWidgetHTML(cfg) {
248
+ const posBtn = getPositionCSS(cfg.position);
249
+ const posForm = getFormPositionCSS(cfg.position);
250
+ return `
251
+ <style>
252
+ #cf-trigger{position:fixed;${posBtn}z-index:100000;background:${cfg.color};color:#fff;border:none;border-radius:50px;padding:10px 18px;font-size:13px;font-family:system-ui,-apple-system,sans-serif;cursor:pointer;box-shadow:0 4px 12px rgba(0,0,0,.15);display:flex;align-items:center;gap:6px;transition:transform .15s}
253
+ #cf-trigger:hover{transform:scale(1.05)}
254
+ #cf-trigger svg{width:16px;height:16px}
255
+ #cf-form{position:fixed;${posForm}z-index:100000;background:#fff;border-radius:12px;box-shadow:0 8px 30px rgba(0,0,0,.12);width:360px;padding:16px;font-family:system-ui,-apple-system,sans-serif;display:none;flex-direction:column;gap:10px}
256
+ #cf-form h3{margin:0;font-size:15px;font-weight:600;color:#111}
257
+ #cf-form input,#cf-form textarea,#cf-form select{width:100%;padding:8px 10px;border:1px solid #e2e8f0;border-radius:8px;font-size:13px;font-family:inherit;box-sizing:border-box;outline:none;transition:border .15s}
258
+ #cf-form input:focus,#cf-form textarea:focus,#cf-form select:focus{border-color:${cfg.color}}
259
+ #cf-form textarea{resize:vertical;min-height:60px}
260
+ .cf-row{display:flex;gap:8px}
261
+ .cf-row select{flex:1}
262
+ .cf-tools{display:flex;gap:6px}
263
+ .cf-tool-btn{display:flex;align-items:center;gap:4px;padding:6px 10px;border:1px solid #e2e8f0;border-radius:6px;background:#f8fafc;color:#475569;font-size:11px;cursor:pointer;font-family:inherit;transition:all .15s}
264
+ .cf-tool-btn:hover{background:#f1f5f9;border-color:#cbd5e1}
265
+ .cf-tool-btn svg{width:14px;height:14px}
266
+ #cf-submit{background:${cfg.color};color:#fff;border:none;border-radius:8px;padding:9px;font-size:13px;font-weight:500;cursor:pointer;transition:opacity .15s}
267
+ #cf-submit:hover{opacity:.9}
268
+ #cf-close{position:absolute;top:10px;right:12px;background:none;border:none;cursor:pointer;font-size:18px;color:#94a3b8;line-height:1}
269
+ #cf-screenshot-preview{display:none;border:1px solid #e2e8f0;border-radius:8px;overflow:hidden;max-height:120px}
270
+ #cf-screenshot-preview img{width:100%;height:auto;display:block}
271
+ </style>
272
+ <button id="cf-trigger">
273
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
274
+ ${cfg.text}
275
+ </button>
276
+ <div id="cf-form">
277
+ <button id="cf-close">&times;</button>
278
+ <h3>Report Feedback</h3>
279
+ <input id="cf-title" type="text" placeholder="Title *" />
280
+ <textarea id="cf-desc" placeholder="Description (optional)"></textarea>
281
+ <div class="cf-row">
282
+ <select id="cf-type">
283
+ <option value="BUG">Bug</option>
284
+ <option value="FEATURE">Feature</option>
285
+ <option value="IMPROVEMENT">Improvement</option>
286
+ <option value="QUESTION">Question</option>
287
+ </select>
288
+ <select id="cf-priority">
289
+ <option value="LOW">Low</option>
290
+ <option value="MEDIUM" selected>Medium</option>
291
+ <option value="HIGH">High</option>
292
+ <option value="CRITICAL">Critical</option>
293
+ </select>
294
+ </div>
295
+ <div class="cf-tools">
296
+ <button type="button" class="cf-tool-btn" id="cf-screenshot">
297
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><path d="m21 15-5-5L5 21"/></svg>
298
+ Screenshot
299
+ </button>
300
+ <button type="button" class="cf-tool-btn" id="cf-highlight">
301
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 20h9"/><path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z"/></svg>
302
+ Highlight
303
+ </button>
304
+ </div>
305
+ <div id="cf-screenshot-preview"><img src="" alt="screenshot" /></div>
306
+ <button id="cf-submit">Send Feedback</button>
307
+ </div>`;
308
+ }
309
+ var DEFAULT_CONFIG, container, onSubmitCallback, screenshotDataUrl, annotationsData;
310
+ var init_widget = __esm({
311
+ "src/widget.ts"() {
312
+ "use strict";
313
+ DEFAULT_CONFIG = {
314
+ position: "bottom-right",
315
+ color: "#1e3a5f",
316
+ text: "Report Bug",
317
+ showOnInit: true
318
+ };
319
+ container = null;
320
+ onSubmitCallback = null;
321
+ screenshotDataUrl = null;
322
+ annotationsData = [];
323
+ }
324
+ });
325
+
326
+ // src/screenshot.ts
327
+ var screenshot_exports = {};
328
+ __export(screenshot_exports, {
329
+ captureScreenshot: () => captureScreenshot,
330
+ clearScreenshot: () => clearScreenshot,
331
+ getLastScreenshot: () => getLastScreenshot,
332
+ loadHtml2Canvas: () => loadHtml2Canvas
333
+ });
334
+ async function captureScreenshot() {
335
+ try {
336
+ if (typeof window.html2canvas === "function") {
337
+ const canvas2 = await window.html2canvas(document.body, {
338
+ useCORS: true,
339
+ allowTaint: true,
340
+ scale: Math.min(window.devicePixelRatio, 2),
341
+ logging: false,
342
+ width: window.innerWidth,
343
+ height: window.innerHeight,
344
+ x: window.scrollX,
345
+ y: window.scrollY
346
+ });
347
+ screenshotData = canvas2.toDataURL("image/png", 0.8);
348
+ return screenshotData;
349
+ }
350
+ const canvas = document.createElement("canvas");
351
+ const ctx = canvas.getContext("2d");
352
+ if (!ctx) return null;
353
+ canvas.width = window.innerWidth;
354
+ canvas.height = window.innerHeight;
355
+ ctx.fillStyle = "#ffffff";
356
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
357
+ ctx.fillStyle = "#333333";
358
+ ctx.font = "14px system-ui";
359
+ ctx.fillText(`Page: ${window.location.href}`, 10, 30);
360
+ ctx.fillText(`Viewport: ${window.innerWidth}x${window.innerHeight}`, 10, 50);
361
+ ctx.fillText(`Screenshot captured at ${(/* @__PURE__ */ new Date()).toISOString()}`, 10, 70);
362
+ const svgData = `
363
+ <svg xmlns="http://www.w3.org/2000/svg" width="${window.innerWidth}" height="${window.innerHeight}">
364
+ <foreignObject width="100%" height="100%">
365
+ <div xmlns="http://www.w3.org/1999/xhtml">
366
+ ${document.documentElement.outerHTML}
367
+ </div>
368
+ </foreignObject>
369
+ </svg>`;
370
+ try {
371
+ const blob = new Blob([svgData], { type: "image/svg+xml;charset=utf-8" });
372
+ const url = URL.createObjectURL(blob);
373
+ const img = new Image();
374
+ await new Promise((resolve, reject) => {
375
+ img.onload = () => resolve();
376
+ img.onerror = () => reject();
377
+ img.src = url;
378
+ });
379
+ ctx.drawImage(img, 0, 0);
380
+ URL.revokeObjectURL(url);
381
+ } catch {
382
+ }
383
+ screenshotData = canvas.toDataURL("image/png", 0.8);
384
+ return screenshotData;
385
+ } catch {
386
+ return null;
387
+ }
388
+ }
389
+ function getLastScreenshot() {
390
+ return screenshotData;
391
+ }
392
+ function clearScreenshot() {
393
+ screenshotData = null;
394
+ }
395
+ function loadHtml2Canvas() {
396
+ return new Promise((resolve, reject) => {
397
+ if (typeof window.html2canvas === "function") {
398
+ resolve();
399
+ return;
400
+ }
401
+ const script = document.createElement("script");
402
+ script.src = "https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js";
403
+ script.onload = () => resolve();
404
+ script.onerror = () => reject(new Error("Failed to load html2canvas"));
405
+ document.head.appendChild(script);
406
+ });
407
+ }
408
+ var screenshotData;
409
+ var init_screenshot = __esm({
410
+ "src/screenshot.ts"() {
411
+ "use strict";
412
+ screenshotData = null;
413
+ }
414
+ });
415
+
416
+ // src/highlighter.ts
417
+ var highlighter_exports = {};
418
+ __export(highlighter_exports, {
419
+ isHighlighting: () => isHighlighting,
420
+ startHighlighting: () => startHighlighting
421
+ });
422
+ function getSelector(el) {
423
+ if (el.id) return `#${el.id}`;
424
+ const parts = [];
425
+ let current = el;
426
+ while (current && current !== document.body) {
427
+ let sel = current.tagName.toLowerCase();
428
+ if (current.id) {
429
+ parts.unshift(`#${current.id}`);
430
+ break;
431
+ }
432
+ if (current.className && typeof current.className === "string") {
433
+ const cls = current.className.trim().split(/\s+/).slice(0, 2).join(".");
434
+ if (cls) sel += `.${cls}`;
435
+ }
436
+ const parent = current.parentElement;
437
+ if (parent) {
438
+ const siblings = Array.from(parent.children).filter((c) => c.tagName === current.tagName);
439
+ if (siblings.length > 1) sel += `:nth-child(${Array.from(parent.children).indexOf(current) + 1})`;
440
+ }
441
+ parts.unshift(sel);
442
+ current = current.parentElement;
443
+ }
444
+ return parts.join(" > ");
445
+ }
446
+ function createOverlay() {
447
+ overlay = document.createElement("div");
448
+ overlay.id = "cf-highlight-overlay";
449
+ overlay.style.cssText = "position:fixed;top:0;left:0;width:100%;height:100%;z-index:99999;cursor:crosshair;";
450
+ const toolbar = document.createElement("div");
451
+ toolbar.style.cssText = "position:fixed;top:12px;left:50%;transform:translateX(-50%);z-index:100002;background:#1e3a5f;color:#fff;padding:8px 16px;border-radius:10px;font-family:system-ui;font-size:13px;display:flex;align-items:center;gap:12px;box-shadow:0 4px 20px rgba(0,0,0,.25);";
452
+ toolbar.innerHTML = `
453
+ <span>Click elements to highlight them</span>
454
+ <button id="cf-hl-done" style="background:#10b981;color:#fff;border:none;border-radius:6px;padding:6px 14px;font-size:12px;cursor:pointer;font-weight:500;">Done (${highlights.length})</button>
455
+ <button id="cf-hl-cancel" style="background:transparent;color:#fff;border:1px solid rgba(255,255,255,.3);border-radius:6px;padding:6px 14px;font-size:12px;cursor:pointer;">Cancel</button>
456
+ `;
457
+ overlay.appendChild(toolbar);
458
+ document.body.appendChild(overlay);
459
+ overlay.addEventListener("click", handleClick);
460
+ overlay.addEventListener("mousemove", handleHover);
461
+ document.getElementById("cf-hl-done")?.addEventListener("click", finishHighlighting);
462
+ document.getElementById("cf-hl-cancel")?.addEventListener("click", cancelHighlighting);
463
+ }
464
+ function handleHover(e) {
465
+ if (!hoverBox) {
466
+ hoverBox = document.createElement("div");
467
+ hoverBox.style.cssText = "position:fixed;border:2px solid #0c66e4;background:rgba(12,102,228,0.08);pointer-events:none;z-index:100001;border-radius:3px;transition:all 0.05s;";
468
+ document.body.appendChild(hoverBox);
469
+ }
470
+ const target = document.elementFromPoint(e.clientX, e.clientY);
471
+ if (target && target !== overlay && !overlay?.contains(target)) {
472
+ const rect = target.getBoundingClientRect();
473
+ hoverBox.style.left = rect.left + "px";
474
+ hoverBox.style.top = rect.top + "px";
475
+ hoverBox.style.width = rect.width + "px";
476
+ hoverBox.style.height = rect.height + "px";
477
+ hoverBox.style.display = "block";
478
+ } else {
479
+ hoverBox.style.display = "none";
480
+ }
481
+ }
482
+ function handleClick(e) {
483
+ e.preventDefault();
484
+ e.stopPropagation();
485
+ const target = document.elementFromPoint(e.clientX, e.clientY);
486
+ if (!target || target === overlay || overlay?.contains(target)) return;
487
+ const rect = target.getBoundingClientRect();
488
+ highlights.push({ el: target, rect });
489
+ const marker = document.createElement("div");
490
+ marker.className = "cf-hl-marker";
491
+ marker.style.cssText = `position:fixed;left:${rect.left}px;top:${rect.top}px;width:${rect.width}px;height:${rect.height}px;border:2px solid #ae2a19;background:rgba(174,42,25,0.12);z-index:100001;pointer-events:none;border-radius:3px;`;
492
+ const badge = document.createElement("div");
493
+ badge.style.cssText = "position:absolute;top:-10px;right:-10px;background:#ae2a19;color:#fff;width:20px;height:20px;border-radius:50%;font-size:11px;display:flex;align-items:center;justify-content:center;font-family:system-ui;font-weight:600;";
494
+ badge.textContent = String(highlights.length);
495
+ marker.appendChild(badge);
496
+ overlay?.appendChild(marker);
497
+ const doneBtn = document.getElementById("cf-hl-done");
498
+ if (doneBtn) doneBtn.textContent = `Done (${highlights.length})`;
499
+ }
500
+ function finishHighlighting() {
501
+ const annotations = highlights.map((h) => ({
502
+ selector: getSelector(h.el),
503
+ tagName: h.el.tagName.toLowerCase(),
504
+ text: h.el.textContent?.slice(0, 100) || void 0,
505
+ rect: { x: Math.round(h.rect.x), y: Math.round(h.rect.y), width: Math.round(h.rect.width), height: Math.round(h.rect.height) },
506
+ note: h.note
507
+ }));
508
+ cleanup();
509
+ onDoneCallback?.(annotations);
510
+ }
511
+ function cancelHighlighting() {
512
+ cleanup();
513
+ onDoneCallback?.([]);
514
+ }
515
+ function cleanup() {
516
+ if (hoverBox) {
517
+ hoverBox.remove();
518
+ hoverBox = null;
519
+ }
520
+ if (overlay) {
521
+ overlay.remove();
522
+ overlay = null;
523
+ }
524
+ highlights = [];
525
+ isActive = false;
526
+ }
527
+ function startHighlighting() {
528
+ return new Promise((resolve) => {
529
+ if (isActive) {
530
+ resolve([]);
531
+ return;
532
+ }
533
+ isActive = true;
534
+ highlights = [];
535
+ onDoneCallback = resolve;
536
+ createOverlay();
537
+ });
538
+ }
539
+ function isHighlighting() {
540
+ return isActive;
541
+ }
542
+ var overlay, highlights, isActive, onDoneCallback, hoverBox;
543
+ var init_highlighter = __esm({
544
+ "src/highlighter.ts"() {
545
+ "use strict";
546
+ overlay = null;
547
+ highlights = [];
548
+ isActive = false;
549
+ onDoneCallback = null;
550
+ hoverBox = null;
551
+ }
552
+ });
553
+
554
+ // src/index.ts
555
+ var index_exports = {};
556
+ __export(index_exports, {
557
+ captureScreenshot: () => captureScreenshot,
558
+ destroy: () => destroy,
559
+ hideWidget: () => hideWidget,
560
+ init: () => init,
561
+ sendFeedback: () => sendFeedback,
562
+ showWidget: () => showWidget,
563
+ startHighlighting: () => startHighlighting
564
+ });
565
+ function init(cfg) {
566
+ config = {
567
+ enabled: true,
568
+ endpoint: DEFAULT_ENDPOINT,
569
+ environment: "production",
570
+ ...cfg
571
+ };
572
+ if (!config.enabled) return;
573
+ installInterceptors();
574
+ if (typeof window !== "undefined") {
575
+ loadHtml2Canvas().catch(() => {
576
+ });
577
+ }
578
+ if (typeof window !== "undefined" && config.widget?.showOnInit !== false) {
579
+ mountWidget(
580
+ config.widget,
581
+ (data) => {
582
+ sendFeedback({
583
+ title: data.title,
584
+ description: data.description,
585
+ type: data.type,
586
+ priority: data.priority,
587
+ screenshot_data: data.screenshot,
588
+ annotations: data.annotations
589
+ });
590
+ },
591
+ {
592
+ onScreenshot: () => captureScreenshot(),
593
+ onHighlight: () => startHighlighting()
594
+ }
595
+ );
596
+ }
597
+ }
598
+ async function sendFeedback(data) {
599
+ if (!config) {
600
+ return { success: false, error: { message: "SDK not initialized. Call init() first.", code: "NOT_INITIALIZED" } };
601
+ }
602
+ const context = typeof window !== "undefined" ? collectContext() : {};
603
+ const perf = typeof window !== "undefined" ? collectPerformance() : void 0;
604
+ const consoleLogs = getConsoleLogs();
605
+ const jsErrors = getJavascriptErrors();
606
+ const payload = {
607
+ ...data,
608
+ ...context,
609
+ environment: config.environment,
610
+ performance_metrics: perf,
611
+ console_logs: consoleLogs.length > 0 ? consoleLogs : void 0,
612
+ javascript_errors: jsErrors.length > 0 ? jsErrors : void 0,
613
+ sdk_version: SDK_VERSION
614
+ };
615
+ if (data.screenshot_data) {
616
+ payload.screenshot_data = data.screenshot_data;
617
+ }
618
+ if (data.annotations && data.annotations.length > 0) {
619
+ payload.annotations = data.annotations;
620
+ }
621
+ try {
622
+ const res = await fetch(`${config.endpoint}/sdk/feedback`, {
623
+ method: "POST",
624
+ headers: {
625
+ "Content-Type": "application/json",
626
+ "X-API-Key": config.apiKey
627
+ },
628
+ body: JSON.stringify(payload)
629
+ });
630
+ const json = await res.json();
631
+ if (!res.ok) {
632
+ return { success: false, error: json.error || { message: "Request failed", code: "REQUEST_FAILED" } };
633
+ }
634
+ return { success: true, data: json.data };
635
+ } catch (err) {
636
+ return { success: false, error: { message: err.message, code: "NETWORK_ERROR" } };
637
+ }
638
+ }
639
+ function showWidget() {
640
+ if (!config) return;
641
+ mountWidget(
642
+ config.widget,
643
+ (data) => {
644
+ sendFeedback({
645
+ title: data.title,
646
+ description: data.description,
647
+ type: data.type,
648
+ priority: data.priority,
649
+ screenshot_data: data.screenshot,
650
+ annotations: data.annotations
651
+ });
652
+ },
653
+ {
654
+ onScreenshot: () => captureScreenshot(),
655
+ onHighlight: () => startHighlighting()
656
+ }
657
+ );
658
+ }
659
+ function hideWidget() {
660
+ unmountWidget();
661
+ }
662
+ function destroy() {
663
+ unmountWidget();
664
+ clearLogs();
665
+ clearScreenshot();
666
+ config = null;
667
+ }
668
+ var SDK_VERSION, DEFAULT_ENDPOINT, config;
669
+ var init_index = __esm({
670
+ "src/index.ts"() {
671
+ "use strict";
672
+ init_collector();
673
+ init_console_interceptor();
674
+ init_widget();
675
+ init_screenshot();
676
+ init_highlighter();
677
+ init_screenshot();
678
+ init_highlighter();
679
+ SDK_VERSION = "1.1.0";
680
+ DEFAULT_ENDPOINT = "https://api.checkflow.space/api/v1";
681
+ config = null;
682
+ }
683
+ });
684
+
685
+ // src/react.ts
686
+ var react_exports = {};
687
+ __export(react_exports, {
688
+ destroyCheckflow: () => destroyCheckflow,
689
+ useCheckflowFeedback: () => useCheckflowFeedback,
690
+ useCheckflowInit: () => useCheckflowInit
691
+ });
692
+ module.exports = __toCommonJS(react_exports);
693
+ var _initialized = false;
694
+ function useCheckflowInit(config2) {
695
+ if (typeof window === "undefined") return;
696
+ if (_initialized) return;
697
+ _initialized = true;
698
+ Promise.resolve().then(() => (init_index(), index_exports)).then(({ init: init2 }) => {
699
+ init2(config2);
700
+ });
701
+ }
702
+ function useCheckflowFeedback() {
703
+ return {
704
+ send: async (data) => {
705
+ if (typeof window === "undefined") return { success: false, error: { message: "Not in browser", code: "SSR" } };
706
+ const { sendFeedback: sendFeedback2 } = await Promise.resolve().then(() => (init_index(), index_exports));
707
+ return sendFeedback2(data);
708
+ },
709
+ screenshot: async () => {
710
+ if (typeof window === "undefined") return null;
711
+ const { captureScreenshot: captureScreenshot2 } = await Promise.resolve().then(() => (init_screenshot(), screenshot_exports));
712
+ return captureScreenshot2();
713
+ },
714
+ highlight: async () => {
715
+ if (typeof window === "undefined") return [];
716
+ const { startHighlighting: startHighlighting2 } = await Promise.resolve().then(() => (init_highlighter(), highlighter_exports));
717
+ return startHighlighting2();
718
+ },
719
+ show: async () => {
720
+ if (typeof window === "undefined") return;
721
+ const { showWidget: showWidget2 } = await Promise.resolve().then(() => (init_index(), index_exports));
722
+ showWidget2();
723
+ },
724
+ hide: async () => {
725
+ if (typeof window === "undefined") return;
726
+ const { hideWidget: hideWidget2 } = await Promise.resolve().then(() => (init_index(), index_exports));
727
+ hideWidget2();
728
+ }
729
+ };
730
+ }
731
+ function destroyCheckflow() {
732
+ if (typeof window === "undefined") return;
733
+ Promise.resolve().then(() => (init_index(), index_exports)).then(({ destroy: destroy2 }) => {
734
+ destroy2();
735
+ _initialized = false;
736
+ });
737
+ }
738
+ // Annotate the CommonJS export names for ESM import in node:
739
+ 0 && (module.exports = {
740
+ destroyCheckflow,
741
+ useCheckflowFeedback,
742
+ useCheckflowInit
743
+ });