@diegotsi/flint-react 1.0.2 → 1.2.0

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.js CHANGED
@@ -2,437 +2,8 @@
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
- // ../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
- }
5
+ // src/api.ts
6
+ import { submitReplay, submitReport } from "@diegotsi/flint-core";
436
7
 
437
8
  // src/ScreenAnnotator.tsx
438
9
  import { domToCanvas } from "modern-screenshot";
@@ -576,6 +147,9 @@ function ScreenAnnotator({ zIndex, onCapture, onCancel }) {
576
147
  );
577
148
  }
578
149
 
150
+ // src/theme.ts
151
+ import { resolveTheme } from "@diegotsi/flint-core";
152
+
579
153
  // src/FlintModal.tsx
580
154
  import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
581
155
  var SEVERITIES = ["P1", "P2", "P3", "P4"];
@@ -632,6 +206,7 @@ function FlintModal({
632
206
  getEnvironment,
633
207
  getConsoleLogs,
634
208
  getNetworkErrors,
209
+ getFormErrors,
635
210
  getReplayEvents,
636
211
  getExternalReplayUrl,
637
212
  initialSelection = "",
@@ -690,7 +265,8 @@ function FlintModal({
690
265
  ...meta,
691
266
  environment: getEnvironment(),
692
267
  consoleLogs: getConsoleLogs(),
693
- networkErrors: getNetworkErrors()
268
+ networkErrors: getNetworkErrors(),
269
+ formErrors: getFormErrors()
694
270
  };
695
271
  if (isText) {
696
272
  collectedMeta.textIssue = {
@@ -1565,9 +1141,25 @@ function CheckIcon({ size = 20 }) {
1565
1141
  }
1566
1142
 
1567
1143
  // src/FlintWidget.tsx
1144
+ import { Flint as Flint2 } from "@diegotsi/flint-core";
1568
1145
  import { useCallback as useCallback2, useEffect as useEffect3, useRef as useRef3, useState as useState3 } from "react";
1569
1146
  import { I18nextProvider, useTranslation as useTranslation2 } from "react-i18next";
1570
1147
 
1148
+ // src/collectors/console.ts
1149
+ import { createConsoleCollector } from "@diegotsi/flint-core";
1150
+
1151
+ // src/collectors/environment.ts
1152
+ import { collectEnvironment } from "@diegotsi/flint-core";
1153
+
1154
+ // src/collectors/formErrors.ts
1155
+ import { createFormErrorCollector } from "@diegotsi/flint-core";
1156
+
1157
+ // src/collectors/frustration.ts
1158
+ import { createFrustrationCollector } from "@diegotsi/flint-core";
1159
+
1160
+ // src/collectors/network.ts
1161
+ import { createNetworkCollector } from "@diegotsi/flint-core";
1162
+
1571
1163
  // src/i18n/index.ts
1572
1164
  import { createInstance } from "i18next";
1573
1165
  import { initReactI18next } from "react-i18next";
@@ -1618,7 +1210,9 @@ widgetI18n.use(initReactI18next).init({
1618
1210
  var i18n_default = widgetI18n;
1619
1211
 
1620
1212
  // src/store.ts
1213
+ import { getSnapshot, subscribe } from "@diegotsi/flint-core";
1621
1214
  import { useSyncExternalStore } from "react";
1215
+ import { _setFormErrorCollector, Flint, flint } from "@diegotsi/flint-core";
1622
1216
  function useFlintStore() {
1623
1217
  return useSyncExternalStore(subscribe, getSnapshot);
1624
1218
  }
@@ -1648,6 +1242,7 @@ function WidgetContent({
1648
1242
  enableScreenshot = true,
1649
1243
  enableConsole = true,
1650
1244
  enableNetwork = true,
1245
+ enableFormErrors = true,
1651
1246
  enableFrustration = false,
1652
1247
  autoReportFrustration = false,
1653
1248
  onBeforeSubmit,
@@ -1725,31 +1320,42 @@ function WidgetContent({
1725
1320
  setOpen(true);
1726
1321
  onOpen?.();
1727
1322
  };
1323
+ const globalInit = Flint2.isInitialized();
1324
+ const global = Flint2.getInstance();
1728
1325
  const consoleCollector = useRef3(null);
1729
1326
  const networkCollector = useRef3(null);
1730
1327
  const replayEvents = useRef3([]);
1731
1328
  const stopReplay = useRef3(null);
1732
- if (enableConsole && !consoleCollector.current) {
1733
- consoleCollector.current = createConsoleCollector();
1734
- consoleCollector.current.start();
1735
- }
1736
- if (enableNetwork && !networkCollector.current) {
1737
- const flintHost = (() => {
1738
- try {
1739
- return new URL(serverUrl).hostname;
1740
- } catch {
1741
- return "";
1742
- }
1743
- })();
1744
- networkCollector.current = createNetworkCollector(flintHost ? [flintHost] : []);
1745
- networkCollector.current.start();
1746
- }
1329
+ const formErrorCollector = useRef3(null);
1747
1330
  const frustrationCollector = useRef3(null);
1748
- if (enableFrustration && !frustrationCollector.current) {
1749
- frustrationCollector.current = createFrustrationCollector();
1750
- frustrationCollector.current.start();
1331
+ if (!globalInit) {
1332
+ if (enableConsole && !consoleCollector.current) {
1333
+ consoleCollector.current = createConsoleCollector();
1334
+ consoleCollector.current.start();
1335
+ }
1336
+ if (enableNetwork && !networkCollector.current) {
1337
+ const flintHost = (() => {
1338
+ try {
1339
+ return new URL(serverUrl).hostname;
1340
+ } catch {
1341
+ return "";
1342
+ }
1343
+ })();
1344
+ networkCollector.current = createNetworkCollector(flintHost ? [flintHost] : []);
1345
+ networkCollector.current.start();
1346
+ }
1347
+ if (enableFormErrors && !formErrorCollector.current) {
1348
+ formErrorCollector.current = createFormErrorCollector();
1349
+ formErrorCollector.current.start();
1350
+ _setFormErrorCollector(formErrorCollector.current);
1351
+ }
1352
+ if (enableFrustration && !frustrationCollector.current) {
1353
+ frustrationCollector.current = createFrustrationCollector();
1354
+ frustrationCollector.current.start();
1355
+ }
1751
1356
  }
1752
1357
  useEffect3(() => {
1358
+ if (globalInit) return;
1753
1359
  let cancelled = false;
1754
1360
  if (enableReplay) {
1755
1361
  import("rrweb").then(({ record }) => {
@@ -1770,11 +1376,14 @@ function WidgetContent({
1770
1376
  cancelled = true;
1771
1377
  consoleCollector.current?.stop();
1772
1378
  networkCollector.current?.stop();
1379
+ formErrorCollector.current?.stop();
1380
+ _setFormErrorCollector(null);
1773
1381
  frustrationCollector.current?.stop();
1774
1382
  stopReplay.current?.();
1775
1383
  };
1776
- }, [enableReplay]);
1384
+ }, [enableReplay, globalInit]);
1777
1385
  useEffect3(() => {
1386
+ if (globalInit) return;
1778
1387
  if (!enableFrustration || !autoReportFrustration || !frustrationCollector.current) return;
1779
1388
  const unsubscribe = frustrationCollector.current.onFrustration(async (event) => {
1780
1389
  const user2 = resolvedUser;
@@ -1789,13 +1398,14 @@ function WidgetContent({
1789
1398
  environment: collectEnvironment(),
1790
1399
  consoleLogs: consoleCollector.current?.getEntries() ?? [],
1791
1400
  networkErrors: networkCollector.current?.getEntries() ?? [],
1401
+ formErrors: formErrorCollector.current?.getEntries() ?? [],
1792
1402
  frustrationEvent: event
1793
1403
  }
1794
1404
  }).catch(() => {
1795
1405
  });
1796
1406
  });
1797
1407
  return unsubscribe;
1798
- }, [enableFrustration, autoReportFrustration]);
1408
+ }, [enableFrustration, autoReportFrustration, globalInit]);
1799
1409
  const label = buttonLabel ?? t("buttonLabel");
1800
1410
  return /* @__PURE__ */ jsxs3(Fragment2, { children: [
1801
1411
  /* @__PURE__ */ jsxs3(
@@ -1893,9 +1503,10 @@ function WidgetContent({
1893
1503
  pendingSelection.current = "";
1894
1504
  },
1895
1505
  getEnvironment: collectEnvironment,
1896
- getConsoleLogs: () => consoleCollector.current?.getEntries() ?? [],
1897
- getNetworkErrors: () => networkCollector.current?.getEntries() ?? [],
1898
- getReplayEvents: () => [...replayEvents.current],
1506
+ getConsoleLogs: () => globalInit ? global?.console?.getEntries() ?? [] : consoleCollector.current?.getEntries() ?? [],
1507
+ getNetworkErrors: () => globalInit ? global?.network?.getEntries() ?? [] : networkCollector.current?.getEntries() ?? [],
1508
+ getFormErrors: () => globalInit ? global?.formErrors?.getEntries() ?? [] : formErrorCollector.current?.getEntries() ?? [],
1509
+ getReplayEvents: () => globalInit ? Flint2.getReplayEvents() : [...replayEvents.current],
1899
1510
  getExternalReplayUrl,
1900
1511
  initialSelection: pendingSelection.current,
1901
1512
  enableScreenshot,
@@ -1947,6 +1558,7 @@ function SparkIcon2() {
1947
1558
  );
1948
1559
  }
1949
1560
  export {
1561
+ Flint,
1950
1562
  FlintModal,
1951
1563
  FlintWidget,
1952
1564
  flint