@checkflow/sdk 1.1.1 → 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.
- package/README.md +63 -219
- package/dist/chunk-CD33QAA6.mjs +131 -0
- package/dist/chunk-CQ56DMFR.mjs +83 -0
- package/dist/highlighter-D_wZWHlS.d.mts +71 -0
- package/dist/highlighter-D_wZWHlS.d.ts +71 -0
- package/dist/highlighter-W4XDALRE.mjs +8 -0
- package/dist/index.d.mts +41 -0
- package/dist/index.d.ts +38 -20
- package/dist/index.js +607 -17221
- package/dist/index.mjs +411 -0
- package/dist/react.d.mts +28 -0
- package/dist/react.d.ts +28 -0
- package/dist/react.js +743 -0
- package/dist/react.mjs +51 -0
- package/dist/screenshot-CUMBPE2T.mjs +12 -0
- package/dist/vue.d.mts +26 -0
- package/dist/vue.d.ts +26 -0
- package/dist/vue.js +744 -0
- package/dist/vue.mjs +53 -0
- package/package.json +38 -53
- package/dist/analytics-tracker.d.ts +0 -112
- package/dist/annotation/editor.d.ts +0 -72
- package/dist/annotation/index.d.ts +0 -9
- package/dist/annotation/styles.d.ts +0 -6
- package/dist/annotation/toolbar.d.ts +0 -32
- package/dist/annotation/types.d.ts +0 -85
- package/dist/api-client.d.ts +0 -76
- package/dist/checkflow.css +0 -1
- package/dist/checkflow.d.ts +0 -112
- package/dist/context-capture.d.ts +0 -42
- package/dist/error-capture.d.ts +0 -60
- package/dist/index.esm.js +0 -17210
- package/dist/index.esm.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/optimized-recorder.d.ts +0 -94
- package/dist/privacy/detector.d.ts +0 -56
- package/dist/privacy/index.d.ts +0 -8
- package/dist/privacy/masker.d.ts +0 -43
- package/dist/privacy/types.d.ts +0 -54
- package/dist/react/index.d.ts +0 -77
- package/dist/session-recording-rrweb.d.ts +0 -100
- package/dist/session-recording.d.ts +0 -74
- package/dist/types.d.ts +0 -299
- package/dist/vue/index.d.ts +0 -55
- package/dist/widget/Widget.d.ts +0 -98
- 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">×</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
|
+
});
|