import { requireOptionalNativeModule } from "expo-modules-core"; import React from "react"; import { Platform, StyleSheet, Text, View } from "react-native"; interface Props { children: React.ReactNode; onError?: (error: Error, errorInfo: React.ErrorInfo) => void; } interface State { hasError: boolean; error: Error | null; } const IFRAME_ID = "rork-web-preview"; const webTargetOrigins = [ "http://localhost:3000", "https://rorkai.com", "https://rork.com", ]; const BridgeModule = requireOptionalNativeModule("Bridge"); function sendErrorToIframeParent(error: any, errorInfo?: any) { const errorData = { message: error?.message || error?.toString() || "Unknown error", stack: error?.stack, componentStack: errorInfo?.componentStack, timestamp: new Date().toISOString(), }; if (Platform.OS === "web" && typeof window !== "undefined") { console.debug("Sending error to parent via postMessage:", { error, errorInfo, referrer: document.referrer, }); const errorMessage = { type: "ERROR", error: errorData, iframeId: IFRAME_ID, }; try { window.parent.postMessage( errorMessage, webTargetOrigins.includes(document.referrer) ? document.referrer : "*", ); } catch (postMessageError) { console.warn("Failed to send error to parent:", postMessageError); } } else if (Platform.OS !== "web" && BridgeModule) { BridgeModule?.sendMessage({ type: "runtime-error", data: JSON.stringify(errorData), }); } } if (Platform.OS === "web" && typeof window !== "undefined") { window.addEventListener( "error", (event) => { event.preventDefault(); const errorDetails = event.error ?? { message: event.message ?? "Unknown error", filename: event.filename ?? "Unknown file", lineno: event.lineno ?? "Unknown line", colno: event.colno ?? "Unknown column", }; sendErrorToIframeParent(errorDetails); }, true, ); window.addEventListener( "unhandledrejection", (event) => { event.preventDefault(); sendErrorToIframeParent(event.reason); }, true, ); } const originalConsoleError = console.error; console.error = (...args) => { sendErrorToIframeParent(args.join(" ")); originalConsoleError.apply(console, args); }; export class RorkErrorBoundary extends React.Component { constructor(props: Props) { super(props); this.state = { hasError: false, error: null }; } static getDerivedStateFromError(error: Error) { return { hasError: true, error }; } componentDidCatch(error: Error, errorInfo: React.ErrorInfo) { sendErrorToIframeParent(error, errorInfo); if (this.props.onError) { this.props.onError(error, errorInfo); } } render() { if (this.state.hasError) { return ( Something went wrong {this.state.error?.message} {Platform.OS !== "web" && ( Please check your device logs for more details. )} ); } return this.props.children; } } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: "#fff", }, content: { flex: 1, alignItems: "center", justifyContent: "center", padding: 20, }, title: { fontSize: 36, textAlign: "center", fontWeight: "bold", marginBottom: 8, }, subtitle: { fontSize: 14, color: "#666", marginBottom: 12, textAlign: "center", }, description: { fontSize: 14, color: "#666", textAlign: "center", marginTop: 8, }, });