@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 CHANGED
@@ -32,7 +32,7 @@ var index_exports = {};
32
32
  __export(index_exports, {
33
33
  FlintModal: () => FlintModal,
34
34
  FlintWidget: () => FlintWidget,
35
- flint: () => import_core8.flint
35
+ flint: () => flint
36
36
  });
37
37
  module.exports = __toCommonJS(index_exports);
38
38
 
@@ -40,8 +40,437 @@ module.exports = __toCommonJS(index_exports);
40
40
  var import_react2 = require("react");
41
41
  var import_react_i18next = require("react-i18next");
42
42
 
43
- // src/api.ts
44
- var import_core = require("@flint/core");
43
+ // ../core/dist/index.js
44
+ var import_fflate = require("fflate");
45
+ async function fetchWithRetry(url, init, retries = 3, baseDelay = 1e3) {
46
+ for (let attempt = 0; attempt <= retries; attempt++) {
47
+ try {
48
+ const res = await fetch(url, init);
49
+ if (res.ok || attempt === retries) return res;
50
+ if (res.status >= 400 && res.status < 500 && res.status !== 429) return res;
51
+ } catch (err) {
52
+ if (attempt === retries) throw err;
53
+ }
54
+ await new Promise((r) => setTimeout(r, baseDelay * 2 ** attempt));
55
+ }
56
+ throw new Error("Max retries exceeded");
57
+ }
58
+ async function submitReport(serverUrl, projectKey, payload, screenshot) {
59
+ const url = `${serverUrl.replace(/\/$/, "")}/api/v1/bug-reports`;
60
+ let body;
61
+ const headers = {
62
+ "x-project-key": projectKey
63
+ };
64
+ if (screenshot) {
65
+ const form = new FormData();
66
+ form.append("reporterId", payload.reporterId);
67
+ form.append("reporterName", payload.reporterName);
68
+ if (payload.reporterEmail) form.append("reporterEmail", payload.reporterEmail);
69
+ form.append("description", payload.description);
70
+ if (payload.expectedBehavior) form.append("expectedBehavior", payload.expectedBehavior);
71
+ if (payload.stepsToReproduce) form.append("stepsToReproduce", JSON.stringify(payload.stepsToReproduce));
72
+ if (payload.externalReplayUrl) form.append("externalReplayUrl", payload.externalReplayUrl);
73
+ if (payload.additionalContext) form.append("additionalContext", payload.additionalContext);
74
+ form.append("severity", payload.severity);
75
+ if (payload.url) form.append("url", payload.url);
76
+ if (payload.meta) form.append("meta", JSON.stringify(payload.meta));
77
+ form.append("screenshot", screenshot);
78
+ body = form;
79
+ } else {
80
+ body = JSON.stringify(payload);
81
+ headers["Content-Type"] = "application/json";
82
+ }
83
+ const res = await fetchWithRetry(url, { method: "POST", headers, body });
84
+ if (!res.ok) {
85
+ const err = await res.json().catch(() => ({ error: "Unknown error" }));
86
+ throw new Error(err.error ?? `HTTP ${res.status}`);
87
+ }
88
+ return res.json();
89
+ }
90
+ async function submitReplay(serverUrl, projectKey, reportId, events) {
91
+ const json = JSON.stringify(events);
92
+ const encoded = new TextEncoder().encode(json);
93
+ const compressed = (0, import_fflate.gzipSync)(encoded);
94
+ const url = `${serverUrl.replace(/\/$/, "")}/api/v1/bug-reports/${reportId}/replay`;
95
+ await fetch(url, {
96
+ method: "POST",
97
+ headers: {
98
+ "x-project-key": projectKey,
99
+ "Content-Type": "application/octet-stream"
100
+ },
101
+ body: compressed.buffer
102
+ });
103
+ }
104
+ var MAX_ENTRIES = 50;
105
+ function createConsoleCollector() {
106
+ const entries = [];
107
+ let active = false;
108
+ const originals = {
109
+ log: console.log.bind(console),
110
+ warn: console.warn.bind(console),
111
+ error: console.error.bind(console)
112
+ };
113
+ let origOnerror = null;
114
+ let origUnhandled = null;
115
+ function push(level, args) {
116
+ let str;
117
+ try {
118
+ str = args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ");
119
+ } catch {
120
+ str = String(args[0]);
121
+ }
122
+ if (str.length > 500) str = str.slice(0, 500) + "\u2026";
123
+ entries.push({ level, args: str, timestamp: Date.now() });
124
+ if (entries.length > MAX_ENTRIES) entries.shift();
125
+ }
126
+ return {
127
+ start() {
128
+ if (active) return;
129
+ active = true;
130
+ console.log = (...args) => {
131
+ push("log", args);
132
+ originals.log(...args);
133
+ };
134
+ console.warn = (...args) => {
135
+ push("warn", args);
136
+ originals.warn(...args);
137
+ };
138
+ console.error = (...args) => {
139
+ push("error", args);
140
+ originals.error(...args);
141
+ };
142
+ origOnerror = window.onerror;
143
+ window.onerror = (msg, src, line, col, err) => {
144
+ push("error", [err?.message ?? String(msg), `${src}:${line}:${col}`]);
145
+ if (typeof origOnerror === "function") return origOnerror(msg, src, line, col, err);
146
+ return false;
147
+ };
148
+ origUnhandled = window.onunhandledrejection;
149
+ window.onunhandledrejection = (event) => {
150
+ const reason = event.reason instanceof Error ? event.reason.message : JSON.stringify(event.reason);
151
+ push("error", ["UnhandledRejection:", reason]);
152
+ if (typeof origUnhandled === "function") origUnhandled.call(window, event);
153
+ };
154
+ },
155
+ stop() {
156
+ if (!active) return;
157
+ active = false;
158
+ console.log = originals.log;
159
+ console.warn = originals.warn;
160
+ console.error = originals.error;
161
+ window.onerror = origOnerror;
162
+ window.onunhandledrejection = origUnhandled;
163
+ },
164
+ getEntries() {
165
+ return [...entries];
166
+ }
167
+ };
168
+ }
169
+ function collectEnvironment() {
170
+ const ua = navigator.userAgent;
171
+ let browser = "Unknown";
172
+ const chromeM = ua.match(/Chrome\/(\d+)/);
173
+ const firefoxM = ua.match(/Firefox\/(\d+)/);
174
+ const edgeM = ua.match(/Edg\/(\d+)/);
175
+ const safariM = ua.match(/Version\/(\d+)/);
176
+ const operaM = ua.match(/OPR\/(\d+)/);
177
+ if (operaM) {
178
+ browser = `Opera ${operaM[1]}`;
179
+ } else if (edgeM) {
180
+ browser = `Edge ${edgeM[1]}`;
181
+ } else if (chromeM && !/Edg|OPR/.test(ua)) {
182
+ browser = `Chrome ${chromeM[1]}`;
183
+ } else if (firefoxM) {
184
+ browser = `Firefox ${firefoxM[1]}`;
185
+ } else if (safariM && /Safari\//.test(ua)) {
186
+ browser = `Safari ${safariM[1]}`;
187
+ }
188
+ let os = "Unknown";
189
+ const macM = ua.match(/Mac OS X (\d+[._]\d+)/);
190
+ const winM = ua.match(/Windows NT (\d+\.\d+)/);
191
+ const androidM = ua.match(/Android (\d+)/);
192
+ const iosM = ua.match(/iPhone OS (\d+[._]\d+)/);
193
+ if (macM) {
194
+ os = `macOS ${macM[1].replace("_", ".")}`;
195
+ } else if (winM) {
196
+ const winMap = {
197
+ "10.0": "10/11",
198
+ "6.3": "8.1",
199
+ "6.2": "8",
200
+ "6.1": "7"
201
+ };
202
+ os = `Windows ${winMap[winM[1]] ?? winM[1]}`;
203
+ } else if (androidM) {
204
+ os = `Android ${androidM[1]}`;
205
+ } else if (iosM) {
206
+ os = `iOS ${iosM[1].replace(/_/g, ".")}`;
207
+ } else if (/Linux/.test(ua)) {
208
+ os = "Linux";
209
+ }
210
+ return {
211
+ browser,
212
+ os,
213
+ viewport: `${window.innerWidth}x${window.innerHeight}`,
214
+ screen: `${screen.width}x${screen.height}`,
215
+ language: navigator.language,
216
+ timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
217
+ online: navigator.onLine
218
+ };
219
+ }
220
+ function createFrustrationCollector(opts) {
221
+ const threshold = opts?.rageClickThreshold ?? 3;
222
+ const window2 = opts?.rageClickWindow ?? 500;
223
+ const errorThreshold = opts?.errorLoopThreshold ?? 3;
224
+ const errorWindow = opts?.errorLoopWindow ?? 3e4;
225
+ const deadClicksEnabled = opts?.enableDeadClicks ?? true;
226
+ const events = [];
227
+ const listeners2 = /* @__PURE__ */ new Set();
228
+ const clickHistory = [];
229
+ const errorCounts = /* @__PURE__ */ new Map();
230
+ let clickHandler = null;
231
+ let origConsoleError = null;
232
+ function emit2(event) {
233
+ events.push(event);
234
+ if (events.length > 50) events.shift();
235
+ for (const cb of listeners2) cb(event);
236
+ }
237
+ function getCSSSelector(el) {
238
+ if (el.id) return `#${el.id}`;
239
+ const tag = el.tagName.toLowerCase();
240
+ const cls = [...el.classList].slice(0, 3).join(".");
241
+ if (cls) return `${tag}.${cls}`;
242
+ return tag;
243
+ }
244
+ function isInteractive(el) {
245
+ const tag = el.tagName.toLowerCase();
246
+ if (["a", "button", "input", "select", "textarea", "label", "summary"].includes(tag)) return true;
247
+ if (el.getAttribute("role") === "button" || el.getAttribute("tabindex")) return true;
248
+ if (el.onclick || el.getAttribute("onclick")) return true;
249
+ if (el.closest("a, button, [role=button], [onclick]")) return true;
250
+ try {
251
+ if (getComputedStyle(el).cursor === "pointer") return true;
252
+ } catch {
253
+ }
254
+ return false;
255
+ }
256
+ function handleClick(e) {
257
+ const target = e.target;
258
+ if (!target) return;
259
+ const now = Date.now();
260
+ clickHistory.push({ target, time: now });
261
+ while (clickHistory.length > 0 && now - clickHistory[0].time > 1e3) {
262
+ clickHistory.shift();
263
+ }
264
+ const recentOnSame = clickHistory.filter((c) => c.target === target && now - c.time < window2);
265
+ if (recentOnSame.length >= threshold) {
266
+ emit2({
267
+ type: "rage_click",
268
+ timestamp: now,
269
+ target: getCSSSelector(target),
270
+ details: `${recentOnSame.length} clicks in ${now - recentOnSame[0].time}ms`,
271
+ url: globalThis.location?.href ?? ""
272
+ });
273
+ clickHistory.length = 0;
274
+ }
275
+ if (deadClicksEnabled && !isInteractive(target)) {
276
+ emit2({
277
+ type: "dead_click",
278
+ timestamp: now,
279
+ target: getCSSSelector(target),
280
+ details: `Click on non-interactive <${target.tagName.toLowerCase()}>`,
281
+ url: globalThis.location?.href ?? ""
282
+ });
283
+ }
284
+ }
285
+ function patchConsoleError() {
286
+ origConsoleError = console.error;
287
+ console.error = (...args) => {
288
+ origConsoleError?.apply(console, args);
289
+ const key = String(args[0]).slice(0, 100);
290
+ const now = Date.now();
291
+ const existing = errorCounts.get(key);
292
+ if (existing && now - existing.firstSeen < errorWindow) {
293
+ existing.count++;
294
+ if (existing.count >= errorThreshold) {
295
+ emit2({
296
+ type: "error_loop",
297
+ timestamp: now,
298
+ target: "console",
299
+ details: `Same error ${existing.count}x in ${Math.round((now - existing.firstSeen) / 1e3)}s: ${key}`,
300
+ url: globalThis.location?.href ?? ""
301
+ });
302
+ errorCounts.delete(key);
303
+ }
304
+ } else {
305
+ errorCounts.set(key, { count: 1, firstSeen: now });
306
+ }
307
+ };
308
+ }
309
+ return {
310
+ start() {
311
+ clickHandler = handleClick;
312
+ document.addEventListener("click", clickHandler, true);
313
+ patchConsoleError();
314
+ },
315
+ stop() {
316
+ if (clickHandler) document.removeEventListener("click", clickHandler, true);
317
+ if (origConsoleError) console.error = origConsoleError;
318
+ clickHistory.length = 0;
319
+ errorCounts.clear();
320
+ },
321
+ getEvents() {
322
+ return [...events];
323
+ },
324
+ onFrustration(callback) {
325
+ listeners2.add(callback);
326
+ return () => listeners2.delete(callback);
327
+ }
328
+ };
329
+ }
330
+ var MAX_ENTRIES2 = 50;
331
+ var BLOCKED_HOSTS = /* @__PURE__ */ new Set([
332
+ "browser-intake-datadoghq.com",
333
+ "rum.browser-intake-datadoghq.com",
334
+ "logs.browser-intake-datadoghq.com",
335
+ "session-replay.browser-intake-datadoghq.com"
336
+ ]);
337
+ function isBlockedUrl(url, extra) {
338
+ try {
339
+ const host = new URL(url, location.href).hostname;
340
+ const all = [...BLOCKED_HOSTS, ...extra];
341
+ return all.some((b) => host === b || host.endsWith("." + b));
342
+ } catch {
343
+ return false;
344
+ }
345
+ }
346
+ function truncateUrl(url) {
347
+ try {
348
+ const u = new URL(url, location.href);
349
+ const base = `${u.origin}${u.pathname}`;
350
+ return base.length > 200 ? base.slice(0, 200) + "\u2026" : base;
351
+ } catch {
352
+ return url.length > 200 ? url.slice(0, 200) + "\u2026" : url;
353
+ }
354
+ }
355
+ function createNetworkCollector(extraBlockedHosts = []) {
356
+ const entries = [];
357
+ const blocked = new Set(extraBlockedHosts);
358
+ let origFetch = null;
359
+ let origXHROpen = null;
360
+ let active = false;
361
+ function push(entry) {
362
+ entries.push(entry);
363
+ if (entries.length > MAX_ENTRIES2) entries.shift();
364
+ }
365
+ return {
366
+ start() {
367
+ if (active) return;
368
+ active = true;
369
+ origFetch = window.fetch;
370
+ window.fetch = async (input, init) => {
371
+ const method = (init?.method ?? "GET").toUpperCase();
372
+ const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
373
+ const startTime = Date.now();
374
+ const res = await origFetch.call(window, input, init);
375
+ if (res.status >= 400 && !isBlockedUrl(url, blocked)) {
376
+ push({
377
+ method,
378
+ url: truncateUrl(url),
379
+ status: res.status,
380
+ duration: Date.now() - startTime,
381
+ timestamp: startTime
382
+ });
383
+ }
384
+ return res;
385
+ };
386
+ origXHROpen = XMLHttpRequest.prototype.open;
387
+ XMLHttpRequest.prototype.open = function(method, url, async, username, password) {
388
+ const startTime = Date.now();
389
+ const urlStr = typeof url === "string" ? url : url.href;
390
+ this.addEventListener("load", () => {
391
+ if (this.status >= 400 && !isBlockedUrl(urlStr, blocked)) {
392
+ push({
393
+ method: method.toUpperCase(),
394
+ url: truncateUrl(urlStr),
395
+ status: this.status,
396
+ duration: Date.now() - startTime,
397
+ timestamp: startTime
398
+ });
399
+ }
400
+ });
401
+ return origXHROpen.apply(this, [method, url, async ?? true, username, password]);
402
+ };
403
+ },
404
+ stop() {
405
+ if (!active) return;
406
+ active = false;
407
+ if (origFetch) window.fetch = origFetch;
408
+ if (origXHROpen) XMLHttpRequest.prototype.open = origXHROpen;
409
+ },
410
+ getEntries() {
411
+ return [...entries];
412
+ }
413
+ };
414
+ }
415
+ var state = { user: void 0, sessionReplay: void 0 };
416
+ var listeners = /* @__PURE__ */ new Set();
417
+ function emit() {
418
+ for (const l of listeners) l();
419
+ }
420
+ function subscribe(listener) {
421
+ listeners.add(listener);
422
+ return () => listeners.delete(listener);
423
+ }
424
+ function getSnapshot() {
425
+ return state;
426
+ }
427
+ var flint = {
428
+ setUser(user) {
429
+ state = { ...state, user: user ?? void 0 };
430
+ emit();
431
+ },
432
+ setSessionReplay(url) {
433
+ state = { ...state, sessionReplay: url ?? void 0 };
434
+ emit();
435
+ }
436
+ };
437
+ var light = {
438
+ background: "rgba(255,255,255,0.90)",
439
+ backgroundSecondary: "rgba(249,250,251,0.75)",
440
+ accent: "#2563eb",
441
+ accentHover: "#1d4ed8",
442
+ text: "#111827",
443
+ textMuted: "#6b7280",
444
+ border: "rgba(255,255,255,0.9)",
445
+ 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)",
446
+ buttonText: "#ffffff",
447
+ backdropFilter: "blur(32px) saturate(1.8)"
448
+ };
449
+ var dark = {
450
+ background: "rgba(15,20,35,0.88)",
451
+ backgroundSecondary: "rgba(5,8,18,0.65)",
452
+ accent: "#4d8aff",
453
+ accentHover: "#3b6fdb",
454
+ text: "#dde3ef",
455
+ textMuted: "#6b7a93",
456
+ border: "rgba(255,255,255,0.08)",
457
+ shadow: "0 24px 60px rgba(0,0,0,0.6), 0 0 0 1px rgba(255,255,255,0.04)",
458
+ buttonText: "#ffffff",
459
+ backdropFilter: "blur(32px) saturate(1.6)"
460
+ };
461
+ function resolveTheme(theme) {
462
+ if (theme === "dark") return dark;
463
+ if (theme === "light") return light;
464
+ const override = theme;
465
+ return {
466
+ ...light,
467
+ background: override.background ?? light.background,
468
+ accent: override.accent ?? light.accent,
469
+ accentHover: override.accent ?? light.accentHover,
470
+ text: override.text ?? light.text,
471
+ border: override.border ?? light.border
472
+ };
473
+ }
45
474
 
