@checkflow/sdk 1.1.1 → 1.1.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.
Files changed (46) hide show
  1. package/README.md +63 -219
  2. package/dist/chunk-6EVTRC5X.mjs +59 -0
  3. package/dist/chunk-CD33QAA6.mjs +131 -0
  4. package/dist/highlighter-Dx2zURb6.d.mts +73 -0
  5. package/dist/highlighter-Dx2zURb6.d.ts +73 -0
  6. package/dist/highlighter-W4XDALRE.mjs +8 -0
  7. package/dist/index.d.mts +46 -0
  8. package/dist/index.d.ts +43 -20
  9. package/dist/index.js +974 -17219
  10. package/dist/index.mjs +802 -0
  11. package/dist/react.d.mts +28 -0
  12. package/dist/react.d.ts +28 -0
  13. package/dist/react.js +1118 -0
  14. package/dist/react.mjs +51 -0
  15. package/dist/screenshot-HXKGZNCZ.mjs +10 -0
  16. package/dist/vue.d.mts +26 -0
  17. package/dist/vue.d.ts +26 -0
  18. package/dist/vue.js +1119 -0
  19. package/dist/vue.mjs +53 -0
  20. package/package.json +38 -53
  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/optimized-recorder.d.ts +0 -94
  36. package/dist/privacy/detector.d.ts +0 -56
  37. package/dist/privacy/index.d.ts +0 -8
  38. package/dist/privacy/masker.d.ts +0 -43
  39. package/dist/privacy/types.d.ts +0 -54
  40. package/dist/react/index.d.ts +0 -77
  41. package/dist/session-recording-rrweb.d.ts +0 -100
  42. package/dist/session-recording.d.ts +0 -74
  43. package/dist/types.d.ts +0 -299
  44. package/dist/vue/index.d.ts +0 -55
  45. package/dist/widget/Widget.d.ts +0 -98
  46. package/dist/widget/index.d.ts +0 -2
