import { usePathname, useRouter } from 'expo-router';
import { App } from 'expo-router/build/qualified-entry';
import React, { memo, useEffect } from 'react';
import './src/__create/polyfills';
import { ErrorBoundary } from './src/__create/ErrorBoundary';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import { Toaster } from 'sonner-native';
import { AlertModal } from './polyfills/web/alerts.web';
import './global.css';
const RUNTIME_ERROR_PATTERNS = [
/fetch failed/i,
/networks*(error|request)/i,
/failed to fetch/i,
/load failed/i,
/ECONNREFUSED/i,
/ECONNRESET/i,
/ETIMEDOUT/i,
/ENOTFOUND/i,
/ERR_CONNECTION/i,
/aborted/i,
/timeout/i,
/socket hang up/i,
/503\b/,
/502\b/,
/504\b/,
/getaddrinfo/i,
];
function isRuntimeError(msg: string) {
return RUNTIME_ERROR_PATTERNS.some((p) => p.test(msg));
}
function postErrorToParent(message: string, name: string, stack: string) {
try {
if (window.parent !== window) {
window.parent.postMessage(
{
type: 'sandbox:error:detected',
error: { message, name, stack },
},
'*'
);
}
} catch {}
}
const GlobalErrorReporter = () => {
useEffect(() => {
if (typeof window === 'undefined') {
return;
}
const errorHandler = (event: ErrorEvent) => {
if (typeof event.preventDefault === 'function') event.preventDefault();
console.error(event.error);
const error = event.error;
const message = error?.message || event.message || 'Unknown error';
if (!isRuntimeError(message)) {
postErrorToParent(message, error?.name || 'Error', error?.stack || '');
}
};
const unhandledRejectionHandler = (event: PromiseRejectionEvent) => {
if (typeof event.preventDefault === 'function') event.preventDefault();
const reason = event.reason;
console.error('Unhandled promise rejection:', reason);
const message = reason?.message || String(reason || '');
if (isRuntimeError(message)) return;
const isCodeError =
reason instanceof TypeError ||
reason instanceof ReferenceError ||
reason instanceof SyntaxError ||
reason?.code === 'MODULE_RESOLVE_FAILED';
if (!isCodeError) return;
postErrorToParent(message, reason?.name || 'Error', reason?.stack || '');
};
window.addEventListener('error', errorHandler);
window.addEventListener('unhandledrejection', unhandledRejectionHandler);
return () => {
window.removeEventListener('error', errorHandler);
window.removeEventListener(
'unhandledrejection',
unhandledRejectionHandler
);
};
}, []);
return null;
};
const Wrapper = memo(() => {
return (
);
});
const healthyResponse = {
type: 'sandbox:mobile:healthcheck:response',
healthy: true,
};
const useHandshakeParent = () => {
useEffect(() => {
const handleMessage = (event: MessageEvent) => {
if (event.data.type === 'sandbox:mobile:healthcheck') {
window.parent.postMessage(healthyResponse, '*');
}
};
window.addEventListener('message', handleMessage);
// Immediately respond to the parent window with a healthy response in
// case we missed the healthcheck message
window.parent.postMessage(healthyResponse, '*');
return () => {
window.removeEventListener('message', handleMessage);
};
}, []);
};
const CreateApp = () => {
const router = useRouter();
const pathname = usePathname();
useHandshakeParent();
useEffect(() => {
const handleMessage = (event: MessageEvent) => {
if (
event.data.type === 'sandbox:navigation' &&
event.data.pathname !== pathname
) {
router.push(event.data.pathname);
}
};
window.addEventListener('message', handleMessage);
window.parent.postMessage({ type: 'sandbox:mobile:ready' }, '*');
return () => {
window.removeEventListener('message', handleMessage);
};
}, [router, pathname]);
useEffect(() => {
window.parent.postMessage(
{
type: 'sandbox:mobile:navigation',
pathname,
},
'*'
);
}, [pathname]);
return (
<>
>
);
};
export default CreateApp;