@diegotsi/flint-react 1.0.1 → 1.0.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/dist/index.cjs +443 -31
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -5
- package/dist/index.d.ts +14 -5
- package/dist/index.js +432 -20
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
export { flint } from '@flint/core';
|
|
3
2
|
|
|
4
3
|
type Severity = "P1" | "P2" | "P3" | "P4";
|
|
5
4
|
interface EnvironmentInfo {
|
|
@@ -31,7 +30,7 @@ interface ThemeOverride {
|
|
|
31
30
|
text?: string;
|
|
32
31
|
border?: string;
|
|
33
32
|
}
|
|
34
|
-
interface FlintUser {
|
|
33
|
+
interface FlintUser$1 {
|
|
35
34
|
id: string;
|
|
36
35
|
name: string;
|
|
37
36
|
email?: string;
|
|
@@ -47,7 +46,7 @@ interface FlintWidgetProps {
|
|
|
47
46
|
/** Full URL of the flint-server, e.g. "https://bugs.example.com" */
|
|
48
47
|
serverUrl: string;
|
|
49
48
|
/** Authenticated user info (optional) */
|
|
50
|
-
user?: FlintUser;
|
|
49
|
+
user?: FlintUser$1;
|
|
51
50
|
/** Arbitrary metadata to attach to every report */
|
|
52
51
|
meta?: Record<string, unknown>;
|
|
53
52
|
/** Extra fields for developer use (e.g. external session replay URL) */
|
|
@@ -538,7 +537,7 @@ declare global {
|
|
|
538
537
|
interface Props {
|
|
539
538
|
projectKey: string;
|
|
540
539
|
serverUrl: string;
|
|
541
|
-
user?: FlintUser;
|
|
540
|
+
user?: FlintUser$1;
|
|
542
541
|
meta?: Record<string, unknown>;
|
|
543
542
|
theme: Theme;
|
|
544
543
|
zIndex: number;
|
|
@@ -559,4 +558,14 @@ declare function FlintModal({ projectKey, serverUrl, user, meta, theme, zIndex,
|
|
|
559
558
|
|
|
560
559
|
declare function FlintWidget(props: FlintWidgetProps): react_jsx_runtime.JSX.Element;
|
|
561
560
|
|
|
562
|
-
|
|
561
|
+
interface FlintUser {
|
|
562
|
+
id: string;
|
|
563
|
+
name: string;
|
|
564
|
+
email?: string;
|
|
565
|
+
}
|
|
566
|
+
declare const flint: {
|
|
567
|
+
setUser(user: FlintUser | null): void;
|
|
568
|
+
setSessionReplay(url: string | (() => string) | null): void;
|
|
569
|
+
};
|
|
570
|
+
|
|
571
|
+
export { FlintModal, type FlintUser$1 as FlintUser, FlintWidget, type FlintWidgetProps, type Locale, type ReportPayload, type ReportResult, type Severity, type Theme, type ThemeOverride, flint };
|
package/dist/index.js
CHANGED
|
@@ -2,8 +2,437 @@
|
|
|
2
2
|
import { useCallback, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
|
|
3
3
|
import { useTranslation } from "react-i18next";
|
|
4
4
|
|
|
5
|
-
//
|
|
6
|
-
import {
|
|
5
|
+
// ../core/dist/index.js
|
|
6
|
+
import { gzipSync } from "fflate";
|
|
7
|
+
async function fetchWithRetry(url, init, retries = 3, baseDelay = 1e3) {
|
|
8
|
+
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
9
|
+
try {
|
|
10
|
+
const res = await fetch(url, init);
|
|
11
|
+
if (res.ok || attempt === retries) return res;
|
|
12
|
+
if (res.status >= 400 && res.status < 500 && res.status !== 429) return res;
|
|
13
|
+
} catch (err) {
|
|
14
|
+
if (attempt === retries) throw err;
|
|
15
|
+
}
|
|
16
|
+
await new Promise((r) => setTimeout(r, baseDelay * 2 ** attempt));
|
|
17
|
+
}
|
|
18
|
+
throw new Error("Max retries exceeded");
|
|
19
|
+
}
|
|
20
|
+
async function submitReport(serverUrl, projectKey, payload, screenshot) {
|
|
21
|
+
const url = `${serverUrl.replace(/\/$/, "")}/api/v1/bug-reports`;
|
|
22
|
+
let body;
|
|
23
|
+
const headers = {
|
|
24
|
+
"x-project-key": projectKey
|
|
25
|
+
};
|
|
26
|
+
if (screenshot) {
|
|
27
|
+
const form = new FormData();
|
|
28
|
+
form.append("reporterId", payload.reporterId);
|
|
29
|
+
form.append("reporterName", payload.reporterName);
|
|
30
|
+
if (payload.reporterEmail) form.append("reporterEmail", payload.reporterEmail);
|
|
31
|
+
form.append("description", payload.description);
|
|
32
|
+
if (payload.expectedBehavior) form.append("expectedBehavior", payload.expectedBehavior);
|
|
33
|
+
if (payload.stepsToReproduce) form.append("stepsToReproduce", JSON.stringify(payload.stepsToReproduce));
|
|
34
|
+
if (payload.externalReplayUrl) form.append("externalReplayUrl", payload.externalReplayUrl);
|
|
35
|
+
if (payload.additionalContext) form.append("additionalContext", payload.additionalContext);
|
|
36
|
+
form.append("severity", payload.severity);
|
|
37
|
+
if (payload.url) form.append("url", payload.url);
|
|
38
|
+
if (payload.meta) form.append("meta", JSON.stringify(payload.meta));
|
|
39
|
+
form.append("screenshot", screenshot);
|
|
40
|
+
body = form;
|
|
41
|
+
} else {
|
|
42
|
+
body = JSON.stringify(payload);
|
|
43
|
+
headers["Content-Type"] = "application/json";
|
|
44
|
+
}
|
|
45
|
+
const res = await fetchWithRetry(url, { method: "POST", headers, body });
|
|
46
|
+
if (!res.ok) {
|
|
47
|
+
const err = await res.json().catch(() => ({ error: "Unknown error" }));
|
|
48
|
+
throw new Error(err.error ?? `HTTP ${res.status}`);
|
|
49
|
+
}
|
|
50
|
+
return res.json();
|
|
51
|
+
}
|
|
52
|
+
async function submitReplay(serverUrl, projectKey, reportId, events) {
|
|
53
|
+
const json = JSON.stringify(events);
|
|
54
|
+
const encoded = new TextEncoder().encode(json);
|
|
55
|
+
const compressed = gzipSync(encoded);
|
|
56
|
+
const url = `${serverUrl.replace(/\/$/, "")}/api/v1/bug-reports/${reportId}/replay`;
|
|
57
|
+
await fetch(url, {
|
|
58
|
+
method: "POST",
|
|
59
|
+
headers: {
|
|
60
|
+
"x-project-key": projectKey,
|
|
61
|
+
"Content-Type": "application/octet-stream"
|
|
62
|
+
},
|
|
63
|
+
body: compressed.buffer
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
var MAX_ENTRIES = 50;
|
|
67
|
+
function createConsoleCollector() {
|
|
68
|
+
const entries = [];
|
|
69
|
+
let active = false;
|
|
70
|
+
const originals = {
|
|
71
|
+
log: console.log.bind(console),
|
|
72
|
+
warn: console.warn.bind(console),
|
|
73
|
+
error: console.error.bind(console)
|
|
74
|
+
};
|
|
75
|
+
let origOnerror = null;
|
|
76
|
+
let origUnhandled = null;
|
|
77
|
+
function push(level, args) {
|
|
78
|
+
let str;
|
|
79
|
+
try {
|
|
80
|
+
str = args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ");
|
|
81
|
+
} catch {
|
|
82
|
+
str = String(args[0]);
|
|
83
|
+
}
|
|
84
|
+
if (str.length > 500) str = str.slice(0, 500) + "\u2026";
|
|
85
|
+
entries.push({ level, args: str, timestamp: Date.now() });
|
|
86
|
+
if (entries.length > MAX_ENTRIES) entries.shift();
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
start() {
|
|
90
|
+
if (active) return;
|
|
91
|
+
active = true;
|
|
92
|
+
console.log = (...args) => {
|
|
93
|
+
push("log", args);
|
|
94
|
+
originals.log(...args);
|
|
95
|
+
};
|
|
96
|
+
console.warn = (...args) => {
|
|
97
|
+
push("warn", args);
|
|
98
|
+
originals.warn(...args);
|
|
99
|
+
};
|
|
100
|
+
console.error = (...args) => {
|
|
101
|
+
push("error", args);
|
|
102
|
+
originals.error(...args);
|
|
103
|
+
};
|
|
104
|
+
origOnerror = window.onerror;
|
|
105
|
+
window.onerror = (msg, src, line, col, err) => {
|
|
106
|
+
push("error", [err?.message ?? String(msg), `${src}:${line}:${col}`]);
|
|
107
|
+
if (typeof origOnerror === "function") return origOnerror(msg, src, line, col, err);
|
|
108
|
+
return false;
|
|
109
|
+
};
|
|
110
|
+
origUnhandled = window.onunhandledrejection;
|
|
111
|
+
window.onunhandledrejection = (event) => {
|
|
112
|
+
const reason = event.reason instanceof Error ? event.reason.message : JSON.stringify(event.reason);
|
|
113
|
+
push("error", ["UnhandledRejection:", reason]);
|
|
114
|
+
if (typeof origUnhandled === "function") origUnhandled.call(window, event);
|
|
115
|
+
};
|
|
116
|
+
},
|
|
117
|
+
stop() {
|
|
118
|
+
if (!active) return;
|
|
119
|
+
active = false;
|
|
120
|
+
console.log = originals.log;
|
|
121
|
+
console.warn = originals.warn;
|
|
122
|
+
console.error = originals.error;
|
|
123
|
+
window.onerror = origOnerror;
|
|
124
|
+
window.onunhandledrejection = origUnhandled;
|
|
125
|
+
},
|
|
126
|
+
getEntries() {
|
|
127
|
+
return [...entries];
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
function collectEnvironment() {
|
|
132
|
+
const ua = navigator.userAgent;
|
|
133
|
+
let browser = "Unknown";
|
|
134
|
+
const chromeM = ua.match(/Chrome\/(\d+)/);
|
|
135
|
+
const firefoxM = ua.match(/Firefox\/(\d+)/);
|
|
136
|
+
const edgeM = ua.match(/Edg\/(\d+)/);
|
|
137
|
+
const safariM = ua.match(/Version\/(\d+)/);
|
|
138
|
+
const operaM = ua.match(/OPR\/(\d+)/);
|
|
139
|
+
if (operaM) {
|
|
140
|
+
browser = `Opera ${operaM[1]}`;
|
|
141
|
+
} else if (edgeM) {
|
|
142
|
+
browser = `Edge ${edgeM[1]}`;
|
|
143
|
+
} else if (chromeM && !/Edg|OPR/.test(ua)) {
|
|
144
|
+
browser = `Chrome ${chromeM[1]}`;
|
|
145
|
+
} else if (firefoxM) {
|
|
146
|
+
browser = `Firefox ${firefoxM[1]}`;
|
|
147
|
+
} else if (safariM && /Safari\//.test(ua)) {
|
|
148
|
+
browser = `Safari ${safariM[1]}`;
|
|
149
|
+
}
|
|
150
|
+
let os = "Unknown";
|
|
151
|
+
const macM = ua.match(/Mac OS X (\d+[._]\d+)/);
|
|
152
|
+
const winM = ua.match(/Windows NT (\d+\.\d+)/);
|
|
153
|
+
const androidM = ua.match(/Android (\d+)/);
|
|
154
|
+
const iosM = ua.match(/iPhone OS (\d+[._]\d+)/);
|
|
155
|
+
if (macM) {
|
|
156
|
+
os = `macOS ${macM[1].replace("_", ".")}`;
|
|
157
|
+
} else if (winM) {
|
|
158
|
+
const winMap = {
|
|
159
|
+
"10.0": "10/11",
|
|
160
|
+
"6.3": "8.1",
|
|
161
|
+
"6.2": "8",
|
|
162
|
+
"6.1": "7"
|
|
163
|
+
};
|
|
164
|
+
os = `Windows ${winMap[winM[1]] ?? winM[1]}`;
|
|
165
|
+
} else if (androidM) {
|
|
166
|
+
os = `Android ${androidM[1]}`;
|
|
167
|
+
} else if (iosM) {
|
|
168
|
+
os = `iOS ${iosM[1].replace(/_/g, ".")}`;
|
|
169
|
+
} else if (/Linux/.test(ua)) {
|
|
170
|
+
os = "Linux";
|
|
171
|
+
}
|
|
172
|
+
return {
|
|
173
|
+
browser,
|
|
174
|
+
os,
|
|
175
|
+
viewport: `${window.innerWidth}x${window.innerHeight}`,
|
|
176
|
+
screen: `${screen.width}x${screen.height}`,
|
|
177
|
+
language: navigator.language,
|
|
178
|
+
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
179
|
+
online: navigator.onLine
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
function createFrustrationCollector(opts) {
|
|
183
|
+
const threshold = opts?.rageClickThreshold ?? 3;
|
|
184
|
+
const window2 = opts?.rageClickWindow ?? 500;
|
|
185
|
+
const errorThreshold = opts?.errorLoopThreshold ?? 3;
|
|
186
|
+
const errorWindow = opts?.errorLoopWindow ?? 3e4;
|
|
187
|
+
const deadClicksEnabled = opts?.enableDeadClicks ?? true;
|
|
188
|
+
const events = [];
|
|
189
|
+
const listeners2 = /* @__PURE__ */ new Set();
|
|
190
|
+
const clickHistory = [];
|
|
191
|
+
const errorCounts = /* @__PURE__ */ new Map();
|
|
192
|
+
let clickHandler = null;
|
|
193
|
+
let origConsoleError = null;
|
|
194
|
+
function emit2(event) {
|
|
195
|
+
events.push(event);
|
|
196
|
+
if (events.length > 50) events.shift();
|
|
197
|
+
for (const cb of listeners2) cb(event);
|
|
198
|
+
}
|
|
199
|
+
function getCSSSelector(el) {
|
|
200
|
+
if (el.id) return `#${el.id}`;
|
|
201
|
+
const tag = el.tagName.toLowerCase();
|
|
202
|
+
const cls = [...el.classList].slice(0, 3).join(".");
|
|
203
|
+
if (cls) return `${tag}.${cls}`;
|
|
204
|
+
return tag;
|
|
205
|
+
}
|
|
206
|
+
function isInteractive(el) {
|
|
207
|
+
const tag = el.tagName.toLowerCase();
|
|
208
|
+
if (["a", "button", "input", "select", "textarea", "label", "summary"].includes(tag)) return true;
|
|
209
|
+
if (el.getAttribute("role") === "button" || el.getAttribute("tabindex")) return true;
|
|
210
|
+
if (el.onclick || el.getAttribute("onclick")) return true;
|
|
211
|
+
if (el.closest("a, button, [role=button], [onclick]")) return true;
|
|
212
|
+
try {
|
|
213
|
+
if (getComputedStyle(el).cursor === "pointer") return true;
|
|
214
|
+
} catch {
|
|
215
|
+
}
|
|
216
|
+
return false;
|
|
217
|
+
}
|
|
218
|
+
function handleClick(e) {
|
|
219
|
+
const target = e.target;
|
|
220
|
+
if (!target) return;
|
|
221
|
+
const now = Date.now();
|
|
222
|
+
clickHistory.push({ target, time: now });
|
|
223
|
+
while (clickHistory.length > 0 && now - clickHistory[0].time > 1e3) {
|
|
224
|
+
clickHistory.shift();
|
|
225
|
+
}
|
|
226
|
+
const recentOnSame = clickHistory.filter((c) => c.target === target && now - c.time < window2);
|
|
227
|
+
if (recentOnSame.length >= threshold) {
|
|
228
|
+
emit2({
|
|
229
|
+
type: "rage_click",
|
|
230
|
+
timestamp: now,
|
|
231
|
+
target: getCSSSelector(target),
|
|
232
|
+
details: `${recentOnSame.length} clicks in ${now - recentOnSame[0].time}ms`,
|
|
233
|
+
url: globalThis.location?.href ?? ""
|
|
234
|
+
});
|
|
235
|
+
clickHistory.length = 0;
|
|
236
|
+
}
|
|
237
|
+
if (deadClicksEnabled && !isInteractive(target)) {
|
|
238
|
+
emit2({
|
|
239
|
+
type: "dead_click",
|
|
240
|
+
timestamp: now,
|
|
241
|
+
target: getCSSSelector(target),
|
|
242
|
+
details: `Click on non-interactive <${target.tagName.toLowerCase()}>`,
|
|
243
|
+
url: globalThis.location?.href ?? ""
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
function patchConsoleError() {
|
|
248
|
+
origConsoleError = console.error;
|
|
249
|
+
console.error = (...args) => {
|
|
250
|
+
origConsoleError?.apply(console, args);
|
|
251
|
+
const key = String(args[0]).slice(0, 100);
|
|
252
|
+
const now = Date.now();
|
|
253
|
+
const existing = errorCounts.get(key);
|
|
254
|
+
if (existing && now - existing.firstSeen < errorWindow) {
|
|
255
|
+
existing.count++;
|
|
256
|
+
if (existing.count >= errorThreshold) {
|
|
257
|
+
emit2({
|
|
258
|
+
type: "error_loop",
|
|
259
|
+
timestamp: now,
|
|
260
|
+
target: "console",
|
|
261
|
+
details: `Same error ${existing.count}x in ${Math.round((now - existing.firstSeen) / 1e3)}s: ${key}`,
|
|
262
|
+
url: globalThis.location?.href ?? ""
|
|
263
|
+
});
|
|
264
|
+
errorCounts.delete(key);
|
|
265
|
+
}
|
|
266
|
+
} else {
|
|
267
|
+
errorCounts.set(key, { count: 1, firstSeen: now });
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
return {
|
|
272
|
+
start() {
|
|
273
|
+
clickHandler = handleClick;
|
|
274
|
+
document.addEventListener("click", clickHandler, true);
|
|
275
|
+
patchConsoleError();
|
|
276
|
+
},
|
|
277
|
+
stop() {
|
|
278
|
+
if (clickHandler) document.removeEventListener("click", clickHandler, true);
|
|
279
|
+
if (origConsoleError) console.error = origConsoleError;
|
|
280
|
+
clickHistory.length = 0;
|
|
281
|
+
errorCounts.clear();
|
|
282
|
+
},
|
|
283
|
+
getEvents() {
|
|
284
|
+
return [...events];
|
|
285
|
+
},
|
|
286
|
+
onFrustration(callback) {
|
|
287
|
+
listeners2.add(callback);
|
|
288
|
+
return () => listeners2.delete(callback);
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
var MAX_ENTRIES2 = 50;
|
|
293
|
+
var BLOCKED_HOSTS = /* @__PURE__ */ new Set([
|
|
294
|
+
"browser-intake-datadoghq.com",
|
|
295
|
+
"rum.browser-intake-datadoghq.com",
|
|
296
|
+
"logs.browser-intake-datadoghq.com",
|
|
297
|
+
"session-replay.browser-intake-datadoghq.com"
|
|
298
|
+
]);
|
|
299
|
+
function isBlockedUrl(url, extra) {
|
|
300
|
+
try {
|
|
301
|
+
const host = new URL(url, location.href).hostname;
|
|
302
|
+
const all = [...BLOCKED_HOSTS, ...extra];
|
|
303
|
+
return all.some((b) => host === b || host.endsWith("." + b));
|
|
304
|
+
} catch {
|
|
305
|
+
return false;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
function truncateUrl(url) {
|
|
309
|
+
try {
|
|
310
|
+
const u = new URL(url, location.href);
|
|
311
|
+
const base = `${u.origin}${u.pathname}`;
|
|
312
|
+
return base.length > 200 ? base.slice(0, 200) + "\u2026" : base;
|
|
313
|
+
} catch {
|
|
314
|
+
return url.length > 200 ? url.slice(0, 200) + "\u2026" : url;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
function createNetworkCollector(extraBlockedHosts = []) {
|
|
318
|
+
const entries = [];
|
|
319
|
+
const blocked = new Set(extraBlockedHosts);
|
|
320
|
+
let origFetch = null;
|
|
321
|
+
let origXHROpen = null;
|
|
322
|
+
let active = false;
|
|
323
|
+
function push(entry) {
|
|
324
|
+
entries.push(entry);
|
|
325
|
+
if (entries.length > MAX_ENTRIES2) entries.shift();
|
|
326
|
+
}
|
|
327
|
+
return {
|
|
328
|
+
start() {
|
|
329
|
+
if (active) return;
|
|
330
|
+
active = true;
|
|
331
|
+
origFetch = window.fetch;
|
|
332
|
+
window.fetch = async (input, init) => {
|
|
333
|
+
const method = (init?.method ?? "GET").toUpperCase();
|
|
334
|
+
const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
|
335
|
+
const startTime = Date.now();
|
|
336
|
+
const res = await origFetch.call(window, input, init);
|
|
337
|
+
if (res.status >= 400 && !isBlockedUrl(url, blocked)) {
|
|
338
|
+
push({
|
|
339
|
+
method,
|
|
340
|
+
url: truncateUrl(url),
|
|
341
|
+
status: res.status,
|
|
342
|
+
duration: Date.now() - startTime,
|
|
343
|
+
timestamp: startTime
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
return res;
|
|
347
|
+
};
|
|
348
|
+
origXHROpen = XMLHttpRequest.prototype.open;
|
|
349
|
+
XMLHttpRequest.prototype.open = function(method, url, async, username, password) {
|
|
350
|
+
const startTime = Date.now();
|
|
351
|
+
const urlStr = typeof url === "string" ? url : url.href;
|
|
352
|
+
this.addEventListener("load", () => {
|
|
353
|
+
if (this.status >= 400 && !isBlockedUrl(urlStr, blocked)) {
|
|
354
|
+
push({
|
|
355
|
+
method: method.toUpperCase(),
|
|
356
|
+
url: truncateUrl(urlStr),
|
|
357
|
+
status: this.status,
|
|
358
|
+
duration: Date.now() - startTime,
|
|
359
|
+
timestamp: startTime
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
});
|
|
363
|
+
return origXHROpen.apply(this, [method, url, async ?? true, username, password]);
|
|
364
|
+
};
|
|
365
|
+
},
|
|
366
|
+
stop() {
|
|
367
|
+
if (!active) return;
|
|
368
|
+
active = false;
|
|
369
|
+
if (origFetch) window.fetch = origFetch;
|
|
370
|
+
if (origXHROpen) XMLHttpRequest.prototype.open = origXHROpen;
|
|
371
|
+
},
|
|
372
|
+
getEntries() {
|
|
373
|
+
return [...entries];
|
|
374
|
+
}
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
var state = { user: void 0, sessionReplay: void 0 };
|
|
378
|
+
var listeners = /* @__PURE__ */ new Set();
|
|
379
|
+
function emit() {
|
|
380
|
+
for (const l of listeners) l();
|
|
381
|
+
}
|
|
382
|
+
function subscribe(listener) {
|
|
383
|
+
listeners.add(listener);
|
|
384
|
+
return () => listeners.delete(listener);
|
|
385
|
+
}
|
|
386
|
+
function getSnapshot() {
|
|
387
|
+
return state;
|
|
388
|
+
}
|
|
389
|
+
var flint = {
|
|
390
|
+
setUser(user) {
|
|
391
|
+
state = { ...state, user: user ?? void 0 };
|
|
392
|
+
emit();
|
|
393
|
+
},
|
|
394
|
+
setSessionReplay(url) {
|
|
395
|
+
state = { ...state, sessionReplay: url ?? void 0 };
|
|
396
|
+
emit();
|
|
397
|
+
}
|
|
398
|
+
};
|
|
399
|
+
var light = {
|
|
400
|
+
background: "rgba(255,255,255,0.90)",
|
|
401
|
+
backgroundSecondary: "rgba(249,250,251,0.75)",
|
|
402
|
+
accent: "#2563eb",
|
|
403
|
+
accentHover: "#1d4ed8",
|
|
404
|
+
text: "#111827",
|
|
405
|
+
textMuted: "#6b7280",
|
|
406
|
+
border: "rgba(255,255,255,0.9)",
|
|
407
|
+
shadow: "0 32px 80px rgba(0,0,0,0.18), 0 8px 32px rgba(0,0,0,0.1), 0 0 0 1px rgba(0,0,0,0.04)",
|
|
408
|
+
buttonText: "#ffffff",
|
|
409
|
+
backdropFilter: "blur(32px) saturate(1.8)"
|
|
410
|
+
};
|
|
411
|
+
var dark = {
|
|
412
|
+
background: "rgba(15,20,35,0.88)",
|
|
413
|
+
backgroundSecondary: "rgba(5,8,18,0.65)",
|
|
414
|
+
accent: "#4d8aff",
|
|
415
|
+
accentHover: "#3b6fdb",
|
|
416
|
+
text: "#dde3ef",
|
|
417
|
+
textMuted: "#6b7a93",
|
|
418
|
+
border: "rgba(255,255,255,0.08)",
|
|
419
|
+
shadow: "0 24px 60px rgba(0,0,0,0.6), 0 0 0 1px rgba(255,255,255,0.04)",
|
|
420
|
+
buttonText: "#ffffff",
|
|
421
|
+
backdropFilter: "blur(32px) saturate(1.6)"
|
|
422
|
+
};
|
|
423
|
+
function resolveTheme(theme) {
|
|
424
|
+
if (theme === "dark") return dark;
|
|
425
|
+
if (theme === "light") return light;
|
|
426
|
+
const override = theme;
|
|
427
|
+
return {
|
|
428
|
+
...light,
|
|
429
|
+
background: override.background ?? light.background,
|
|
430
|
+
accent: override.accent ?? light.accent,
|
|
431
|
+
accentHover: override.accent ?? light.accentHover,
|
|
432
|
+
text: override.text ?? light.text,
|
|
433
|
+
border: override.border ?? light.border
|
|
434
|
+
};
|
|
435
|
+
}
|
|
7
436
|
|
|
8
437
|
// src/ScreenAnnotator.tsx
|
|
9
438
|
import { domToCanvas } from "modern-screenshot";
|
|
@@ -147,9 +576,6 @@ function ScreenAnnotator({ zIndex, onCapture, onCancel }) {
|
|
|
147
576
|
);
|
|
148
577
|
}
|
|
149
578
|
|
|
150
|
-
// src/theme.ts
|
|
151
|
-
import { resolveTheme } from "@flint/core";
|
|
152
|
-
|
|
153
579
|
// src/FlintModal.tsx
|
|
154
580
|
import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
155
581
|
var SEVERITIES = ["P1", "P2", "P3", "P4"];
|
|
@@ -1142,18 +1568,6 @@ function CheckIcon({ size = 20 }) {
|
|
|
1142
1568
|
import { useCallback as useCallback2, useEffect as useEffect3, useRef as useRef3, useState as useState3 } from "react";
|
|
1143
1569
|
import { I18nextProvider, useTranslation as useTranslation2 } from "react-i18next";
|
|
1144
1570
|
|
|
1145
|
-
// src/collectors/console.ts
|
|
1146
|
-
import { createConsoleCollector } from "@flint/core";
|
|
1147
|
-
|
|
1148
|
-
// src/collectors/environment.ts
|
|
1149
|
-
import { collectEnvironment } from "@flint/core";
|
|
1150
|
-
|
|
1151
|
-
// src/collectors/frustration.ts
|
|
1152
|
-
import { createFrustrationCollector } from "@flint/core";
|
|
1153
|
-
|
|
1154
|
-
// src/collectors/network.ts
|
|
1155
|
-
import { createNetworkCollector } from "@flint/core";
|
|
1156
|
-
|
|
1157
1571
|
// src/i18n/index.ts
|
|
1158
1572
|
import { createInstance } from "i18next";
|
|
1159
1573
|
import { initReactI18next } from "react-i18next";
|
|
@@ -1204,9 +1618,7 @@ widgetI18n.use(initReactI18next).init({
|
|
|
1204
1618
|
var i18n_default = widgetI18n;
|
|
1205
1619
|
|
|
1206
1620
|
// src/store.ts
|
|
1207
|
-
import { getSnapshot, subscribe } from "@flint/core";
|
|
1208
1621
|
import { useSyncExternalStore } from "react";
|
|
1209
|
-
import { flint as flint2 } from "@flint/core";
|
|
1210
1622
|
function useFlintStore() {
|
|
1211
1623
|
return useSyncExternalStore(subscribe, getSnapshot);
|
|
1212
1624
|
}
|
|
@@ -1537,6 +1949,6 @@ function SparkIcon2() {
|
|
|
1537
1949
|
export {
|
|
1538
1950
|
FlintModal,
|
|
1539
1951
|
FlintWidget,
|
|
1540
|
-
|
|
1952
|
+
flint
|
|
1541
1953
|
};
|
|
1542
1954
|
//# sourceMappingURL=index.js.map
|