Live video on the AT Protocol
1// Super quick and dirty hooks to get error reporting in
2
3import { Platform } from "react-native";
4import pkg from "../package.json";
5
6let errorReportingConfig = {
7 ip: "",
8};
9
10// random string set on load
11let randomString = Math.random().toString(36);
12
13// get it from cdn-cgi/trace
14// cloudflare only!
15const fetchIp = async () => {
16 try {
17 const res = await fetch("https://api.ipify.org?format=json");
18 const j = await res.json();
19 errorReportingConfig.ip = j.ip;
20 } catch (e) {
21 // ignore
22 }
23};
24fetchIp();
25
26const getReportingUrl = (): string => {
27 return "/api/player-event";
28};
29
30export const register = () => {
31 console.log("file registered, error reporting should be ok");
32};
33
34const getExtraInfo = () => {
35 return {
36 os: Platform.OS,
37 osVersion: Platform.Version,
38 appVersion: pkg.version,
39 environment: __DEV__ ? "development" : "production",
40 ip: errorReportingConfig.ip,
41 };
42};
43
44const getPlayerId = (): string => {
45 if (errorReportingConfig.ip) {
46 const encoded = "app-" + btoa(errorReportingConfig.ip);
47 return encoded;
48 }
49
50 return `app-${randomString}`;
51};
52
53const sendPlayerEvent = async (
54 eventType: string,
55 message: string,
56 meta: any = {},
57) => {
58 try {
59 const reportingURL = getReportingUrl();
60
61 const playerEventData = {
62 time: new Date().toISOString(),
63 playerId: getPlayerId(),
64 eventType,
65 meta: {
66 message,
67 timestamp: new Date().toISOString(),
68 userAgent:
69 typeof navigator !== "undefined" ? navigator.userAgent : undefined,
70 url: typeof window !== "undefined" ? window.location?.href : undefined,
71 ...getExtraInfo(),
72 ...meta,
73 },
74 };
75
76 await fetch(reportingURL, {
77 method: "POST",
78 headers: {
79 "Content-Type": "application/json",
80 },
81 body: JSON.stringify(playerEventData),
82 });
83 } catch (e) {
84 console.warn("Failed to send error event:", e);
85 }
86};
87
88// Hook into React Native unhandled errors
89// @ts-expect-error
90if (global.ErrorUtils) {
91 // @ts-expect-error
92 const defaultHandler = global.ErrorUtils.getGlobalHandler();
93 // @ts-expect-error
94 global.ErrorUtils.setGlobalHandler(
95 (error: { message: string; stack: any }, isFatal: any) => {
96 sendPlayerEvent("unhandled-error", error.message, {
97 stack: error.stack,
98 isFatal,
99 source: "react-native-error-utils",
100 });
101
102 if (defaultHandler) {
103 defaultHandler(error, isFatal);
104 }
105 },
106 );
107}
108if (typeof process !== "undefined" && process.on) {
109 process.on("uncaughtException", (error: Error) => {
110 sendPlayerEvent("uncaught-exception", error.message, {
111 stack: error.stack,
112 source: "node-uncaught-exception",
113 });
114 });
115
116 process.on("unhandledRejection", (reason: any, promise: Promise<any>) => {
117 const message = reason instanceof Error ? reason.message : String(reason);
118 const stack = reason instanceof Error ? reason.stack : undefined;
119
120 sendPlayerEvent(
121 "unhandled-rejection",
122 `Unhandled Promise Rejection: ${message}`,
123 {
124 stack,
125 source: "node-unhandled-rejection",
126 reason: reason instanceof Error ? undefined : reason,
127 },
128 );
129 });
130}
131
132// Hook into uncaught errors (Browser)
133if (typeof window !== "undefined" && Platform.OS === "web") {
134 window.addEventListener("error", (event: ErrorEvent) => {
135 sendPlayerEvent("javascript-error", event.message, {
136 stack: event.error?.stack,
137 source: "browser-window-error",
138 filename: event.filename,
139 lineno: event.lineno,
140 colno: event.colno,
141 });
142 });
143
144 window.addEventListener(
145 "unhandledrejection",
146 (event: PromiseRejectionEvent) => {
147 const message =
148 event.reason instanceof Error
149 ? event.reason.message
150 : String(event.reason);
151 const stack =
152 event.reason instanceof Error ? event.reason.stack : undefined;
153
154 sendPlayerEvent(
155 "unhandled-rejection",
156 `Unhandled Promise Rejection: ${message}`,
157 {
158 stack,
159 source: "browser-unhandled-rejection",
160 reason: event.reason instanceof Error ? undefined : event.reason,
161 },
162 );
163 },
164 );
165}
166
167// Report console errors and warnings
168const originalError = console.error;
169const originalWarn = console.warn;
170
171console.error = (...args: any[]) => {
172 const message = args.join(" ");
173 sendPlayerEvent("console-error", message, {
174 source: "console-error",
175 args: args,
176 });
177 originalError(...args);
178};
179
180console.warn = (...args: any[]) => {
181 const message = args.join(" ");
182 sendPlayerEvent("console-warning", message, {
183 source: "console-warning",
184 args: args,
185 });
186 originalWarn(...args);
187};