diff --git a/apps/expo-demo/.gitignore b/apps/expo-demo/.gitignore new file mode 100644 index 0000000..8c0a260 --- /dev/null +++ b/apps/expo-demo/.gitignore @@ -0,0 +1,2 @@ +ios/ +android/ diff --git a/apps/expo-demo/App.tsx b/apps/expo-demo/App.tsx new file mode 100644 index 0000000..4339566 --- /dev/null +++ b/apps/expo-demo/App.tsx @@ -0,0 +1,71 @@ +import SandboxReactNativeView from '@callstack/react-native-sandbox' +import React, {useState} from 'react' +import {SafeAreaView, StyleSheet, Text, View} from 'react-native' + +import CrashIfYouCanDemo from './CrashIfYouCanDemo' + +const DemoApp: React.FC = () => { + const [lastError, setLastError] = useState(null) + + return ( + + + + Main App + + + + Sandboxed + {lastError && {lastError}} + { + const message = `${error.isFatal ? '[fatal]' : '[warn]'} ${error.name}: ${error.message}` + console.warn('Sandbox error:', message) + setLastError(message) + return false + }} + /> + + + + ) +} + +const styles = StyleSheet.create({ + safeArea: { + flex: 1, + }, + container: { + flex: 1, + flexDirection: 'row', + padding: 16, + }, + columnSandbox: { + borderWidth: 1, + borderColor: '#8232ff', + borderRadius: 4, + }, + column: { + flex: 1, + padding: 8, + }, + header: { + fontWeight: 'bold', + fontSize: 16, + marginBottom: 8, + textAlign: 'center', + }, + sandboxView: { + flex: 1, + }, + errorText: { + color: 'red', + fontSize: 11, + marginBottom: 4, + }, +}) + +export default DemoApp diff --git a/apps/expo-demo/CrashIfYouCanDemo.tsx b/apps/expo-demo/CrashIfYouCanDemo.tsx new file mode 100644 index 0000000..165b2c3 --- /dev/null +++ b/apps/expo-demo/CrashIfYouCanDemo.tsx @@ -0,0 +1,69 @@ +import React, {useState} from 'react' +import { + Button, + LogBox, + NativeModules, + ScrollView, + StyleSheet, + View, +} from 'react-native' + +export default function CrashIfYouCanDemo() { + const [counter, setCounter] = useState(0) + + const triggerCrash = () => { + // @ts-ignore + global.nonExistentMethod() // Should crash the app + } + + const overwriteGlobal = () => { + // Overwrite console.log to something harmful + console.log = () => { + throw new Error('console.log has been hijacked!') + } + console.log('This will now throw') // This will crash or break logs + } + + const accessBlockedTurboModule = () => { + const FileReaderModule = NativeModules.FileReaderModule + FileReaderModule.readAsText('/some/file.txt') + .then((text: string) => console.log(text)) + .catch((err: any) => console.log(err.message)) + } + + // Hangs the sandbox JS thread only — the host app stays responsive because + // each sandbox runs in its own Hermes instance and JS thread. + const infiniteLoop = () => { + while (true) {} + } + + const incrementCounter = () => { + setCounter(counter + 1) + } + + return ( + +