Repository: LovesWorking/rn-better-dev-tools
Branch: main
Commit: d300ff7074bd
Files: 78
Total size: 260.7 KB
Directory structure:
gitextract_s7vy5tt0/
├── .eslintignore
├── .eslintrc.json
├── .github/
│ └── workflows/
│ └── build.yml
├── .gitignore
├── .npmrc
├── DEVELOPMENT.md
├── GITHUB_RELEASE.md
├── README.md
├── RELEASE.md
├── assets/
│ └── icon.icns
├── auto-release.sh
├── build-and-pack.sh
├── build-macos.sh
├── config.js
├── copy-to-desktop.sh
├── entitlements.plist
├── forge.config.ts
├── forge.env.d.ts
├── index.html
├── package.json
├── postcss.config.js
├── release-version.sh
├── socket-client.js
├── src/
│ ├── auto-updater.ts
│ ├── components/
│ │ ├── App.tsx
│ │ └── external-dash/
│ │ ├── Dash.tsx
│ │ ├── DeviceSelection.tsx
│ │ ├── LogConsole.tsx
│ │ ├── Main.tsx
│ │ ├── NoDevicesConnected.tsx
│ │ ├── UserInfo/
│ │ │ ├── DeviceSpecificationsSection.tsx
│ │ │ ├── EnvironmentVariablesSection.tsx
│ │ │ ├── InfoRow.tsx
│ │ │ ├── StorageControlsSection.tsx
│ │ │ ├── TargetGlowEffect.tsx
│ │ │ ├── UserCardDetails.tsx
│ │ │ ├── UserCardHeader.tsx
│ │ │ └── index.ts
│ │ ├── UserInfo.tsx
│ │ ├── _hooks/
│ │ │ └── useConnectedUsers.ts
│ │ ├── hooks/
│ │ │ └── useDevToolsEventHandler.ts
│ │ ├── providers.tsx
│ │ ├── shared/
│ │ │ ├── hydration.ts
│ │ │ └── types.ts
│ │ ├── types/
│ │ │ ├── ClientQuery.ts
│ │ │ └── User.ts
│ │ ├── useSyncQueriesWeb.ts
│ │ └── utils/
│ │ ├── devToolsEvents.ts
│ │ ├── logStore.ts
│ │ ├── logger.ts
│ │ ├── platformUtils.tsx
│ │ ├── storageQueryKeys.ts
│ │ └── storageStore.ts
│ ├── config.ts
│ ├── index.css
│ ├── main.ts
│ ├── preload.ts
│ ├── react-query-external-sync/
│ │ ├── README.md
│ │ ├── User.ts
│ │ ├── hydration.ts
│ │ ├── index.ts
│ │ ├── platformUtils.ts
│ │ ├── types.ts
│ │ ├── useMySocket.ts
│ │ ├── useSyncQueries.ts
│ │ └── utils/
│ │ └── logger.ts
│ ├── renderer.ts
│ ├── renderer.tsx
│ ├── server/
│ │ └── socketHandle.ts
│ ├── server.ts
│ └── types.d.ts
├── tailwind.config.js
├── tanstack-query-devtools-5.74.7.tgz
├── tanstack-react-query-devtools-5.75.7.tgz
├── tsconfig.json
├── vite.main.config.ts
├── vite.preload.config.ts
└── vite.renderer.config.ts
================================================
FILE CONTENTS
================================================
================================================
FILE: .eslintignore
================================================
# Dependencies
node_modules/
# Build outputs
build/
dist/
.next/
out/
# IDE Specific
.idea/
.vscode/
# Specific files with TypeScript issues
src/components/external-dash/LogConsole.tsx
================================================
FILE: .eslintrc.json
================================================
{
"env": {
"browser": true,
"es6": true,
"node": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended",
"plugin:import/recommended",
"plugin:import/electron",
"plugin:import/typescript"
],
"parser": "@typescript-eslint/parser",
"settings": {
"import/resolver": {
"node": {
"extensions": [".js", ".jsx", ".ts", ".tsx"]
}
},
"import/ignore": ["@tanstack/react-query-devtools"]
},
"rules": {
"import/no-unresolved": [
"error",
{
"ignore": ["^@tanstack/react-query-devtools"]
}
]
}
}
================================================
FILE: .github/workflows/build.yml
================================================
---
name: Build/release
on:
push:
tags:
- "v*"
# Add permissions block
permissions:
contents: write
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [macos-latest, ubuntu-latest, windows-latest]
arch: [x64, arm64]
steps:
- name: Check out Git repository
uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v3
with:
version: 10.4.1
- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: "pnpm"
- name: Install dependencies
run: pnpm install
- name: Import certificates
if: runner.os == 'macOS'
env:
MACOS_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE }}
MACOS_CERTIFICATE_PWD: ${{ secrets.MACOS_CERTIFICATE_PWD }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
run: |
# Write certificate to file and decode it
echo "$MACOS_CERTIFICATE" | base64 -D > certificate.p12
# Create keychain
security create-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
security default-keychain -s build.keychain
security unlock-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
# Import certificate
security import certificate.p12 -k build.keychain -P "$MACOS_CERTIFICATE_PWD" -T /usr/bin/codesign
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" build.keychain
# Verify certificate import
security find-identity -v -p codesigning build.keychain
- name: Build and package app
env:
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
ARCH: ${{ matrix.arch }}
run: pnpm run make --arch=${{ matrix.arch }}
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: app-${{ matrix.os }}-${{ matrix.arch }}
path: "out/**/*.zip"
if-no-files-found: error
release:
needs: build
runs-on: ubuntu-latest
steps:
- name: Download all uploaded artifacts
uses: actions/download-artifact@v4
with:
path: ./downloaded-artifacts
- name: Create or update release
uses: ncipollo/release-action@v1
if: startsWith(github.ref, 'refs/tags/')
with:
allowUpdates: true
replacesArtifacts: true
removeArtifacts: true
artifacts: "downloaded-artifacts/**/*.zip"
draft: false
prerelease: false
token: ${{ secrets.GITHUB_TOKEN }}
================================================
FILE: .gitignore
================================================
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
.DS_Store
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
# parcel-bundler cache (https://parceljs.org/)
.cache
# next.js build output
.next
# nuxt.js build output
.nuxt
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# Webpack
.webpack/
# Vite
.vite/
# Electron-Forge
out/
# Yalc
.yalc/.env
# Environment variables
.env.local
.env.*
================================================
FILE: .npmrc
================================================
node-linker = hoisted
================================================
FILE: DEVELOPMENT.md
================================================
# Development Guide
This guide covers everything you need to know about developing React Native DevTools.
## 🛠 Prerequisites
- Node.js 20 or later
- pnpm 10.4.1 or later
- macOS for building and signing
- Apple Developer account for signing
- GitHub CLI (`gh`) for releases
## 🚀 Getting Started
1. Clone the repository:
```bash
git clone https://github.com/LovesWorking/rn-better-dev-tools.git
cd rn-better-dev-tools
```
2. Install dependencies:
```bash
pnpm install
```
3. Create a `.env` file based on `.env.example`:
```bash
cp .env.example .env
```
4. Fill in your Apple Developer credentials in `.env`:
```
APPLE_ID=your.email@example.com
APPLE_PASSWORD=app-specific-password
APPLE_TEAM_ID=your-team-id
```
## 🏗 Building
### Development Build
```bash
# Start in development mode with hot reload
pnpm start
# Build and copy to desktop for testing
pnpm run make:desktop
# Build only
pnpm run make
```
### Release Build
We provide an automated release script that:
- Bumps version (minor)
- Builds locally to verify
- Commits changes
- Creates and pushes tag
- Monitors GitHub Action progress
```bash
# Using npm script
pnpm run auto-release
# Or directly
./auto-release.sh
```
## 🐛 Debugging
### Enable Debug Logs
Add to your `.env`:
```bash
DEBUG=electron-osx-sign*
```
### Common Issues
1. **Build Hanging on "Finalizing package"**
- Check Apple Developer credentials
- Verify keychain access
- Run with debug logs enabled
2. **Permission Issues**
```bash
# Fix directory permissions
sudo chown -R $(whoami) .
# Clean build artifacts
rm -rf .vite out
```
3. **Certificate Issues**
- Verify Apple Developer membership is active
- Check Team ID matches in `.env`
- Ensure app-specific password is correct
### Development Commands
```bash
# Clean install
pnpm run nuke
# Package without making distributables
pnpm run package
# Run linter
pnpm run lint
```
## 📦 Project Structure
```
.
├── src/ # Source code
│ ├── main.ts # Main process
│ ├── preload.ts # Preload scripts
│ └── components/ # React components
├── assets/ # Static assets
├── .github/workflows/ # GitHub Actions
└── forge.config.ts # Electron Forge config
```
## 🔄 Release Process
### Automatic Release
```bash
./auto-release.sh
```
### Manual Release Steps
1. Update version in `package.json`
2. Build and test locally
3. Create and push tag
4. GitHub Action will build and publish
## 🧪 Testing
Before submitting a PR:
1. Test in development mode (`pnpm start`)
2. Build and test locally (`pnpm run make:desktop`)
3. Verify all features work
4. Check console for errors
5. Run linter (`pnpm run lint`)
================================================
FILE: GITHUB_RELEASE.md
================================================
# GitHub Release Process
This guide explains how to release updates to GitHub and enable auto-updating for React Native DevTools.
## Automated Release Process
The recommended way to create a new release is to use the automated script:
1. Make sure your changes are committed to the main branch
2. Run the release script:
```bash
pnpm run release
# or directly with
./release-version.sh
```
3. Follow the interactive prompts to:
- Select the version bump type (patch, minor, major, or custom)
- Enter release notes
- Confirm the release
4. The script will:
- Update the version in package.json
- Commit and push the changes
- Create and push a git tag
- Monitor the GitHub Actions workflow
- Automatically publish the release when complete
## Manual Releases
If you need to manually publish a release:
1. Ensure you have a GitHub access token with "repo" permissions
2. Set the token as an environment variable:
```bash
export GITHUB_TOKEN=your_github_token
```
3. Run the pack script:
```bash
pnpm run pack
# or directly with
./build-and-pack.sh
```
## GitHub Actions Automated Releases
For automated releases using GitHub Actions:
1. Create a new tag following semantic versioning:
```bash
git tag v1.x.x
git push origin v1.x.x
```
2. The GitHub Actions workflow will automatically build and release the app
3. The release will initially be created as a draft
4. Review the release and publish it when ready
## Auto-Updates
The app is configured to automatically check for updates when running. When a new version is released on GitHub:
1. Users with the previous version will automatically receive update notifications
2. Updates are downloaded in the background
3. The update will be installed when the user restarts the app
## Configuration Files
The auto-update system is configured in several files:
- `forge.config.ts`: Contains the GitHub publisher configuration
- `package.json`: Contains the electron-builder configuration
- `src/auto-updater.ts`: Implements the auto-update checking logic
- `.github/workflows/build.yml`: Defines the GitHub Actions workflow for automated builds
## Troubleshooting
- If the auto-updater isn't working, check the log file at:
- macOS: `~/Library/Logs/react-native-devtools/main.log`
- Make sure your repository is public, or if it's private, ensure users have proper access tokens configured
- To debug update issues, run the app with the `DEBUG` environment variable:
```bash
DEBUG=electron-updater npm start
```
## Version Updates
The automated release script handles version updates for you, but if you need to do it manually:
1. Update the version in `package.json`
2. Commit the changes
3. Create a new tag matching the version number
4. Push the tag to GitHub
The version format should follow semantic versioning: `MAJOR.MINOR.PATCH`
================================================
FILE: README.md
================================================
# React Native DevTools
Enhanced developer tools for React Native applications, supporting React Query DevTools and device storage monitoring with a beautiful native interface.

https://github.com/user-attachments/assets/5c0c5748-e031-427a-8ebf-9c085434e8ba
## Example app
https://github.com/LovesWorking/RN-Dev-Tools-Example
### If you need internal React Query dev tools within the device you can use my other package here!
https://github.com/LovesWorking/react-native-react-query-devtools
## ✨ Features
- 🔄 Real-time React Query state monitoring
- 💾 **Device storage monitoring with CRUD operations** - MMKV, AsyncStorage, and SecureStorage
- 🌐 **Environment variables monitoring** - View and track public environment variables
- 🎨 Beautiful native macOS interface
- 🚀 Automatic connection to React apps
- 📊 Query status visualization
- 🔌 Socket.IO integration for reliable communication
- ⚡️ Simple setup with NPM package
- 📱 Works with **any React-based platform**: React Native, React Web, Next.js, Expo, tvOS, VR, etc.
- 🛑 Zero-config production safety - automatically disabled in production builds
## 📦 Installation
### DevTools Desktop Application (macOS)
> **⚠️ Important**: The desktop app has currently only been tested on Apple Silicon Macs (M1/M2/M3).
> If you encounter issues on Intel-based Macs, please [open an issue](https://github.com/LovesWorking/rn-better-dev-tools/issues)
> and we'll work together to fix it.
1. Download the latest release from the [Releases page](https://github.com/LovesWorking/rn-better-dev-tools/releases)
2. Extract the ZIP file
3. Move the app to your Applications folder
4. Launch the app
### React Application Integration
The easiest way to connect your React application to the DevTools is by installing the npm package:
```bash
# Using npm
npm install --save-dev react-query-external-sync socket.io-client
npm install expo-device # For automatic device detection
# Using yarn
yarn add -D react-query-external-sync socket.io-client
yarn add expo-device # For automatic device detection
# Using pnpm (recommended)
pnpm add -D react-query-external-sync socket.io-client
pnpm add expo-device # For automatic device detection
```
## 🚀 Quick Start
1. Download and launch the React Native DevTools application
2. Add the hook to your application where you set up your React Query context:
```jsx
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { useSyncQueriesExternal } from "react-query-external-sync";
// Import Platform for React Native or use other platform detection for web/desktop
import { Platform } from "react-native";
import AsyncStorage from "@react-native-async-storage/async-storage";
import * as SecureStore from "expo-secure-store";
import * as ExpoDevice from "expo-device";
import { storage } from "./mmkv"; // Your MMKV instance
// Create your query client
const queryClient = new QueryClient();
function App() {
return (
);
}
function AppContent() {
// Set up the sync hook - automatically disabled in production!
useSyncQueriesExternal({
queryClient,
socketURL: "http://localhost:42831", // Default port for React Native DevTools
deviceName: Platform?.OS || "web", // Platform detection
platform: Platform?.OS || "web", // Use appropriate platform identifier
deviceId: Platform?.OS || "web", // Use a PERSISTENT identifier (see note below)
isDevice: ExpoDevice.isDevice, // Automatically detects real devices vs emulators
extraDeviceInfo: {
// Optional additional info about your device
appVersion: "1.0.0",
// Add any relevant platform info
},
enableLogs: false,
envVariables: {
NODE_ENV: process.env.NODE_ENV,
// Add any private environment variables you want to monitor
// Public environment variables are automatically loaded
},
// Storage monitoring with CRUD operations
mmkvStorage: storage, // MMKV storage for ['#storage', 'mmkv', 'key'] queries + monitoring
asyncStorage: AsyncStorage, // AsyncStorage for ['#storage', 'async', 'key'] queries + monitoring
secureStorage: SecureStore, // SecureStore for ['#storage', 'secure', 'key'] queries + monitoring
secureStorageKeys: [
"userToken",
"refreshToken",
"biometricKey",
"deviceId",
], // SecureStore keys to monitor
});
// Your app content
return ;
}
```
3. Start your React application
4. DevTools will automatically detect and connect to your running application
## 🔒 Production Safety
The React Query External Sync package is automatically disabled in production builds.
```jsx
// The package handles this internally:
if (process.env.NODE_ENV !== "production") {
useSyncQueries = require("./new-sync/useSyncQueries").useSyncQueries;
} else {
// In production, this becomes a no-op function
useSyncQueries = () => ({
isConnected: false,
connect: () => {},
disconnect: () => {},
socket: null,
users: [],
});
}
```
### 📱 Using with Real Devices (Local Network)
When testing on real devices connected to your local network, you'll need to use your host machine's IP address instead of `localhost`. Here's a helpful setup for Expo apps (contributed by [ShoeBoom](https://github.com/ShoeBoom)):
```jsx
import Constants from "expo-constants";
import AsyncStorage from "@react-native-async-storage/async-storage";
import * as SecureStore from "expo-secure-store";
import { storage } from "./mmkv"; // Your MMKV instance
// Get the host IP address dynamically
const hostIP =
Constants.expoGoConfig?.debuggerHost?.split(`:`)[0] ||
Constants.expoConfig?.hostUri?.split(`:`)[0];
function AppContent() {
useSyncQueriesExternal({
queryClient,
socketURL: `http://${hostIP}:42831`, // Use local network IP
deviceName: Platform?.OS || "web",
platform: Platform?.OS || "web",
deviceId: Platform?.OS || "web",
extraDeviceInfo: {
appVersion: "1.0.0",
},
enableLogs: false,
envVariables: {
NODE_ENV: process.env.NODE_ENV,
},
// Storage monitoring
mmkvStorage: storage,
asyncStorage: AsyncStorage,
secureStorage: SecureStore,
secureStorageKeys: ["userToken", "refreshToken"],
});
return ;
}
```
> **Note**: For optimal connection, launch DevTools before starting your application.
## 💡 Usage Tips
- Keep DevTools running while developing
- Monitor query states in real-time
- View detailed query information
- Track cache updates and invalidations
- **Monitor device storage**: View and modify MMKV, AsyncStorage, and SecureStorage data in real-time
- **Track environment variables**: Monitor public environment variables across your application
- **Use storage queries**: Access storage data via React Query with keys like `['#storage', 'mmkv', 'key']`
- The hook is automatically disabled in production builds, no configuration needed
## 📱 Platform Support
React Native DevTools works with **any React-based application**, regardless of platform:
- 📱 Mobile: iOS, Android
- 🖥️ Web: React, Next.js, Remix, etc.
- 🖥️ Desktop: Electron, Tauri
- 📺 TV: tvOS, Android TV
- 🥽 VR/AR: Meta Quest, etc.
- 💻 Cross-platform: Expo, React Native Web
If your platform can run React and connect to a socket server, it will work with these DevTools!
## 💾 Storage Monitoring
React Native DevTools now includes powerful storage monitoring capabilities with full CRUD operations:
### Supported Storage Types
- **MMKV**: High-performance key-value storage
- **AsyncStorage**: React Native's standard async storage
- **SecureStorage**: Secure storage for sensitive data (Expo SecureStore)
### Features
- **Real-time monitoring**: See storage changes as they happen
- **CRUD operations**: Create, read, update, and delete storage entries directly from DevTools
- **React Query integration**: Access storage data via queries like `['#storage', 'mmkv', 'keyName']`
- **Type-safe operations**: Automatic serialization/deserialization of complex data types
- **Secure data handling**: SecureStorage keys are monitored securely
### Usage Example
```jsx
// In your app, use React Query to interact with storage
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
// Read from MMKV storage
const { data: userData } = useQuery({
queryKey: ["#storage", "mmkv", "user"],
// Data will be automatically synced with DevTools
});
// Write to AsyncStorage
const queryClient = useQueryClient();
const updateAsyncStorage = useMutation({
mutationFn: async ({ key, value }) => {
await AsyncStorage.setItem(key, JSON.stringify(value));
// Invalidate to trigger sync
queryClient.invalidateQueries(["#storage", "async", key]);
},
});
```
## ⚙️ Configuration Options
The `useSyncQueriesExternal` hook accepts the following options:
| Option | Type | Required | Description |
| ------------------- | ------------ | -------- | ----------------------------------------------------------------------------------------------------------------- |
| `queryClient` | QueryClient | Yes | Your React Query client instance |
| `socketURL` | string | Yes | URL of the socket server (e.g., 'http://localhost:42831') |
| `deviceName` | string | Yes | Human-readable name for your device |
| `platform` | string | Yes | Platform identifier ('ios', 'android', 'web', 'macos', 'windows', etc.) |
| `deviceId` | string | Yes | Unique identifier for your device |
| `isDevice` | boolean | No | Whether running on a real device (true) or emulator (false). Used for Android socket URL handling (default: true) |
| `extraDeviceInfo` | object | No | Additional device metadata to display in DevTools |
| `enableLogs` | boolean | No | Enable console logging for debugging (default: false) |
| `envVariables` | object | No | Private environment variables to sync with DevTools (public vars are auto-loaded) |
| `mmkvStorage` | MmkvStorage | No | MMKV storage instance for real-time monitoring |
| `asyncStorage` | AsyncStorage | No | AsyncStorage instance for polling-based monitoring |
| `secureStorage` | SecureStore | No | SecureStore instance for secure data monitoring |
| `secureStorageKeys` | string[] | No | Array of SecureStore keys to monitor (required if using secureStorage) |
## 🔮 Future Plans
React Native DevTools is actively being developed with exciting features on the roadmap:
- ✅ **Storage Viewers**: Beautiful interfaces for viewing and modifying storage (AsyncStorage, MMKV, SecureStorage) - **Now Available!**
- 🌐 **Network Request Monitoring**: Track API calls, WebSockets, and GraphQL requests
- ❌ **Failed Request Tracking**: Easily identify and debug network failures
- 🔄 **Remote Expo DevTools**: Trigger Expo DevTools commands remotely without using the command line
- 🧩 **Plugin System**: Allow community extensions for specialized debugging tasks
- 🗄️ **Drizzle Studio Plugin**: Integration with Drizzle ORM for database management
Stay tuned for updates!
## 🤝 Contributing
I welcome contributions! See [Development Guide](DEVELOPMENT.md) for details on:
- Setting up the development environment
- Building and testing
- Release process
- Contribution guidelines
## 🐛 Troubleshooting
Having issues? Check these common solutions:
1. **App Not Connecting**
- Ensure DevTools is launched before your React app
- Check that your React app is running
- Verify you're on the same network
- Make sure the `socketURL` is correctly pointing to localhost:42831
- Verify the Socket.IO client is properly installed in your app
- Check that the `useSyncQueriesExternal` hook is properly implemented
2. **App Not Starting**
- Verify you're using the latest version
- Check system requirements (macOS with Apple Silicon chip)
- Try reinstalling the application
- If using an Intel Mac and encountering issues, please report them
3. **Socket Connection Issues**
- Make sure no firewall is blocking the connection on port 42831
- Restart both the DevTools app and your React app
- Check the console logs with `enableLogs: true` for any error messages
- If the React Query data is too large the socket connection will crash! If you see the device connect and then disconnect with no logs this is what's happening. You'll need to fix your query cache to not be so large.
4. **Data Not Syncing**
- Confirm you're passing the correct `queryClient` instance
- Set `enableLogs: true` to see connection information
5. **Android Real Device Connection Issues**
- If using a real Android device with React Native CLI and ADB, ensure `isDevice: true`
- The package transforms `localhost` to `10.0.2.2` for emulators only
- Use `ExpoDevice.isDevice` for automatic detection: `import * as ExpoDevice from "expo-device"`
- Check network connectivity between your device and development machine
6. **DevTools App Issues**
- Make sure your `deviceId` is persistent (see below)
- Verify you're using the latest version
- Check system requirements (macOS with Apple Silicon chip)
- Try reinstalling the application
- If using an Intel Mac and encountering issues, please report them
7. **Storage Monitoring Issues**
- Ensure storage instances are properly passed to the hook
- For SecureStorage, make sure `secureStorageKeys` array is provided
- Check that storage permissions are granted on the device
- Verify storage libraries are properly installed and configured
- Use `enableLogs: true` to see storage sync information
That's it! If you're still having issues, visit the [GitHub repository](https://github.com/LovesWorking/rn-better-dev-tools/issues) for support.
## 🏷️ Device Type Detection
The `isDevice` prop helps the DevTools distinguish between real devices and simulators/emulators. This is **crucial for Android connectivity** - the package automatically handles URL transformation for Android emulators (localhost → 10.0.2.2) but needs to know if you're running on a real device to avoid this transformation.
### ⚠️ Android Connection Issue
On real Android devices using React Native CLI and ADB, the automatic emulator detection can incorrectly transform `localhost` to `10.0.2.2`, breaking WebSocket connections. Setting `isDevice: true` prevents this transformation.
**Recommended approaches:**
```jsx
// Best approach using Expo Device (works with bare React Native too)
import * as ExpoDevice from "expo-device";
useSyncQueriesExternal({
queryClient,
socketURL: "http://localhost:42831",
deviceName: Platform.OS,
platform: Platform.OS,
deviceId: Platform.OS,
isDevice: ExpoDevice.isDevice, // Automatically detects real devices vs emulators
// ... other props
});
// Alternative: Simple approach using React Native's __DEV__ flag
isDevice: !__DEV__, // true for production/real devices, false for development/simulators
// Alternative: More sophisticated detection using react-native-device-info
import DeviceInfo from 'react-native-device-info';
isDevice: !DeviceInfo.isEmulator(), // Automatically detects if running on emulator
// Manual control for specific scenarios
isDevice: Platform.OS === 'ios' ? !Platform.isPad : Platform.OS !== 'web',
```
## ⚠️ Important Note About Device IDs
The `deviceId` parameter must be **persistent** across app restarts and re-renders. Using a value that changes (like `Date.now()`) will cause each render to be treated as a new device.
**Recommended approaches:**
```jsx
// Simple approach for single devices
deviceId: Platform.OS, // Works if you only have one device per platform
// Better approach for multiple simulators/devices of same type
// Using AsyncStorage, MMKV, or another storage solution
const [deviceId, setDeviceId] = useState(Platform.OS);
useEffect(() => {
const loadOrCreateDeviceId = async () => {
// Try to load existing ID
const storedId = await AsyncStorage.getItem('deviceId');
if (storedId) {
setDeviceId(storedId);
} else {
// First launch - generate and store a persistent ID
const newId = `${Platform.OS}-${Date.now()}`;
await AsyncStorage.setItem('deviceId', newId);
setDeviceId(newId);
}
};
loadOrCreateDeviceId();
}, []);
```
For more detailed troubleshooting, see our [Development Guide](DEVELOPMENT.md).
## 📄 License
MIT
---
Made with ❤️ by [LovesWorking](https://github.com/LovesWorking)
## 🚀 More
**Take a shortcut from web developer to mobile development fluency with guided learning**
Enjoyed this project? Learn to use React Native to build production-ready, native mobile apps for both iOS and Android based on your existing web development skills.
================================================
FILE: RELEASE.md
================================================
# Releasing React Native DevTools
This document outlines the process for creating a new release of React Native DevTools.
## Automated Release Process (Recommended)
The easiest way to create a new release is to use our automated script:
```bash
pnpm run release
```
This interactive script will:
1. Prompt you to select a version bump type (patch, minor, major, or custom)
2. Update the version in package.json
3. Ask for release notes
4. Commit and push the changes
5. Create and push a git tag
6. Monitor the GitHub Actions workflow
7. Automatically publish the release when complete
## Manual Release Process
If you need to perform the release manually, follow these steps:
1. Update the version in `package.json`:
```json
{
"version": "x.y.z",
...
}
```
2. Commit your changes:
```bash
git add package.json
git commit -m "Bump version to x.y.z"
```
3. Create and push a new tag:
```bash
git tag -a vx.y.z -m "Version x.y.z"
git push origin vx.y.z
```
4. The GitHub Actions workflow will automatically:
- Build the app for macOS
- Create a draft release with all the built installers
- Add the release notes
5. Go to the GitHub Releases page, review the draft release, add any additional notes, and publish it.
## Local Build and Package
If you want to build the app locally without publishing:
```bash
pnpm run pack
```
This will:
- Build the app
- Create installation packages
- Copy them to your Desktop in a "release rn better tools" folder
## Testing Before Release
Before creating a new release tag, make sure to:
1. Test the app thoroughly on your local machine
2. Run `pnpm run make` locally to ensure the build process completes without errors
3. Test the generated installers
## Troubleshooting
If the GitHub Actions build fails:
1. Check the workflow logs for errors
2. Make sure the repository has the necessary secrets and permissions set up
3. Try running the build locally to isolate the issue
## Auto-Update Feature
The app includes auto-update functionality. When a new release is published:
1. Existing users will be automatically notified of the update
2. The update will be downloaded in the background
3. The update will be installed when the user restarts the app
See GITHUB_RELEASE.md for more details on the auto-update configuration.
================================================
FILE: assets/icon.icns
================================================
// This is a placeholder - you need to replace this with an actual .icns file
// For now, you'll need to create or convert your icon to .icns format manually
// You can use tools like iconutil or online converters to create .icns files
================================================
FILE: auto-release.sh
================================================
#!/bin/bash
# Set error handling
set -e
# Colors for better logging
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Function for logging
log() {
echo -e "${BLUE}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} $1"
}
error() {
echo -e "${RED}[ERROR]${NC} $1"
exit 1
}
success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
# Check if we're in the right directory
if [ ! -f "package.json" ]; then
error "Must be run from project root directory"
fi
# Get current version from package.json
CURRENT_VERSION=$(node -p "require('./package.json').version")
log "Current version: $CURRENT_VERSION"
# Calculate new version (minor bump)
NEW_VERSION=$(node -p "
const [major, minor, patch] = '$CURRENT_VERSION'.split('.');
\`\${major}.\${parseInt(minor) + 1}.0\`
")
log "New version will be: $NEW_VERSION"
# Update version in package.json
log "Updating package.json version..."
npm version $NEW_VERSION --no-git-tag-version
# Build locally first to ensure everything works
log "Building locally to verify..."
pnpm run make:desktop || error "Local build failed"
success "Local build successful!"
# Stage all changes
log "Staging changes..."
git add . || error "Failed to stage changes"
# Commit with conventional commit message
log "Committing changes..."
git commit -m "chore: release v$NEW_VERSION" || error "Failed to commit changes"
# Create and push tag
log "Creating tag v$NEW_VERSION..."
git tag -d "v$NEW_VERSION" 2>/dev/null || true
git push origin ":refs/tags/v$NEW_VERSION" 2>/dev/null || true
git tag "v$NEW_VERSION" || error "Failed to create tag"
# Push changes and tags
log "Pushing changes and tags..."
git push && git push --tags || error "Failed to push changes"
success "Changes pushed successfully!"
# Wait for GitHub Action to start
log "Waiting for GitHub Action to start..."
sleep 5
# Monitor GitHub Action progress
MAX_ATTEMPTS=30
ATTEMPT=1
while [ $ATTEMPT -le $MAX_ATTEMPTS ]; do
STATUS=$(gh run list --json status,name --jq '.[0].status' 2>/dev/null || echo "unknown")
if [ "$STATUS" = "completed" ]; then
success "GitHub Action completed successfully!"
break
elif [ "$STATUS" = "failed" ]; then
error "GitHub Action failed. Check the logs with: gh run view"
fi
log "Build still in progress... (Attempt $ATTEMPT/$MAX_ATTEMPTS)"
sleep 10
ATTEMPT=$((ATTEMPT + 1))
done
if [ $ATTEMPT -gt $MAX_ATTEMPTS ]; then
warning "Timed out waiting for GitHub Action to complete. Check status manually with: gh run view"
fi
success "Release process completed!"
log "New version v$NEW_VERSION is being published"
log "You can check the release status at: https://github.com/LovesWorking/rn-better-dev-tools/releases"
================================================
FILE: build-and-pack.sh
================================================
#!/bin/bash
# Exit on any error
set -e
# Display what's happening
echo "🚀 Building and packaging React Native DevTools..."
# Variables
VERSION=$(node -e "console.log(require('./package.json').version)")
OUTPUT_DIR="$HOME/Desktop/release rn better tools"
APP_NAME="React Native DevTools"
# Ensure the output directory exists
mkdir -p "$OUTPUT_DIR"
# Clean previous builds
echo "🧹 Cleaning previous builds..."
rm -rf out/
# Check if GITHUB_TOKEN is set
if [ -n "$GITHUB_TOKEN" ]; then
# If GITHUB_TOKEN is set, publish to GitHub
echo "🌐 Publishing to GitHub..."
npx electron-forge publish
else
# If GITHUB_TOKEN is not set, just build locally
echo "🔨 Building application locally..."
npx electron-forge make --targets=@electron-forge/maker-zip
# Copy the output to the destination folder
echo "📦 Copying packaged app to destination folder..."
cp "out/make/zip/darwin/arm64/$APP_NAME-darwin-arm64-$VERSION.zip" "$OUTPUT_DIR/"
# Create a dated copy for versioning/archiving purposes
DATED_FILENAME="$APP_NAME-darwin-arm64-$VERSION-$(date +%Y%m%d%H%M).zip"
cp "out/make/zip/darwin/arm64/$APP_NAME-darwin-arm64-$VERSION.zip" "$OUTPUT_DIR/$DATED_FILENAME"
echo "✅ Build and packaging complete!"
echo "📝 Files created:"
echo " - $OUTPUT_DIR/$APP_NAME-darwin-arm64-$VERSION.zip"
echo " - $OUTPUT_DIR/$DATED_FILENAME"
echo ""
echo "🖥️ Open folder using: open \"$OUTPUT_DIR\""
echo ""
echo "⚠️ Note: To publish to GitHub, set the GITHUB_TOKEN environment variable and run this script again."
fi
================================================
FILE: build-macos.sh
================================================
#!/bin/bash
# Exit on error
set -e
echo "=== Building React Native DevTools for macOS ==="
# Clean previous builds
rm -rf out || true
echo "✅ Cleaned previous builds"
# Install dependencies
pnpm install
echo "✅ Dependencies installed"
# Build package
echo "🔨 Building macOS package..."
pnpm run make
# Check if ZIP was created
ZIP_PATH=$(find out/make -name "*.zip" | head -n 1)
if [ -f "$ZIP_PATH" ]; then
echo "✅ ZIP package created at: $ZIP_PATH"
echo "✅ Total size: $(du -h "$ZIP_PATH" | cut -f1)"
echo ""
echo "To run the app:"
echo "1. Extract the ZIP file"
echo "2. Move the app to your Applications folder"
echo "3. Open the app (you may need to right-click and select Open for the first time)"
echo ""
echo "To release:"
echo "1. Update version in package.json"
echo "2. Commit changes"
echo "3. Create and push tag: git tag -a v1.0.0 -m 'v1.0.0' && git push origin v1.0.0"
echo ""
echo "Build complete! 🎉"
else
echo "❌ ZIP package was not created. Check for errors above."
exit 1
fi
================================================
FILE: config.js
================================================
/**
* Socket.IO Test Client Config
* CommonJS version for use with the test script
*/
// Server configuration
const SERVER_PORT = 42831; // Using an uncommon port to avoid conflicts
// Client configuration
const CLIENT_URL = `http://localhost:${SERVER_PORT}`;
module.exports = {
SERVER_PORT,
CLIENT_URL,
};
================================================
FILE: copy-to-desktop.sh
================================================
#!/bin/bash
# Get the version from package.json
VERSION=$(node -p "require('./package.json').version")
# Create desktop directory if it doesn't exist
DESKTOP_DIR="$HOME/Desktop/rn-dev-tools-releases"
mkdir -p "$DESKTOP_DIR"
# Copy the zip file to desktop
cp "out/make/zip/darwin/arm64/React Native DevTools-darwin-arm64-$VERSION.zip" "$DESKTOP_DIR/"
echo "✅ Release copied to $DESKTOP_DIR"
================================================
FILE: entitlements.plist
================================================
com.apple.security.cs.allow-jitcom.apple.security.cs.allow-unsigned-executable-memorycom.apple.security.cs.disable-library-validationcom.apple.security.device.audio-inputcom.apple.security.device.bluetoothcom.apple.security.device.cameracom.apple.security.device.printcom.apple.security.device.usbcom.apple.security.personal-information.location
================================================
FILE: forge.config.ts
================================================
import { config as dotenvConfig } from "dotenv";
import * as path from "path";
// Load .env file from the project root
dotenvConfig({ path: path.resolve(process.cwd(), ".env") });
// Debug logging to verify environment variables
console.log("Environment variables loaded:", {
APPLE_ID: process.env.APPLE_ID,
TEAM_ID: process.env.APPLE_TEAM_ID,
DEBUG: process.env.DEBUG,
});
import type { ForgeConfig } from "@electron-forge/shared-types";
import { MakerZIP } from "@electron-forge/maker-zip";
import { VitePlugin } from "@electron-forge/plugin-vite";
import { FusesPlugin } from "@electron-forge/plugin-fuses";
import { FuseV1Options, FuseVersion } from "@electron/fuses";
import { PublisherGithub } from "@electron-forge/publisher-github";
const config: ForgeConfig = {
packagerConfig: {
asar: true,
icon: "./assets/icon", // No file extension required
appBundleId: "com.lovesworking.rn-dev-tools",
appCategoryType: "public.app-category.developer-tools",
executableName: "React Native DevTools",
osxSign: {
identity: "6EC9AE0A608BB7CBBA6BCC7936689773E76D63F0",
},
// The osxSign config comes with defaults that work out of the box in most cases, so we recommend you start with an empty configuration object.
// For a full list of configuration options, see https://js.electronforge.io/modules/_electron_forge_shared_types.InternalOptions.html#OsxSignOptions
osxNotarize: {
appleId: process.env.APPLE_ID!,
appleIdPassword: process.env.APPLE_PASSWORD!,
teamId: process.env.APPLE_TEAM_ID!,
},
},
rebuildConfig: {},
makers: [
// Build a ZIP for all platforms
new MakerZIP({}, ["darwin", "linux", "win32"]),
// The following makers are commented out for now
// new MakerSquirrel({}),
// new MakerRpm({}),
// new MakerDeb({})
],
publishers: [
new PublisherGithub({
repository: {
owner: "lovesworking", // Replace with your GitHub username or organization
name: "rn-better-dev-tools", // Replace with your repository name
},
prerelease: false, // Set to true if you want to mark releases as pre-releases
}),
],
plugins: [
new VitePlugin({
// `build` can specify multiple entry builds, which can be Main process, Preload scripts, Worker process, etc.
// If you are familiar with Vite configuration, it will look really familiar.
build: [
{
// `entry` is just an alias for `build.lib.entry` in the corresponding file of `config`.
entry: "src/main.ts",
config: "vite.main.config.ts",
target: "main",
},
{
entry: "src/preload.ts",
config: "vite.preload.config.ts",
target: "preload",
},
],
renderer: [
{
name: "main_window",
config: "vite.renderer.config.ts",
},
],
}),
// Fuses are used to enable/disable various Electron functionality
// at package time, before code signing the application
new FusesPlugin({
version: FuseVersion.V1,
[FuseV1Options.RunAsNode]: false,
[FuseV1Options.EnableCookieEncryption]: true,
[FuseV1Options.EnableNodeOptionsEnvironmentVariable]: false,
[FuseV1Options.EnableNodeCliInspectArguments]: false,
[FuseV1Options.EnableEmbeddedAsarIntegrityValidation]: true,
[FuseV1Options.OnlyLoadAppFromAsar]: true,
}),
],
};
export default config;
================================================
FILE: forge.env.d.ts
================================================
///
================================================
FILE: index.html
================================================
React Native Dev Tools
================================================
FILE: package.json
================================================
{
"name": "rn-better-dev-tools",
"productName": "React Native DevTools",
"version": "1.1.0",
"description": "Enhanced developer tools for React Native applications (Only supports React Query DevTools Right Now)",
"main": ".vite/build/main.js",
"scripts": {
"release": "./release-version.sh",
"pack": "./build-and-pack.sh",
"nuke": "rm -rf node_modules .vite/build pnpm-lock.yaml && pnpm store prune && pnpm cache clean && pnpm install",
"start": "electron-forge start",
"package": "electron-forge package",
"make": "electron-forge make",
"make:desktop": "pnpm run make && ./copy-to-desktop.sh",
"publish": "electron-forge publish",
"lint": "eslint --ext .ts,.tsx .",
"auto-release": "./auto-release.sh"
},
"keywords": [],
"author": {
"name": "lovesworking",
"email": "austinlovesworking@gmail.com"
},
"license": "MIT",
"pnpm": {
"onlyBuiltDependencies": [
"electron"
]
},
"packageManager": "pnpm@10.4.1+sha512.c753b6c3ad7afa13af388fa6d808035a008e30ea9993f58c6663e2bc5ff21679aa834db094987129aa4d488b86df57f7b634981b2f827cdcacc698cc0cfb88af",
"devDependencies": {
"@electron-forge/cli": "^7.8.0",
"@electron-forge/maker-deb": "^7.8.0",
"@electron-forge/maker-dmg": "^7.8.0",
"@electron-forge/maker-rpm": "^7.8.0",
"@electron-forge/maker-squirrel": "^7.8.0",
"@electron-forge/maker-zip": "^7.8.0",
"@electron-forge/plugin-auto-unpack-natives": "^7.8.0",
"@electron-forge/plugin-fuses": "^7.8.0",
"@electron-forge/plugin-vite": "^7.8.0",
"@electron-forge/publisher-github": "^7.8.0",
"@electron/fuses": "^1.8.0",
"@types/express": "^5.0.1",
"@types/react": "^19.0.12",
"@types/react-dom": "^19.0.4",
"@types/socket.io": "^3.0.2",
"@typescript-eslint/eslint-plugin": "^5.0.0",
"@typescript-eslint/parser": "^5.0.0",
"@vitejs/plugin-react": "^4.3.4",
"autoprefixer": "^10.4.16",
"dotenv": "^16.4.7",
"electron": "35.1.2",
"eslint": "^8.0.1",
"eslint-plugin-import": "^2.25.0",
"postcss": "^8.4.31",
"tailwindcss": "^3.3.5",
"ts-node": "^10.0.0",
"typescript": "~4.5.4",
"vite": "^5.0.12"
},
"dependencies": {
"@tanstack/query-devtools": "file:tanstack-query-devtools-5.74.7.tgz",
"@tanstack/react-query": "^5.75.7",
"@tanstack/react-query-devtools": "file:tanstack-react-query-devtools-5.75.7.tgz",
"bufferutil": "^4.0.9",
"electron-log": "^5.3.3",
"electron-squirrel-startup": "^1.0.1",
"electron-updater": "^6.6.2",
"express": "^4.21.2",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"react-use": "^17.6.0",
"socket.io": "^4.8.1",
"socket.io-client": "^4.8.1",
"utf-8-validate": "^6.0.5",
"zustand": "^5.0.3"
},
"build": {
"appId": "com.lovesworking.rn-dev-tools",
"productName": "React Native DevTools",
"mac": {
"category": "public.app-category.developer-tools",
"target": "zip"
},
"publish": {
"provider": "github",
"owner": "lovesworking",
"repo": "rn-better-dev-tools"
}
}
}
================================================
FILE: postcss.config.js
================================================
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};
================================================
FILE: release-version.sh
================================================
#!/bin/bash
# Exit on any error
set -e
# Colors for better output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Function to display status messages
function echo_status() {
echo -e "${BLUE}[INFO]${NC} $1"
}
# Function to display success messages
function echo_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
# Function to display error messages
function echo_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# Function to display warning messages
function echo_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
# Check if gh CLI is installed
if ! command -v gh &> /dev/null; then
echo_error "GitHub CLI (gh) is not installed. Please install it first."
echo "You can install it with: brew install gh"
exit 1
fi
# Check if gh is authenticated
if ! gh auth status &> /dev/null; then
echo_error "You're not authenticated with GitHub CLI."
echo "Please run: gh auth login"
exit 1
fi
# Ensure we're on the main branch
current_branch=$(git rev-parse --abbrev-ref HEAD)
if [ "$current_branch" != "main" ]; then
echo_warning "You are not on the main branch. Switching to main..."
git checkout main
fi
# Make sure the working directory is clean
if ! git diff-index --quiet HEAD --; then
echo_error "Your working directory has uncommitted changes."
echo "Please commit or stash them before running this script."
exit 1
fi
# Pull latest changes
echo_status "Pulling latest changes from main..."
git pull origin main
# Get current version from package.json
current_version=$(node -e "console.log(require('./package.json').version)")
echo_status "Current version: ${current_version}"
# Prompt for version bump type
echo "Select version bump type:"
echo "1) Patch (1.0.0 -> 1.0.1) - For bug fixes"
echo "2) Minor (1.0.0 -> 1.1.0) - For new features"
echo "3) Major (1.0.0 -> 2.0.0) - For breaking changes"
echo "4) Custom (Enter a specific version)"
read -p "Enter your choice (1-4): " version_choice
case $version_choice in
1)
bump_type="patch"
;;
2)
bump_type="minor"
;;
3)
bump_type="major"
;;
4)
read -p "Enter the new version (e.g., 1.2.3): " custom_version
bump_type="custom"
new_version=$custom_version
;;
*)
echo_error "Invalid choice. Exiting."
exit 1
;;
esac
# Calculate new version for non-custom bumps
if [ "$bump_type" != "custom" ]; then
# Split version by dots
IFS='.' read -ra VERSION_PARTS <<< "$current_version"
major=${VERSION_PARTS[0]}
minor=${VERSION_PARTS[1]}
patch=${VERSION_PARTS[2]}
case $bump_type in
patch)
patch=$((patch + 1))
;;
minor)
minor=$((minor + 1))
patch=0
;;
major)
major=$((major + 1))
minor=0
patch=0
;;
esac
new_version="${major}.${minor}.${patch}"
fi
echo_status "New version will be: ${new_version}"
# Prompt for confirmation
read -p "Proceed with release? (y/n): " confirm
if [[ $confirm != "y" && $confirm != "Y" ]]; then
echo_warning "Release canceled."
exit 0
fi
# Update version in package.json
echo_status "Updating package.json version to ${new_version}..."
# Use a temporary file to avoid issues with inline editing
node -e "
const fs = require('fs');
const packageJson = JSON.parse(fs.readFileSync('./package.json', 'utf8'));
packageJson.version = '${new_version}';
fs.writeFileSync('./package.json', JSON.stringify(packageJson, null, 2) + '\n');
"
# Prompt for release notes
echo "Enter release notes (or leave empty for default message):"
echo "Type your notes and press Ctrl+D when finished (or Ctrl+C to cancel)"
release_notes=$(cat)
if [ -z "$release_notes" ]; then
release_notes="Version ${new_version}"
fi
# Commit the version change
echo_status "Committing version change..."
git add package.json
git commit -m "Bump version to ${new_version}"
# Push the changes
echo_status "Pushing changes to main..."
git push origin main
# Create and push tag
tag_name="v${new_version}"
echo_status "Creating and pushing tag ${tag_name}..."
git tag $tag_name
git push origin $tag_name
echo_success "Version ${new_version} has been released!"
echo "GitHub Actions should now be building and publishing your release."
# Monitor the GitHub Actions workflow
echo_status "Monitoring workflow run..."
sleep 3 # Give GitHub a moment to register the workflow
# Find the latest run ID for the tag we just pushed
echo_status "Getting the latest workflow run ID..."
run_id=$(gh run list --workflow "Build and Release macOS App" --limit 1 --json databaseId --jq ".[0].databaseId")
if [ -z "$run_id" ]; then
echo_warning "Could not find the workflow run. Please check GitHub Actions manually."
else
echo_status "Workflow run ID: ${run_id}"
echo_status "Watching workflow run (press Ctrl+C to stop watching)..."
gh run watch $run_id
# Check the status of the run
run_status=$(gh run view $run_id --json conclusion --jq ".conclusion")
if [ "$run_status" == "success" ]; then
echo_success "Workflow completed successfully!"
# Update the release notes
echo_status "Updating release notes..."
gh release edit $tag_name --title "Version ${new_version}" --notes "$release_notes"
# Publish the release (remove the draft status)
echo_status "Publishing release..."
gh release edit $tag_name --draft=false
echo_success "Release v${new_version} has been published!"
echo "URL: https://github.com/lovesworking/rn-better-dev-tools/releases/tag/${tag_name}"
else
echo_error "Workflow failed or was canceled. Please check GitHub Actions."
echo "URL: https://github.com/lovesworking/rn-better-dev-tools/actions"
fi
fi
================================================
FILE: socket-client.js
================================================
/**
* Socket.IO Test Client
*
* This simple client connects to the Socket.IO server and allows
* sending messages from the command line.
*/
// We need to use CommonJS require for this standalone script
const { io } = require("socket.io-client");
// Import config values from CommonJS config file
const { CLIENT_URL } = require("./config.js");
console.log("Starting Socket.IO test client...");
console.log(`Connecting to: ${CLIENT_URL}`);
// Connect to the Socket.IO server
const socket = io(CLIENT_URL);
// Event handler for successful connection
socket.on("connect", () => {
console.log("✅ Connected to Socket.IO server");
console.log("Socket ID:", socket.id);
// Send a test message after connection
setTimeout(() => {
sendMessage("Hello from test client!");
}, 1000);
});
// Event handler for disconnection
socket.on("disconnect", () => {
console.log("❌ Disconnected from Socket.IO server");
});
// Event handler for connection errors
socket.on("connect_error", (err) => {
console.error("❌ Connection error:", err.message);
});
// Event handler for receiving messages
socket.on("message", (data) => {
console.log(`📨 Received: "${data}"`);
});
// Add handler for query-action events
socket.on("query-action", (data) => {
console.log(`📨 Received query-action:`, data);
});
// Function to send a message
function sendMessage(message) {
socket.emit("message", message);
console.log(`📤 Sent: "${message}"`);
}
// Allow sending messages from the command line
process.stdin.on("data", (data) => {
const message = data.toString().trim();
if (message) {
sendMessage(message);
}
});
console.log("Type messages and press Enter to send. Press Ctrl+C to exit.");
================================================
FILE: src/auto-updater.ts
================================================
import { autoUpdater, UpdateInfo, ProgressInfo } from "electron-updater";
import log from "electron-log";
// Configure logger
log.transports.file.level = "info";
autoUpdater.logger = log;
export function setupAutoUpdater() {
// Check for updates on startup
autoUpdater.checkForUpdatesAndNotify();
// Set up auto updater events
autoUpdater.on("checking-for-update", () => {
log.info("Checking for update...");
});
autoUpdater.on("update-available", (info: UpdateInfo) => {
log.info("Update available:", info);
});
autoUpdater.on("update-not-available", (info: UpdateInfo) => {
log.info("Update not available:", info);
});
autoUpdater.on("error", (err: Error) => {
log.error("Error in auto-updater:", err);
});
autoUpdater.on("download-progress", (progressObj: ProgressInfo) => {
let logMessage = `Download speed: ${progressObj.bytesPerSecond}`;
logMessage = `${logMessage} - Downloaded ${progressObj.percent}%`;
logMessage = `${logMessage} (${progressObj.transferred}/${progressObj.total})`;
log.info(logMessage);
});
autoUpdater.on("update-downloaded", (info: UpdateInfo) => {
log.info("Update downloaded:", info);
// Install the update when the app is quit
// Alternatively, you could prompt the user here
});
// Check for updates periodically
const CHECK_INTERVAL = 1000 * 60 * 60; // Check every hour
setInterval(() => {
autoUpdater.checkForUpdatesAndNotify();
}, CHECK_INTERVAL);
}
================================================
FILE: src/components/App.tsx
================================================
import Providers from "./external-dash/providers";
import Main from "./external-dash/Main";
export const App: React.FC = () => {
return (
);
};
================================================
FILE: src/components/external-dash/Dash.tsx
================================================
import React, { useEffect, useState } from "react";
import { User } from "./types/User";
import "../../index.css";
import { ReactQueryDevtools } from "@tanstack/react-query-devtools/production";
import { useLogStore } from "./utils/logStore";
import { onDevToolsEvent } from "./utils/devToolsEvents";
import { useDevToolsEventHandler } from "./hooks/useDevToolsEventHandler";
import { DeviceSelection } from "./DeviceSelection";
import { UserInfo } from "./UserInfo";
import { LogConsole } from "./LogConsole";
import { NoDevicesConnected } from "./NoDevicesConnected";
import { StorageControlsSection } from "./UserInfo/StorageControlsSection";
export const PlatformIcon: React.FC<{ platform: string }> = ({ platform }) => {
const normalizedPlatform = platform?.toLowerCase() || "";
switch (normalizedPlatform) {
case "ios":
return (
);
case "android":
return (
);
case "web":
return (
);
case "tv":
case "tvos":
return (
);
default:
return (
);
}
};
export const getPlatformColor = (platform: string): string => {
const normalizedPlatform = platform?.toLowerCase() || "";
switch (normalizedPlatform) {
case "ios":
return "text-gray-100";
case "android":
return "text-green-300";
case "web":
return "text-blue-300";
case "tv":
case "tvos":
return "text-purple-300";
default:
return "text-gray-300";
}
};
export const getPlatformBgColor = (platform: string): string => {
const normalizedPlatform = platform?.toLowerCase() || "";
switch (normalizedPlatform) {
case "ios":
return "bg-blue-900/30 text-blue-200";
case "android":
return "bg-green-900/30 text-green-200";
case "web":
return "bg-cyan-900/30 text-cyan-200";
case "tv":
case "tvos":
return "bg-purple-900/30 text-purple-200";
default:
return "bg-gray-800/60 text-gray-300";
}
};
interface DashProps {
allDevices: User[];
isDashboardConnected: boolean;
targetDevice: User;
setTargetDevice: (device: User) => void;
}
export const Dash: React.FC = ({
isDashboardConnected,
allDevices,
targetDevice,
setTargetDevice,
}) => {
const [showOfflineDevices, setShowOfflineDevices] = useState(true);
const { isEnabled, setIsEnabled, isVisible, setIsVisible } = useLogStore();
const filteredDevices = showOfflineDevices
? allDevices
: allDevices.filter((device) => {
if (typeof device === "string") {
return false;
}
return device.isConnected;
});
// Find the target device
useEffect(() => {
const foundDevice = filteredDevices?.find((device) => {
return device.deviceId === targetDevice.deviceId;
});
foundDevice && setTargetDevice(foundDevice);
}, [setTargetDevice, filteredDevices, targetDevice]);
useDevToolsEventHandler();
return (
Disabling a storage type will clear its queries from React
Query DevTools and filter out new queries. Re-enabling
will show new queries but won't restore previously cleared
ones.