46
475
  // src/ScreenAnnotator.tsx
47
476
  var import_modern_screenshot = require("modern-screenshot");
@@ -185,9 +614,6 @@ function ScreenAnnotator({ zIndex, onCapture, onCancel }) {
185
614
  );
186
615
  }
187
616
 
188
- // src/theme.ts
189
- var import_core2 = require("@flint/core");
190
-
191
617
  // src/FlintModal.tsx
192
618
  var import_jsx_runtime2 = require("react/jsx-runtime");
193
619
  var SEVERITIES = ["P1", "P2", "P3", "P4"];
@@ -254,7 +680,7 @@ function FlintModal({
254
680
  onError
255
681
  }) {
256
682
  const { t } = (0, import_react_i18next.useTranslation)();
257
- const colors = (0, import_core2.resolveTheme)(theme);
683
+ const colors = resolveTheme(theme);
258
684
  const isDark = theme === "dark";
259
685
  const [severity, setSeverity] = (0, import_react2.useState)("P2");
260
686
  const [description, setDescription] = (0, import_react2.useState)("");
@@ -331,13 +757,13 @@ function FlintModal({
331
757
  }
332
758
  }
333
759
  try {
334
- const res = await (0, import_core.submitReport)(serverUrl, projectKey, payload, !isText ? screenshot ?? void 0 : void 0);
760
+ const res = await submitReport(serverUrl, projectKey, payload, !isText ? screenshot ?? void 0 : void 0);
335
761
  setResult(res);
336
762
  setStatus("success");
337
763
  onSuccess?.(res);
338
764
  const events = getReplayEvents();
339
765
  if (events.length > 0) {
340
- (0, import_core.submitReplay)(serverUrl, projectKey, res.id, events).catch(() => {
766
+ submitReplay(serverUrl, projectKey, res.id, events).catch(() => {
341
767
  });
342
768
  }
343
769
  } catch (err) {
@@ -1180,18 +1606,6 @@ function CheckIcon({ size = 20 }) {
1180
1606
  var import_react4 = require("react");
1181
1607
  var import_react_i18next3 = require("react-i18next");
1182
1608
 
1183
- // src/collectors/console.ts
1184
- var import_core3 = require("@flint/core");
1185
-
1186
- // src/collectors/environment.ts
1187
- var import_core4 = require("@flint/core");
1188
-
1189
- // src/collectors/frustration.ts
1190
- var import_core5 = require("@flint/core");
1191
-
1192
- // src/collectors/network.ts
1193
- var import_core6 = require("@flint/core");
1194
-
1195
1609
  // src/i18n/index.ts
1196
1610
  var import_i18next = require("i18next");
1197
1611
  var import_react_i18next2 = require("react-i18next");
@@ -1242,11 +1656,9 @@ widgetI18n.use(import_react_i18next2.initReactI18next).init({
1242
1656
  var i18n_default = widgetI18n;
1243
1657
 
1244
1658
  // src/store.ts
1245
- var import_core7 = require("@flint/core");
1246
1659
  var import_react3 = require("react");
1247
- var import_core8 = require("@flint/core");
1248
1660
  function useFlintStore() {
1249
- return (0, import_react3.useSyncExternalStore)(import_core7.subscribe, import_core7.getSnapshot);
1661
+ return (0, import_react3.useSyncExternalStore)(subscribe, getSnapshot);
1250
1662
  }
1251
1663
 
1252
1664
  // src/FlintWidget.tsx
@@ -1308,7 +1720,7 @@ function WidgetContent({
1308
1720
  const [open, setOpen] = (0, import_react4.useState)(false);
1309
1721
  const [hovered, setHovered] = (0, import_react4.useState)(false);
1310
1722
  const pendingSelection = (0, import_react4.useRef)("");
1311
- const colors = (0, import_core2.resolveTheme)(theme);
1723
+ const colors = resolveTheme(theme);
1312
1724
  const [selectionTooltip, setSelectionTooltip] = (0, import_react4.useState)(null);
1313
1725
  const tooltipRef = (0, import_react4.useRef)(null);
1314
1726
  const triggerRef = (0, import_react4.useRef)(null);
@@ -1356,7 +1768,7 @@ function WidgetContent({
1356
1768
  const replayEvents = (0, import_react4.useRef)([]);
1357
1769
  const stopReplay = (0, import_react4.useRef)(null);
1358
1770
  if (enableConsole && !consoleCollector.current) {
1359
- consoleCollector.current = (0, import_core3.createConsoleCollector)();
1771
+ consoleCollector.current = createConsoleCollector();
1360
1772
  consoleCollector.current.start();
1361
1773
  }
1362
1774
  if (enableNetwork && !networkCollector.current) {
@@ -1367,12 +1779,12 @@ function WidgetContent({
1367
1779
  return "";
1368
1780
  }
1369
1781
  })();
1370
- networkCollector.current = (0, import_core6.createNetworkCollector)(flintHost ? [flintHost] : []);
1782
+ networkCollector.current = createNetworkCollector(flintHost ? [flintHost] : []);
1371
1783
  networkCollector.current.start();
1372
1784
  }
1373
1785
  const frustrationCollector = (0, import_react4.useRef)(null);
1374
1786
  if (enableFrustration && !frustrationCollector.current) {
1375
- frustrationCollector.current = (0, import_core5.createFrustrationCollector)();
1787
+ frustrationCollector.current = createFrustrationCollector();
1376
1788
  frustrationCollector.current.start();
1377
1789
  }
1378
1790
  (0, import_react4.useEffect)(() => {
@@ -1404,7 +1816,7 @@ function WidgetContent({
1404
1816
  if (!enableFrustration || !autoReportFrustration || !frustrationCollector.current) return;
1405
1817
  const unsubscribe = frustrationCollector.current.onFrustration(async (event) => {
1406
1818
  const user2 = resolvedUser;
1407
- await (0, import_core.submitReport)(serverUrl, projectKey, {
1819
+ await submitReport(serverUrl, projectKey, {
1408
1820
  reporterId: user2?.id ?? "anonymous",
1409
1821
  reporterName: user2?.name ?? "Anonymous",
1410
1822
  reporterEmail: user2?.email,
@@ -1412,7 +1824,7 @@ function WidgetContent({
1412
1824
  severity: event.type === "error_loop" ? "P1" : event.type === "rage_click" ? "P2" : "P3",
1413
1825
  url: event.url,
1414
1826
  meta: {
1415
- environment: (0, import_core4.collectEnvironment)(),
1827
+ environment: collectEnvironment(),
1416
1828
  consoleLogs: consoleCollector.current?.getEntries() ?? [],
1417
1829
  networkErrors: networkCollector.current?.getEntries() ?? [],
1418
1830
  frustrationEvent: event
@@ -1518,7 +1930,7 @@ function WidgetContent({
1518
1930
  onClose?.();
1519
1931
  pendingSelection.current = "";
1520
1932
  },
1521
- getEnvironment: import_core4.collectEnvironment,
1933
+ getEnvironment: collectEnvironment,
1522
1934
  getConsoleLogs: () => consoleCollector.current?.getEntries() ?? [],
1523
1935
  getNetworkErrors: () => networkCollector.current?.getEntries() ?? [],
1524
1936
  getReplayEvents: () => [...replayEvents.current],