@not-true/devtools
Version:
Remote debugging and development tools client library for React Native applications
423 lines (325 loc) • 11.5 kB
Markdown
# @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.