package/dist/vue.js ADDED
@@ -0,0 +1,1119 @@
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/network-interceptor.ts
139
+ function installNetworkInterceptor() {
140
+ if (installed2 || typeof window === "undefined") return;
141
+ installed2 = true;
142
+ const origFetch = window.fetch;
143
+ window.fetch = async function(...args) {
144
+ const start = Date.now();
145
+ const req = new Request(...args);
146
+ const entry = {
147
+ method: req.method,
148
+ url: req.url,
149
+ type: "fetch",
150
+ timestamp: start
151
+ };
152
+ try {
153
+ const res = await origFetch.apply(this, args);
154
+ entry.status = res.status;
155
+ entry.duration = Date.now() - start;
156
+ entry.response_type = res.headers.get("content-type") || void 0;
157
+ pushLog(entry);
158
+ return res;
159
+ } catch (err) {
160
+ entry.duration = Date.now() - start;
161
+ entry.error = err.message || "Network error";
162
+ pushLog(entry);
163
+ throw err;
164
+ }
165
+ };
166
+ const origOpen = XMLHttpRequest.prototype.open;
167
+ const origSend = XMLHttpRequest.prototype.send;
168
+ XMLHttpRequest.prototype.open = function(method, url, ...rest) {
169
+ this.__cf_method = method;
170
+ this.__cf_url = String(url);
171
+ return origOpen.apply(this, [method, url, ...rest]);
172
+ };
173
+ XMLHttpRequest.prototype.send = function(...args) {
174
+ const start = Date.now();
175
+ const xhr = this;
176
+ xhr.addEventListener("loadend", () => {
177
+ const entry = {
178
+ method: xhr.__cf_method || "GET",
179
+ url: xhr.__cf_url || "",
180
+ status: xhr.status,
181
+ duration: Date.now() - start,
182
+ type: "xhr",
183
+ timestamp: start,
184
+ response_type: xhr.getResponseHeader("content-type") || void 0
185
+ };
186
+ if (xhr.status === 0) entry.error = "Request failed";
187
+ pushLog(entry);
188
+ });
189
+ return origSend.apply(this, args);
190
+ };
191
+ }
192
+ function pushLog(entry) {
193
+ if (entry.url.includes("/sdk/feedback")) return;
194
+ logs2.push(entry);
195
+ if (logs2.length > MAX_LOGS2) logs2.shift();
196
+ }
197
+ function getNetworkLogs() {
198
+ return [...logs2];
199
+ }
200
+ function clearNetworkLogs() {
201
+ logs2 = [];
202
+ }
203
+ var MAX_LOGS2, logs2, installed2;
204
+ var init_network_interceptor = __esm({
205
+ "src/network-interceptor.ts"() {
206
+ "use strict";
207
+ MAX_LOGS2 = 50;
208
+ logs2 = [];
209
+ installed2 = false;
210
+ }
211
+ });
212
+
213
+ // src/widget.ts
214
+ function mountWidget(config2 = {}, onSubmit, opts) {
215
+ if (container) return;
216
+ onSubmitCallback = onSubmit;
217
+ const cfg = { ...DEFAULT_CONFIG, ...config2 };
218
+ container = document.createElement("div");
219
+ container.id = "checkflow-widget";
220
+ injectStyles(cfg);
221
+ container.innerHTML = getTriggerHTML(cfg);
222
+ document.body.appendChild(container);
223
+ const btn = container.querySelector("#cf-trigger");
224
+ btn?.addEventListener("click", () => openModal(cfg, opts));
225
+ }
226
+ function openModal(cfg, opts) {
227
+ if (!container) return;
228
+ const existing = document.getElementById("cf-modal-backdrop");
229
+ if (existing) existing.remove();
230
+ isExpanded = false;
231
+ screenshotDataUrl = null;
232
+ annotationsData = [];
233
+ const backdrop = document.createElement("div");
234
+ backdrop.id = "cf-modal-backdrop";
235
+ backdrop.innerHTML = getModalHTML(cfg, false);
236
+ document.body.appendChild(backdrop);
237
+ backdrop.addEventListener("click", (e) => {
238
+ if (e.target === backdrop) closeModal();
239
+ });
240
+ bindModalEvents(cfg, opts);
241
+ }
242
+ function closeModal() {
243
+ const backdrop = document.getElementById("cf-modal-backdrop");
244
+ if (backdrop) backdrop.remove();
245
+ isExpanded = false;
246
+ screenshotDataUrl = null;
247
+ annotationsData = [];
248
+ }
249
+ function expandModal(cfg, opts) {
250
+ const backdrop = document.getElementById("cf-modal-backdrop");
251
+ if (!backdrop) return;
252
+ const name = backdrop.querySelector("#cf-name")?.value || "";
253
+ const email = backdrop.querySelector("#cf-email")?.value || "";
254
+ const desc = backdrop.querySelector("#cf-desc")?.value || "";
255
+ isExpanded = true;
256
+ backdrop.innerHTML = getModalHTML(cfg, true);
257
+ bindModalEvents(cfg, opts);
258
+ const nameEl = backdrop.querySelector("#cf-name");
259
+ const emailEl = backdrop.querySelector("#cf-email");
260
+ const descEl = backdrop.querySelector("#cf-desc");
261
+ if (nameEl) nameEl.value = name;
262
+ if (emailEl) emailEl.value = email;
263
+ if (descEl) descEl.value = desc;
264
+ }
265
+ function collapseModal(cfg, opts) {
266
+ const backdrop = document.getElementById("cf-modal-backdrop");
267
+ if (!backdrop) return;
268
+ const name = backdrop.querySelector("#cf-name")?.value || "";
269
+ const email = backdrop.querySelector("#cf-email")?.value || "";
270
+ const desc = backdrop.querySelector("#cf-desc")?.value || "";
271
+ isExpanded = false;
272
+ screenshotDataUrl = null;
273
+ annotationsData = [];
274
+ backdrop.innerHTML = getModalHTML(cfg, false);
275
+ bindModalEvents(cfg, opts);
276
+ const nameEl = backdrop.querySelector("#cf-name");
277
+ const emailEl = backdrop.querySelector("#cf-email");
278
+ const descEl = backdrop.querySelector("#cf-desc");
279
+ if (nameEl) nameEl.value = name;
280
+ if (emailEl) emailEl.value = email;
281
+ if (descEl) descEl.value = desc;
282
+ }
283
+ function bindModalEvents(cfg, opts) {
284
+ const backdrop = document.getElementById("cf-modal-backdrop");
285
+ if (!backdrop) return;
286
+ backdrop.querySelector("#cf-cancel")?.addEventListener("click", closeModal);
287
+ backdrop.querySelector("#cf-screenshot-btn")?.addEventListener("click", async () => {
288
+ if (!opts?.onScreenshot) return;
289
+ backdrop.style.display = "none";
290
+ try {
291
+ const data = await opts.onScreenshot();
292
+ if (data) {
293
+ screenshotDataUrl = data;
294
+ backdrop.style.display = "flex";
295
+ expandModal(cfg, opts);
296
+ return;
297
+ }
298
+ } catch {
299
+ }
300
+ backdrop.style.display = "flex";
301
+ });
302
+ backdrop.querySelector("#cf-remove-screenshot")?.addEventListener("click", () => {
303
+ collapseModal(cfg, opts);
304
+ });
305
+ backdrop.querySelector("#cf-highlight-btn")?.addEventListener("click", async () => {
306
+ if (!opts?.onHighlight) return;
307
+ backdrop.style.display = "none";
308
+ try {
309
+ const annotations = await opts.onHighlight();
310
+ if (annotations && annotations.length > 0) {
311
+ annotationsData = annotations;
312
+ }
313
+ } catch {
314
+ }
315
+ backdrop.style.display = "flex";
316
+ const hlBtn = backdrop.querySelector("#cf-highlight-btn");
317
+ if (hlBtn && annotationsData.length > 0) {
318
+ hlBtn.textContent = `Surligner (${annotationsData.length})`;
319
+ }
320
+ });
321
+ backdrop.querySelector("#cf-mask-btn")?.addEventListener("click", async () => {
322
+ if (!opts?.onHighlight) return;
323
+ backdrop.style.display = "none";
324
+ try {
325
+ const annotations = await opts.onHighlight();
326
+ if (annotations && annotations.length > 0) {
327
+ annotationsData = [...annotationsData, ...annotations];
328
+ }
329
+ } catch {
330
+ }
331
+ backdrop.style.display = "flex";
332
+ });
333
+ backdrop.querySelector("#cf-submit")?.addEventListener("click", () => {
334
+ const desc = backdrop.querySelector("#cf-desc")?.value;
335
+ const name = backdrop.querySelector("#cf-name")?.value;
336
+ const email = backdrop.querySelector("#cf-email")?.value;
337
+ if (!desc?.trim()) {
338
+ const descEl = backdrop.querySelector("#cf-desc");
339
+ if (descEl) {
340
+ descEl.style.borderColor = "#e74c3c";
341
+ descEl.focus();
342
+ }
343
+ return;
344
+ }
345
+ onSubmitCallback?.({
346
+ title: desc.trim().slice(0, 100),
347
+ description: desc.trim(),
348
+ type: "BUG",
349
+ priority: "MEDIUM",
350
+ screenshot: screenshotDataUrl || void 0,
351
+ annotations: annotationsData.length > 0 ? annotationsData : void 0,
352
+ reporter_name: name?.trim() || void 0,
353
+ reporter_email: email?.trim() || void 0
354
+ });
355
+ closeModal();
356
+ showToast("Rapport envoy\xE9 avec succ\xE8s !");
357
+ });
358
+ }
359
+ function unmountWidget() {
360
+ closeModal();
361
+ if (container) {
362
+ container.remove();
363
+ container = null;
364
+ }
365
+ }
366
+ function showToast(msg) {
367
+ const toast = document.createElement("div");
368
+ toast.textContent = msg;
369
+ toast.style.cssText = 'position:fixed;bottom:80px;right:20px;background:#10b981;color:#fff;padding:10px 20px;border-radius:10px;font-size:14px;z-index:100010;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;box-shadow:0 4px 16px rgba(0,0,0,.18);animation:cf-toast-in .3s ease;';
370
+ document.body.appendChild(toast);
371
+ setTimeout(() => {
372
+ toast.style.opacity = "0";
373
+ toast.style.transition = "opacity .3s";
374
+ }, 2500);
375
+ setTimeout(() => toast.remove(), 3e3);
376
+ }
377
+ function injectStyles(cfg) {
378
+ const style = document.createElement("style");
379
+ style.id = "cf-widget-styles";
380
+ style.textContent = `
381
+ @keyframes cf-toast-in { from { opacity:0; transform:translateY(10px); } to { opacity:1; transform:translateY(0); } }
382
+ @keyframes cf-modal-in { from { opacity:0; transform:scale(.96) translateY(8px); } to { opacity:1; transform:scale(1) translateY(0); } }
383
+
384
+ #cf-trigger {
385
+ position:fixed;
386
+ ${getPositionCSS(cfg.position)}
387
+ z-index:100000;
388
+ background:${cfg.color};
389
+ color:#fff;
390
+ border:none;
391
+ border-radius:50px;
392
+ padding:11px 20px;
393
+ font-size:14px;
394
+ font-weight:500;
395
+ font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;
396
+ cursor:pointer;
397
+ box-shadow:0 4px 16px rgba(0,0,0,.18);
398
+ display:flex;
399
+ align-items:center;
400
+ gap:8px;
401
+ transition:transform .15s,box-shadow .15s;
402
+ }
403
+ #cf-trigger:hover { transform:scale(1.04); box-shadow:0 6px 24px rgba(0,0,0,.22); }
404
+ #cf-trigger svg { width:18px; height:18px; }
405
+
406
+ #cf-modal-backdrop {
407
+ position:fixed;
408
+ top:0;left:0;right:0;bottom:0;
409
+ background:rgba(0,0,0,.45);
410
+ z-index:100001;
411
+ display:flex;
412
+ align-items:center;
413
+ justify-content:center;
414
+ font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;
415
+ }
416
+
417
+ .cf-modal {
418
+ background:#fff;
419
+ border-radius:16px;
420
+ box-shadow:0 24px 80px rgba(0,0,0,.25);
421
+ overflow:hidden;
422
+ animation:cf-modal-in .25s ease;
423
+ display:flex;
424
+ flex-direction:column;
425
+ max-height:90vh;
426
+ }
427
+ .cf-modal--compact { width:420px; }
428
+ .cf-modal--expanded { width:min(1100px,92vw); flex-direction:column; }
429
+
430
+ .cf-modal-header {
431
+ display:flex;
432
+ align-items:center;
433
+ justify-content:space-between;
434
+ padding:20px 24px 16px;
435
+ border-bottom:1px solid #f0f0f0;
436
+ }
437
+ .cf-modal-header h2 {
438
+ margin:0;
439
+ font-size:20px;
440
+ font-weight:700;
441
+ color:#1a1a2e;
442
+ }
443
+ .cf-modal-header .cf-logo {
444
+ width:28px;
445
+ height:28px;
446
+ color:${cfg.color};
447
+ }
448
+
449
+ .cf-modal-body { display:flex; flex:1; overflow:hidden; }
450
+
451
+ .cf-screenshot-panel {
452
+ flex:1;
453
+ min-width:0;
454
+ background:#1a1a2e;
455
+ display:flex;
456
+ flex-direction:column;
457
+ position:relative;
458
+ }
459
+ .cf-screenshot-panel img {
460
+ width:100%;
461
+ height:100%;
462
+ object-fit:contain;
463
+ max-height:60vh;
464
+ }
465
+ .cf-screenshot-tools {
466
+ position:absolute;
467
+ bottom:16px;
468
+ left:50%;
469
+ transform:translateX(-50%);
470
+ display:flex;
471
+ gap:8px;
472
+ }
473
+ .cf-screenshot-tools button {
474
+ padding:8px 18px;
475
+ border-radius:8px;
476
+ font-size:13px;
477
+ font-weight:500;
478
+ cursor:pointer;
479
+ font-family:inherit;
480
+ border:none;
481
+ transition:all .15s;
482
+ }
483
+ .cf-tool-highlight {
484
+ background:${cfg.color};
485
+ color:#fff;
486
+ }
487
+ .cf-tool-highlight:hover { opacity:.9; }
488
+ .cf-tool-mask {
489
+ background:#fff;
490
+ color:#1a1a2e;
491
+ border:1px solid #e0e0e0 !important;
492
+ }
493
+ .cf-tool-mask:hover { background:#f5f5f5; }
494
+
495
+ .cf-form-panel {
496
+ width:100%;
497
+ padding:20px 24px;
498
+ display:flex;
499
+ flex-direction:column;
500
+ gap:14px;
501
+ overflow-y:auto;
502
+ }
503
+ .cf-modal--expanded .cf-form-panel {
504
+ width:340px;
505
+ flex-shrink:0;
506
+ border-left:1px solid #f0f0f0;
507
+ }
508
+
509
+ .cf-field label {
510
+ display:block;
511
+ font-size:13px;
512
+ font-weight:500;
513
+ color:#1a1a2e;
514
+ margin-bottom:6px;
515
+ }
516
+ .cf-field label span { font-weight:400; color:#999; }
517
+ .cf-field input, .cf-field textarea {
518
+ width:100%;
519
+ padding:10px 14px;
520
+ border:1px solid #e0e0e0;
521
+ border-radius:10px;
522
+ font-size:14px;
523
+ font-family:inherit;
524
+ box-sizing:border-box;
525
+ outline:none;
526
+ transition:border-color .15s,box-shadow .15s;
527
+ color:#1a1a2e;
528
+ background:#fff;
529
+ }
530
+ .cf-field input::placeholder, .cf-field textarea::placeholder { color:#bbb; }
531
+ .cf-field input:focus, .cf-field textarea:focus {
532
+ border-color:${cfg.color};
533
+ box-shadow:0 0 0 3px ${cfg.color}18;
534
+ }
535
+ .cf-field textarea { resize:vertical; min-height:100px; }
536
+
537
+ .cf-screenshot-action {
538
+ width:100%;
539
+ padding:12px;
540
+ border:1px solid #e0e0e0;
541
+ border-radius:10px;
542
+ background:#fff;
543
+ font-size:14px;
544
+ color:#1a1a2e;
545
+ cursor:pointer;
546
+ font-family:inherit;
547
+ transition:all .15s;
548
+ text-align:center;
549
+ }
550
+ .cf-screenshot-action:hover { background:#f8f8f8; border-color:#ccc; }
551
+
552
+ .cf-remove-screenshot {
553
+ width:100%;
554
+ padding:10px;
555
+ border:1px solid #e0e0e0;
556
+ border-radius:10px;
557
+ background:#fff;
558
+ font-size:13px;
559
+ color:#666;
560
+ cursor:pointer;
561
+ font-family:inherit;
562
+ transition:all .15s;
563
+ text-align:center;
564
+ }
565
+ .cf-remove-screenshot:hover { background:#fff0f0; color:#e74c3c; border-color:#e74c3c; }
566
+
567
+ .cf-submit-btn {
568
+ width:100%;
569
+ padding:13px;
570
+ border:none;
571
+ border-radius:10px;
572
+ background:${cfg.color};
573
+ color:#fff;
574
+ font-size:15px;
575
+ font-weight:600;
576
+ cursor:pointer;
577
+ font-family:inherit;
578
+ transition:all .15s;
579
+ }
580
+ .cf-submit-btn:hover { opacity:.92; transform:translateY(-1px); box-shadow:0 4px 12px ${cfg.color}40; }
581
+ .cf-submit-btn:disabled { opacity:.5; cursor:not-allowed; transform:none; }
582
+
583
+ .cf-cancel-btn {
584
+ width:100%;
585
+ padding:11px;
586
+ border:1px solid #e0e0e0;
587
+ border-radius:10px;
588
+ background:#fff;
589
+ color:#1a1a2e;
590
+ font-size:14px;
591
+ font-weight:500;
592
+ cursor:pointer;
593
+ font-family:inherit;
594
+ transition:all .15s;
595
+ text-align:center;
596
+ }
597
+ .cf-cancel-btn:hover { background:#f8f8f8; }
598
+
599
+ .cf-footer {
600
+ text-align:center;
601
+ padding:12px;
602
+ border-top:1px solid #f0f0f0;
603
+ font-size:11px;
604
+ color:#bbb;
605
+ }
606
+ .cf-footer a {
607
+ color:#999;
608
+ text-decoration:none;
609
+ font-weight:500;
610
+ }
611
+ .cf-footer a:hover { color:${cfg.color}; }
612
+ `;
613
+ document.head.appendChild(style);
614
+ }
615
+ function getPositionCSS(pos) {
616
+ switch (pos) {
617
+ case "bottom-left":
618
+ return "bottom:20px;left:20px;";
619
+ case "top-right":
620
+ return "top:20px;right:20px;";
621
+ case "top-left":
622
+ return "top:20px;left:20px;";
623
+ default:
624
+ return "bottom:20px;right:20px;";
625
+ }
626
+ }
627
+ function getTriggerHTML(cfg) {
628
+ return `
629
+ <button id="cf-trigger">
630
+ <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>
631
+ ${cfg.text}
632
+ </button>
633
+ `;
634
+ }
635
+ function getCheckflowLogo() {
636
+ return `<svg class="cf-logo" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M2 12C2 6.5 6.5 2 12 2a10 10 0 0 1 8 4"/><path d="M5 19.5C5.5 18 6 15 6 12c0-.7.12-1.37.34-2"/><path d="M17.29 21.02c.12-.6.43-2.3.5-3.02"/><path d="M12 10a2 2 0 0 0-2 2c0 1.02-.1 2.51-.26 4"/><path d="M8.65 22c.21-.66.45-1.32.57-2"/><path d="M14 13.12c0 2.38 0 6.38-1 8.88"/><path d="M2 16h.01"/><path d="M21.8 16c.2-2 .131-5.354 0-6"/><path d="M9 6.8a6 6 0 0 1 9 5.2v2"/></svg>`;
637
+ }
638
+ function getModalHTML(cfg, expanded) {
639
+ const modalClass = expanded ? "cf-modal cf-modal--expanded" : "cf-modal cf-modal--compact";
640
+ const formFields = `
641
+ <div class="cf-field">
642
+ <label>Nom <span>(obligatoire)</span></label>
643
+ <input id="cf-name" type="text" placeholder="Votre nom" />
644
+ </div>
645
+ <div class="cf-field">
646
+ <label>Email <span>(obligatoire)</span></label>
647
+ <input id="cf-email" type="email" placeholder="votre.email@exemple.com" />
648
+ </div>
649
+ <div class="cf-field">
650
+ <label>Description <span>(obligatoire)</span></label>
651
+ <textarea id="cf-desc" placeholder="Quel est le probl\xE8me ? Que vous attendiez-vous \xE0 voir ?"></textarea>
652
+ </div>
653
+ `;
654
+ if (expanded && screenshotDataUrl) {
655
+ return `
656
+ <div class="${modalClass}">
657
+ <div class="cf-modal-header">
658
+ <h2>Envoyer le rapport</h2>
659
+ ${getCheckflowLogo()}
660
+ </div>
661
+ <div class="cf-modal-body">
662
+ <div class="cf-screenshot-panel">
663
+ <img src="${screenshotDataUrl}" alt="Capture d'\xE9cran" />
664
+ <div class="cf-screenshot-tools">
665
+ <button class="cf-tool-highlight" id="cf-highlight-btn">Surligner</button>
666
+ <button class="cf-tool-mask" id="cf-mask-btn">Masquer</button>
667
+ </div>
668
+ </div>
669
+ <div class="cf-form-panel">
670
+ ${formFields}
671
+ <button class="cf-remove-screenshot" id="cf-remove-screenshot">Supprimer la capture d'\xE9cran</button>
672
+ <button class="cf-submit-btn" id="cf-submit">Envoyer le rapport</button>
673
+ <button class="cf-cancel-btn" id="cf-cancel">Annuler</button>
674
+ </div>
675
+ </div>
676
+ <div class="cf-footer">Powered by <a href="https://checkflow.space" target="_blank" rel="noopener">Checkflow</a></div>
677
+ </div>
678
+ `;
679
+ }
680
+ return `
681
+ <div class="${modalClass}">
682
+ <div class="cf-modal-header">
683
+ <h2>Envoyer le rapport</h2>
684
+ ${getCheckflowLogo()}
685
+ </div>
686
+ <div class="cf-form-panel">
687
+ ${formFields}
688
+ <button class="cf-screenshot-action" id="cf-screenshot-btn">Ajouter une capture d'\xE9cran</button>
689
+ <button class="cf-submit-btn" id="cf-submit">Envoyer le rapport</button>
690
+ <button class="cf-cancel-btn" id="cf-cancel">Annuler</button>
691
+ </div>
692
+ <div class="cf-footer">Powered by <a href="https://checkflow.space" target="_blank" rel="noopener">Checkflow</a></div>
693
+ </div>
694
+ `;
695
+ }
696
+ var DEFAULT_CONFIG, container, onSubmitCallback, screenshotDataUrl, annotationsData, isExpanded;
697
+ var init_widget = __esm({
698
+ "src/widget.ts"() {
699
+ "use strict";
700
+ DEFAULT_CONFIG = {
701
+ position: "bottom-right",
702
+ color: "#1e3a5f",
703
+ text: "Report Bug",
704
+ showOnInit: true
705
+ };
706
+ container = null;
707
+ onSubmitCallback = null;
708
+ screenshotDataUrl = null;
709
+ annotationsData = [];
710
+ isExpanded = false;
711
+ }
712
+ });
713
+
714
+ // src/screenshot.ts
715
+ var screenshot_exports = {};
716
+ __export(screenshot_exports, {
717
+ captureScreenshot: () => captureScreenshot,
718
+ clearScreenshot: () => clearScreenshot,
719
+ getLastScreenshot: () => getLastScreenshot
720
+ });
721
+ async function captureScreenshot() {
722
+ try {
723
+ const stream = await navigator.mediaDevices.getDisplayMedia({
724
+ video: { displaySurface: "browser" },
725
+ preferCurrentTab: true
726
+ });
727
+ const track = stream.getVideoTracks()[0];
728
+ const imageCapture = new window.ImageCapture(track);
729
+ await new Promise((r) => setTimeout(r, 300));
730
+ let bitmap;
731
+ try {
732
+ bitmap = await imageCapture.grabFrame();
733
+ } catch {
734
+ const video = document.createElement("video");
735
+ video.srcObject = stream;
736
+ video.autoplay = true;
737
+ await new Promise((resolve) => {
738
+ video.onloadedmetadata = () => {
739
+ video.play();
740
+ resolve();
741
+ };
742
+ });
743
+ await new Promise((r) => setTimeout(r, 200));
744
+ const canvas2 = document.createElement("canvas");
745
+ canvas2.width = video.videoWidth;
746
+ canvas2.height = video.videoHeight;
747
+ const ctx2 = canvas2.getContext("2d");
748
+ ctx2.drawImage(video, 0, 0);
749
+ track.stop();
750
+ screenshotData = canvas2.toDataURL("image/png", 0.92);
751
+ return screenshotData;
752
+ }
753
+ const canvas = document.createElement("canvas");
754
+ canvas.width = bitmap.width;
755
+ canvas.height = bitmap.height;
756
+ const ctx = canvas.getContext("2d");
757
+ ctx.drawImage(bitmap, 0, 0);
758
+ bitmap.close();
759
+ track.stop();
760
+ screenshotData = canvas.toDataURL("image/png", 0.92);
761
+ return screenshotData;
762
+ } catch {
763
+ return null;
764
+ }
765
+ }
766
+ function getLastScreenshot() {
767
+ return screenshotData;
768
+ }
769
+ function clearScreenshot() {
770
+ screenshotData = null;
771
+ }
772
+ var screenshotData;
773
+ var init_screenshot = __esm({
774
+ "src/screenshot.ts"() {
775
+ "use strict";
776
+ screenshotData = null;
777
+ }
778
+ });
779
+
780
+ // src/highlighter.ts
781
+ var highlighter_exports = {};
782
+ __export(highlighter_exports, {
783
+ isHighlighting: () => isHighlighting,
784
+ startHighlighting: () => startHighlighting
785
+ });
786
+ function getSelector(el) {
787
+ if (el.id) return `#${el.id}`;
788
+ const parts = [];
789
+ let current = el;
790
+ while (current && current !== document.body) {
791
+ let sel = current.tagName.toLowerCase();
792
+ if (current.id) {
793
+ parts.unshift(`#${current.id}`);
794
+ break;
795
+ }
796
+ if (current.className && typeof current.className === "string") {
797
+ const cls = current.className.trim().split(/\s+/).slice(0, 2).join(".");
798
+ if (cls) sel += `.${cls}`;
799
+ }
800
+ const parent = current.parentElement;
801
+ if (parent) {
802
+ const siblings = Array.from(parent.children).filter((c) => c.tagName === current.tagName);
803
+ if (siblings.length > 1) sel += `:nth-child(${Array.from(parent.children).indexOf(current) + 1})`;
804
+ }
805
+ parts.unshift(sel);
806
+ current = current.parentElement;
807
+ }
808
+ return parts.join(" > ");
809
+ }
810
+ function createOverlay() {
811
+ overlay = document.createElement("div");
812
+ overlay.id = "cf-highlight-overlay";
813
+ overlay.style.cssText = "position:fixed;top:0;left:0;width:100%;height:100%;z-index:99999;cursor:crosshair;";
814
+ const toolbar = document.createElement("div");
815
+ 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);";
816
+ toolbar.innerHTML = `
817
+ <span>Click elements to highlight them</span>
818
+ <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>
819
+ <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>
820
+ `;
821
+ overlay.appendChild(toolbar);
822
+ document.body.appendChild(overlay);
823
+ overlay.addEventListener("click", handleClick);
824
+ overlay.addEventListener("mousemove", handleHover);
825
+ document.getElementById("cf-hl-done")?.addEventListener("click", finishHighlighting);
826
+ document.getElementById("cf-hl-cancel")?.addEventListener("click", cancelHighlighting);
827
+ }
828
+ function handleHover(e) {
829
+ if (!hoverBox) {
830
+ hoverBox = document.createElement("div");
831
+ 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;";
832
+ document.body.appendChild(hoverBox);
833
+ }
834
+ const target = document.elementFromPoint(e.clientX, e.clientY);
835
+ if (target && target !== overlay && !overlay?.contains(target)) {
836
+ const rect = target.getBoundingClientRect();
837
+ hoverBox.style.left = rect.left + "px";
838
+ hoverBox.style.top = rect.top + "px";
839
+ hoverBox.style.width = rect.width + "px";
840
+ hoverBox.style.height = rect.height + "px";
841
+ hoverBox.style.display = "block";
842
+ } else {
843
+ hoverBox.style.display = "none";
844
+ }
845
+ }
846
+ function handleClick(e) {
847
+ e.preventDefault();
848
+ e.stopPropagation();
849
+ const target = document.elementFromPoint(e.clientX, e.clientY);
850
+ if (!target || target === overlay || overlay?.contains(target)) return;
851
+ const rect = target.getBoundingClientRect();
852
+ highlights.push({ el: target, rect });
853
+ const marker = document.createElement("div");
854
+ marker.className = "cf-hl-marker";
855
+ 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;`;
856
+ const badge = document.createElement("div");
857
+ 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;";
858
+ badge.textContent = String(highlights.length);
859
+ marker.appendChild(badge);
860
+ overlay?.appendChild(marker);
861
+ const doneBtn = document.getElementById("cf-hl-done");
862
+ if (doneBtn) doneBtn.textContent = `Done (${highlights.length})`;
863
+ }
864
+ function finishHighlighting() {
865
+ const annotations = highlights.map((h) => ({
866
+ selector: getSelector(h.el),
867
+ tagName: h.el.tagName.toLowerCase(),
868
+ text: h.el.textContent?.slice(0, 100) || void 0,
869
+ 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) },
870
+ note: h.note
871
+ }));
872
+ cleanup();
873
+ onDoneCallback?.(annotations);
874
+ }
875
+ function cancelHighlighting() {
876
+ cleanup();
877
+ onDoneCallback?.([]);
878
+ }
879
+ function cleanup() {
880
+ if (hoverBox) {
881
+ hoverBox.remove();
882
+ hoverBox = null;
883
+ }
884
+ if (overlay) {
885
+ overlay.remove();
886
+ overlay = null;
887
+ }
888
+ highlights = [];
889
+ isActive = false;
890
+ }
891
+ function startHighlighting() {
892
+ return new Promise((resolve) => {
893
+ if (isActive) {
894
+ resolve([]);
895
+ return;
896
+ }
897
+ isActive = true;
898
+ highlights = [];
899
+ onDoneCallback = resolve;
900
+ createOverlay();
901
+ });
902
+ }
903
+ function isHighlighting() {
904
+ return isActive;
905
+ }
906
+ var overlay, highlights, isActive, onDoneCallback, hoverBox;
907
+ var init_highlighter = __esm({
908
+ "src/highlighter.ts"() {
909
+ "use strict";
910
+ overlay = null;
911
+ highlights = [];
912
+ isActive = false;
913
+ onDoneCallback = null;
914
+ hoverBox = null;
915
+ }
916
+ });
917
+
918
+ // src/index.ts
919
+ var index_exports = {};
920
+ __export(index_exports, {
921
+ captureScreenshot: () => captureScreenshot,
922
+ destroy: () => destroy,
923
+ hideWidget: () => hideWidget,
924
+ init: () => init,
925
+ sendFeedback: () => sendFeedback,
926
+ showWidget: () => showWidget,
927
+ startHighlighting: () => startHighlighting
928
+ });
929
+ function init(cfg) {
930
+ config = {
931
+ enabled: true,
932
+ endpoint: DEFAULT_ENDPOINT,
933
+ environment: "production",
934
+ ...cfg
935
+ };
936
+ if (!config.enabled) return;
937
+ installInterceptors();
938
+ installNetworkInterceptor();
939
+ if (typeof window !== "undefined" && config.widget?.showOnInit !== false) {
940
+ mountWidget(
941
+ config.widget,
942
+ (data) => {
943
+ sendFeedback({
944
+ title: data.title,
945
+ description: data.description,
946
+ type: data.type,
947
+ priority: data.priority,
948
+ screenshot_data: data.screenshot,
949
+ annotations: data.annotations,
950
+ reporter_name: data.reporter_name,
951
+ reporter_email: data.reporter_email
952
+ });
953
+ },
954
+ {
955
+ onScreenshot: () => captureScreenshot(),
956
+ onHighlight: () => startHighlighting()
957
+ }
958
+ );
959
+ }
960
+ }
961
+ async function sendFeedback(data) {
962
+ if (!config) {
963
+ return { success: false, error: { message: "SDK not initialized. Call init() first.", code: "NOT_INITIALIZED" } };
964
+ }
965
+ const context = typeof window !== "undefined" ? collectContext() : {};
966
+ const perf = typeof window !== "undefined" ? collectPerformance() : void 0;
967
+ const consoleLogs = getConsoleLogs();
968
+ const jsErrors = getJavascriptErrors();
969
+ const networkLogs = getNetworkLogs();
970
+ const payload = {
971
+ ...data,
972
+ ...context,
973
+ environment: config.environment,
974
+ performance_metrics: perf,
975
+ console_logs: consoleLogs.length > 0 ? consoleLogs : void 0,
976
+ javascript_errors: jsErrors.length > 0 ? jsErrors : void 0,
977
+ network_logs: networkLogs.length > 0 ? networkLogs : void 0,
978
+ sdk_version: SDK_VERSION
979
+ };
980
+ if (data.screenshot_data) {
981
+ payload.screenshot_data = data.screenshot_data;
982
+ }
983
+ if (data.annotations && data.annotations.length > 0) {
984
+ payload.annotations = data.annotations;
985
+ }
986
+ if (data.reporter_name) {
987
+ payload.reporter_name = data.reporter_name;
988
+ }
989
+ if (data.reporter_email) {
990
+ payload.reporter_email = data.reporter_email;
991
+ }
992
+ try {
993
+ const res = await fetch(`${config.endpoint}/sdk/feedback`, {
994
+ method: "POST",
995
+ headers: {
996
+ "Content-Type": "application/json",
997
+ "X-API-Key": config.apiKey
998
+ },
999
+ body: JSON.stringify(payload)
1000
+ });
1001
+ const json = await res.json();
1002
+ if (!res.ok) {
1003
+ return { success: false, error: json.error || { message: "Request failed", code: "REQUEST_FAILED" } };
1004
+ }
1005
+ return { success: true, data: json.data };
1006
+ } catch (err) {
1007
+ return { success: false, error: { message: err.message, code: "NETWORK_ERROR" } };
1008
+ }
1009
+ }
1010
+ function showWidget() {
1011
+ if (!config) return;
1012
+ mountWidget(
1013
+ config.widget,
1014
+ (data) => {
1015
+ sendFeedback({
1016
+ title: data.title,
1017
+ description: data.description,
1018
+ type: data.type,
1019
+ priority: data.priority,
1020
+ screenshot_data: data.screenshot,
1021
+ annotations: data.annotations,
1022
+ reporter_name: data.reporter_name,
1023
+ reporter_email: data.reporter_email
1024
+ });
1025
+ },
1026
+ {
1027
+ onScreenshot: () => captureScreenshot(),
1028
+ onHighlight: () => startHighlighting()
1029
+ }
1030
+ );
1031
+ }
1032
+ function hideWidget() {
1033
+ unmountWidget();
1034
+ }
1035
+ function destroy() {
1036
+ unmountWidget();
1037
+ clearLogs();
1038
+ clearNetworkLogs();
1039
+ clearScreenshot();
1040
+ config = null;
1041
+ }
1042
+ var SDK_VERSION, DEFAULT_ENDPOINT, config;
1043
+ var init_index = __esm({
1044
+ "src/index.ts"() {
1045
+ "use strict";
1046
+ init_collector();
1047
+ init_console_interceptor();
1048
+ init_network_interceptor();
1049
+ init_widget();
1050
+ init_screenshot();
1051
+ init_highlighter();
1052
+ init_screenshot();
1053
+ init_highlighter();
1054
+ SDK_VERSION = "1.1.0";
1055
+ DEFAULT_ENDPOINT = "https://api.checkflow.space/api/v1";
1056
+ config = null;
1057
+ }
1058
+ });
1059
+
1060
+ // src/vue.ts
1061
+ var vue_exports = {};
1062
+ __export(vue_exports, {
1063
+ createCheckflowPlugin: () => createCheckflowPlugin,
1064
+ useCheckflow: () => useCheckflow
1065
+ });
1066
+ module.exports = __toCommonJS(vue_exports);
1067
+ var _config = null;
1068
+ var _initialized = false;
1069
+ function createCheckflowPlugin(config2) {
1070
+ return {
1071
+ install() {
1072
+ if (typeof window === "undefined") return;
1073
+ if (_initialized) return;
1074
+ _initialized = true;
1075
+ _config = config2;
1076
+ Promise.resolve().then(() => (init_index(), index_exports)).then(({ init: init2 }) => init2(config2));
1077
+ }
1078
+ };
1079
+ }
1080
+ function useCheckflow() {
1081
+ return {
1082
+ send: async (data) => {
1083
+ if (typeof window === "undefined") return { success: false, error: { message: "Not in browser", code: "SSR" } };
1084
+ const { sendFeedback: sendFeedback2 } = await Promise.resolve().then(() => (init_index(), index_exports));
1085
+ return sendFeedback2(data);
1086
+ },
1087
+ screenshot: async () => {
1088
+ if (typeof window === "undefined") return null;
1089
+ const { captureScreenshot: captureScreenshot2 } = await Promise.resolve().then(() => (init_screenshot(), screenshot_exports));
1090
+ return captureScreenshot2();
1091
+ },
1092
+ highlight: async () => {
1093
+ if (typeof window === "undefined") return [];
1094
+ const { startHighlighting: startHighlighting2 } = await Promise.resolve().then(() => (init_highlighter(), highlighter_exports));
1095
+ return startHighlighting2();
1096
+ },
1097
+ show: async () => {
1098
+ if (typeof window === "undefined") return;
1099
+ const { showWidget: showWidget2 } = await Promise.resolve().then(() => (init_index(), index_exports));
1100
+ showWidget2();
1101
+ },
1102
+ hide: async () => {
1103
+ if (typeof window === "undefined") return;
1104
+ const { hideWidget: hideWidget2 } = await Promise.resolve().then(() => (init_index(), index_exports));
1105
+ hideWidget2();
1106
+ },
1107
+ destroy: async () => {
1108
+ if (typeof window === "undefined") return;
1109
+ const { destroy: destroy2 } = await Promise.resolve().then(() => (init_index(), index_exports));
1110
+ destroy2();
1111
+ _initialized = false;
1112
+ }
1113
+ };
1114
+ }
1115
+ // Annotate the CommonJS export names for ESM import in node:
1116
+ 0 && (module.exports = {
1117
+ createCheckflowPlugin,
1118
+ useCheckflow
1119
+ });