UNPKG

@not-true/devtools

Version:

Remote debugging and development tools client library for React Native applications

423 lines (325 loc) 11.5 kB
# @not-true/devtools Remote debugging and development tools client library for React Native applications. ## Features - 🔧 **Real-time Console Logging** - Automatically capture and stream console output - 🎮 **Remote REPL** - Execute JavaScript commands remotely on your device - 📱 **Screenshot Capture** - Take screenshots of your app remotely - 🔄 **State Synchronization** - Monitor Redux, Context, and AsyncStorage state - ⚙️ **Remote Configuration** - Update feature flags and config dynamically - 🔌 **Automatic Reconnection** - Robust connection handling with queue management - 📊 **Device Information** - Collect and display device/app metadata - 🚀 **TypeScript Support** - Fully typed for better developer experience ## Installation ```bash npm install @not-true/devtools # or yarn add @not-true/devtools ``` ### Dependencies The package includes socket.io-client 2.5.0 which is optimized for React Native compatibility: ```bash npm install @not-true/devtools # socket.io-client 2.5.0 is included as a dependency ``` ## Quick Start ### Basic Setup ```typescript import RemoteDevTools from '@not-true/devtools'; const devTools = new RemoteDevTools({ serverUrl: 'http://your-devtools-server:3000', name: 'My React Native App', version: '1.0.0', }, { onConnect: () => console.log('Connected to DevTools'), onDisconnect: () => console.log('Disconnected from DevTools'), }); // Connect to the server await devTools.connect(); ``` ### With React Hooks ```typescript import React, { useEffect } from 'react'; import { useRemoteDevTools, useReduxSync } from '@not-true/devtools'; import { store } from './store'; // Your Redux store function App() { const { devTools, isConnected, connect, connectionStatus } = useRemoteDevTools({ serverUrl: 'http://localhost:3000', name: 'My App', version: '1.0.0', }, { onConnect: () => console.log('DevTools connected!'), onRemoteConfig: (config) => { // Handle remote configuration updates console.log('Received config:', config); }, }); // Automatically sync Redux state useReduxSync(devTools, store); useEffect(() => { connect(); }, [connect]); return ( <div> <p>DevTools Status: {connectionStatus}</p> {/* Your app content */} </div> ); } ``` ## Configuration ### RemoteDevToolsConfig ```typescript interface RemoteDevToolsConfig { serverUrl: string; // Required: WebSocket server URL name: string; // Required: Client display name version: string; // Required: Application version // Optional settings maxQueueSize?: number; // Default: 1000 maxReconnectAttempts?: number; // Default: 5 reconnectDelay?: number; // Default: 1000ms // Feature toggles enableConsoleLogging?: boolean; // Default: true enableStateSync?: boolean; // Default: true enableScreenshots?: boolean; // Default: true enableREPL?: boolean; // Default: true enableRemoteConfig?: boolean; // Default: true // Screenshot settings screenshotQuality?: number; // 0-1, default: 0.8 screenshotFormat?: 'png' | 'jpg'; // Default: 'png' // State sync settings stateUpdateThrottle?: number; // ms, default: 500 // Custom info deviceInfo?: object; clientInfo?: object; } ``` ## Usage Examples ### Manual Logging ```typescript // These will be automatically captured if enableConsoleLogging is true console.log('Hello from device!'); console.warn('Warning message'); console.error('Error occurred'); // Or send logs manually devTools.log('info', 'Custom log message', { data: 'example' }); ``` ### State Synchronization ```typescript // Redux state sync (automatic with useReduxSync hook) import { StateUtils } from '@not-true/devtools'; const stateUpdate = StateUtils.createReduxStateUpdate(store.getState()); devTools.updateState(stateUpdate); // Custom state sync const customState = StateUtils.createCustomStateUpdate({ userPreferences: { theme: 'dark', language: 'en' }, featureFlags: { newUI: true } }, 'app-state'); devTools.updateState(customState); // AsyncStorage sync const asyncStorageUpdate = StateUtils.createAsyncStorageUpdate('userToken', 'abc123'); devTools.updateState(asyncStorageUpdate); ``` ### Screenshot Capture The client library requires you to implement your own screenshot capture (e.g., using `react-native-view-shot` or similar): ```typescript import { ScreenshotUtils } from '@not-true/devtools'; // You need to install and import your screenshot library // import { captureScreen } from 'react-native-view-shot'; // Handle remote screenshot requests const devTools = new RemoteDevTools(config, { onScreenshotRequest: async (options) => { // Implement your own screenshot capture const uri = await captureScreen({ format: options.format || 'png', quality: options.quality || 0.8, result: 'data-uri' // or 'base64' }); // Convert to base64 if needed const base64 = ScreenshotUtils.dataURIToBase64(uri); // Create screenshot data with metadata return ScreenshotUtils.createScreenshotWithMetadata(base64, { width: 375, // actual screen width height: 812, // actual screen height format: options.format || 'png' }); } }); // Send screenshot manually const sendScreenshot = async () => { try { const uri = await captureScreen({ format: 'png', quality: 0.8 }); const base64 = ScreenshotUtils.dataURIToBase64(uri); const screenshot = ScreenshotUtils.createScreenshotWithMetadata(base64, { width: 375, height: 812, format: 'png' }); devTools.sendScreenshot(screenshot); } catch (error) { console.error('Screenshot failed:', error); } }; ``` ### REPL Command Handling ```typescript const devTools = new RemoteDevTools(config, { onREPLCommand: async (command) => { // Handle remote JavaScript execution try { // Safely evaluate the command if (command.command === 'getAppVersion()') { return '1.0.0'; } if (command.command === 'getCurrentUser()') { return { id: 1, name: 'John Doe' }; } // For security, limit what can be executed throw new Error('Command not allowed'); } catch (error) { throw error; } } }); ``` ### Remote Configuration ```typescript const devTools = new RemoteDevTools(config, { onRemoteConfig: (config) => { // Apply configuration changes if (config.config.enableDarkMode) { // Enable dark mode } if (config.config.apiEndpoint) { // Update API endpoint } // Update feature flags updateFeatureFlags(config.config.featureFlags || {}); } }); ``` ### Context State Sync ```typescript import React, { useContext } from 'react'; import { useContextSync } from '@not-true/devtools'; const ThemeContext = React.createContext({ theme: 'light' }); function MyComponent({ devTools }) { const themeValue = useContext(ThemeContext); // Automatically sync context value useContextSync(devTools, themeValue, 'ThemeContext'); return <div>Component content</div>; } ``` ## Advanced Usage ### Custom Queue Management ```typescript import { QueueManager } from '@not-true/devtools'; const customQueue = new QueueManager(500); // Custom size limit // Manually manage queue customQueue.enqueue({ type: 'log', data: { level: 'info', message: 'Custom message' }, timestamp: Date.now() }); // Get queue stats const stats = customQueue.getStats(); console.log(`Queue size: ${stats.size}/${stats.maxSize}`); ``` ### Device Information ```typescript import { DeviceInfoUtils } from '@not-true/devtools'; const deviceInfo = DeviceInfoUtils.getDeviceInfo(); console.log('Platform:', deviceInfo.platform); console.log('OS Version:', deviceInfo.osVersion); console.log('Screen Size:', deviceInfo.screenSize); const memoryInfo = DeviceInfoUtils.getMemoryInfo(); const networkInfo = DeviceInfoUtils.getNetworkInfo(); ``` ### Error Handling ```typescript const devTools = new RemoteDevTools(config, { onError: (error) => { console.error('DevTools error:', error); // Handle or report error }, onReconnectError: (error) => { console.error('Failed to reconnect:', error); // Show user notification or fallback } }); ``` ## API Reference ### RemoteDevTools Class #### Methods - `connect()`: Promise<void> - Connect to the server - `disconnect()`: void - Disconnect from the server - `log(level, ...args)`: void - Send log entry - `updateState(stateUpdate)`: void - Send state update - `sendScreenshot(data)`: void - Send screenshot data - `sendREPLResult(result)`: void - Send REPL execution result - `isConnectedToServer()`: boolean - Check connection status - `getConfig()`: RemoteDevToolsConfig - Get current configuration - `updateConfig(config)`: void - Update configuration - `destroy()`: void - Cleanup and disconnect ### React Hooks - `useRemoteDevTools(config, handlers)` - Main hook for RemoteDevTools integration - `useReduxSync(devTools, store, throttleMs?)` - Automatic Redux state synchronization - `useREPLHandler(devTools, evaluator?)` - REPL command handling - `useScreenshotHandler(devTools, capturer?)` - Screenshot request handling - `useContextSync(devTools, contextValue, name, throttleMs?)` - React Context synchronization ### Utility Classes - `DeviceInfoUtils` - Device and platform information - `QueueManager` - Message queue management - `ScreenshotUtils` - Screenshot capture utilities - `StateUtils` - State management helpers ## Development Server This client library works with the Remote DevTools Platform server. To set up the server: ```bash # Clone the server repository git clone https://github.com/your-org/remote-devtools-platform cd remote-devtools-platform # Install dependencies npm install # Start development server npm run dev # Or start production server npm run build && npm start ``` The dashboard will be available at `http://localhost:3000`. ## Security Considerations - **REPL Execution**: The remote REPL feature allows arbitrary code execution. Only use in development environments. - **Network Security**: Use HTTPS/WSS in production environments. - **Data Sanitization**: State data is automatically sanitized to prevent large payloads and circular references. - **Access Control**: Implement proper authentication/authorization in your server setup. ## Platform Support - ✅ React Native (iOS/Android) - ✅ Expo (managed/bare workflow) - ⚠️ Web (limited screenshot support) - ❌ React Native Windows/macOS (not tested) ## Troubleshooting ### Connection Issues ```typescript // Check if server is accessible const devTools = new RemoteDevTools(config, { onConnect: () => console.log('✅ Connected'), onDisconnect: () => console.log('❌ Disconnected'), onReconnect: (attempt) => console.log(`🔄 Reconnecting... (${attempt})`), onError: (error) => console.error('❗ Error:', error) }); ``` ### Performance Issues ```typescript // Increase throttling for state updates const config = { // ... other config stateUpdateThrottle: 1000, // Update at most once per second }; // Reduce queue size const config = { // ... other config maxQueueSize: 100, }; ``` ## Contributing Contributions are welcome! Please see our contributing guidelines for more details. ## License MIT License - see LICENSE file for details.