| 1 | "use client"; |
| 2 | |
| 3 | import { useEffect } from "react"; |
| 4 | |
| 5 | export function DevErrorReporter() { |
| 6 | useEffect(() => { |
| 7 | if (process.env.NODE_ENV === "production") return; |
| 8 | |
| 9 | const originalError = console.error; |
| 10 | const originalWarn = console.warn; |
| 11 | |
| 12 | function report(type: string, args: unknown[]) { |
| 13 | const message = args |
| 14 | .map((a) => (typeof a === "string" ? a : JSON.stringify(a, null, 2))) |
| 15 | .join(" ") |
| 16 | .slice(0, 4000); |
| 17 | |
| 18 | fetch("/api/dev-errors", { |
| 19 | method: "POST", |
| 20 | headers: { "Content-Type": "application/json" }, |
| 21 | body: JSON.stringify({ type, message, url: window.location.href }), |
| 22 | }).catch(() => {}); |
| 23 | } |
| 24 | |
| 25 | console.error = (...args: unknown[]) => { |
| 26 | report("console.error", args); |
| 27 | originalError.apply(console, args); |
| 28 | }; |
| 29 | |
| 30 | console.warn = (...args: unknown[]) => { |
| 31 | report("console.warn", args); |
| 32 | originalWarn.apply(console, args); |
| 33 | }; |
| 34 | |
| 35 | const onError = (e: ErrorEvent) => { |
| 36 | report("unhandled-error", [e.message, e.filename, e.lineno, e.colno]); |
| 37 | }; |
| 38 | |
| 39 | const onRejection = (e: PromiseRejectionEvent) => { |
| 40 | report("unhandled-rejection", [String(e.reason)]); |
| 41 | }; |
| 42 | |
| 43 | window.addEventListener("error", onError); |
| 44 | window.addEventListener("unhandledrejection", onRejection); |
| 45 | |
| 46 | return () => { |
| 47 | console.error = originalError; |
| 48 | console.warn = originalWarn; |
| 49 | window.removeEventListener("error", onError); |
| 50 | window.removeEventListener("unhandledrejection", onRejection); |
| 51 | }; |
| 52 | }, []); |
| 53 | |
| 54 | return null; |
| 55 | } |
| 56 | |