Skip to content

Conversation

@lopeselio
Copy link
Contributor

Description

Fixes Android/React Native compatibility issues, addressing issue #89 and related problems.

Primary fixes (Issue #89)

  1. UUID generation: replaced uuidv4() with expo-crypto.randomUUID() on native platforms

    • Created apps/client/lib/uuid.ts utility using expo-crypto.randomUUID() for Android/iOS
    • Falls back to uuid library on web or if expo-crypto fails
    • Updated conversations.ts and messages.ts to use the new utility
    • Resolves: crypto.getRandomValues() not supported error on Android
  2. Network connectivity: platform-aware URL conversion for Android emulator

    • Added helper in apps/client/lib/config.ts to convert localhost10.0.2.2 on Android
    • Android emulator uses 10.0.2.2 as alias for host machine's localhost
    • Resolves: TypeError: Network request failed when hitting backend API

Additional fixes

  1. React Native compatibility: guarded window API usage

    • Added Platform.OS === 'web' and typeof window !== 'undefined' checks
    • Added typeof CustomEvent !== 'undefined' checks
    • Prevents crashes from window.addEventListener, window.dispatchEvent, and CustomEvent on React Native
  2. Chat functionality on React Native: use cache functions instead of window events

    • Exposed sendMessage, stop, and regenerate functions in chat-cache for direct use
    • useChatState now uses cache functions on React Native, bypassing window events
  3. Grid sign-in retry loop: prevent infinite retries

    • Added useRef guard in wallet screen to track sign-in attempts
    • Prevents automatic retry loops when Grid sign-in fails
    • Allows manual retry after 5-second delay
  4. Navigation fix: allow authenticated users to stay on /verify-otp

    • Updated AuthContext to check for Grid OTP session before redirecting
    • Authenticated users can complete Grid OTP verification without being redirected to chat
  5. Google Sign-In: improved error handling

    • Added robust response parsing for different Google Sign-In response structures
    • Better error logging and handling
  6. Grid SDK crypto polyfill: added crypto.getRandomValues() polyfill

    • Grid SDK requires crypto.getRandomValues() for keypair generation
    • Polyfill uses expo-crypto.getRandomBytes() to support Grid SDK on React Native
  7. Backend error logging: improved Grid sign-in error handling

    • Added detailed logging for createAccount() and initAuth() responses
    • Better error messages for debugging
  8. Wallet context: prevent auto-triggering Grid sign-in

    • Modified WalletContext to only load wallet data if Grid account exists
    • Grid sign-in now triggered on-demand when wallet features are accessed
    • Improves UX by not interrupting user flow immediately after Google sign-in

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Release (version bump)

Release

Is this a release? No

Testing

Prerequisites

  1. Backend server running: bun run server (or cd apps/server && bun run dev)
  2. Android emulator running (Pixel 9 Pro XL or similar)
  3. Android Studio installed with Android SDK

Test Steps

1. Test UUID Generation (Issue #89)

cd apps/client
bun run android
  • Sign in with Google on Android emulator
  • Verify onboarding conversation is created without crypto.getRandomValues() not supported error
  • Check logs: should see conversation created successfully

2. Test Network Connectivity (Issue #89)

# Ensure backend is running on localhost:3001
bun run server
  • Navigate to wallet screen after Google sign-in
  • Trigger Grid sign-in
  • Verify Grid sign-in reaches backend (check backend logs for /api/grid/start-sign-in requests)
  • Should NOT see TypeError: Network request failed error

3. Test Grid Sign-In Flow

  • Sign in with Google
  • Navigate to wallet screen (profile icon → wallet)
  • Verify Grid sign-in initiates automatically
  • Verify navigation to OTP screen
  • Verify user stays on OTP screen (not redirected to chat)
  • Enter OTP code from email
  • Verify Grid sign-in completes successfully
  • Verify wallet data loads (should show SOL and USDC balances)

4. Test Retry Loop Prevention

  • Sign in with Google
  • Navigate to wallet screen
  • If Grid sign-in fails, verify it doesn't retry infinitely
  • Check logs: should see single attempt, not repeated errors

5. Test Chat Functionality on React Native

  • After successful sign-in, navigate to chat screen
  • Send a message
  • Verify message sends without window.addEventListener is not a function errors
  • Verify AI responds correctly

6. Test Google Sign-In Error Handling

  • Test with invalid/missing Google Client ID (if possible)
  • Verify app handles errors gracefully without crashing
  • Check logs for detailed error information

Expected Results

  • ✅ Onboarding conversation creates successfully on Android
  • ✅ Grid sign-in reaches backend API successfully
  • ✅ OTP verification flow completes without navigation issues
  • ✅ Wallet data loads and displays correctly
  • ✅ Chat functionality works on React Native
  • ✅ No infinite retry loops
  • ✅ No window API errors on React Native

Files Changed

  • apps/client/lib/uuid.ts - New utility for UUID generation
  • apps/client/lib/config.ts - Platform-aware URL conversion
  • apps/client/polyfills.js - Crypto polyfill for Grid SDK
  • apps/client/app/(main)/wallet.tsx - Retry loop prevention
  • apps/client/contexts/AuthContext.tsx - Navigation fix for verify-otp
  • apps/client/contexts/WalletContext.tsx - Prevent auto-trigger Grid sign-in
  • apps/client/features/auth/services/google.ts - Improved error handling
  • apps/client/components/chat/ChatManager.tsx - React Native compatibility
  • apps/client/hooks/useChatState.ts - React Native compatibility
  • apps/server/src/routes/grid.ts - Improved error logging

Checklist

  • My code follows the project's style guidelines
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • My changes generate no new warnings or errors
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing tests pass locally with my changes
  • If releasing, I have verified the version number is correct and follows semantic versioning

Note: This PR addresses Issue #89 and includes additional React Native compatibility fixes discovered during testing.

- Update minSdkVersion from 21 to 24 (required by react-native-worklets)
- Update compileSdkVersion from 34 to 35 (required by androidx dependencies)
- Update targetSdkVersion to 35
- Update buildToolsVersion to 35.0.0

Fixes build errors:
- 16 dependency compatibility issues requiring compileSdk 35+
- react-native-worklets minSdkVersion mismatch (21 vs 24)
Replace crypto.getRandomValues polyfill with expo-crypto.randomUUID()
as suggested by maintainer. This provides a cleaner solution that
works out of the box on React Native.

- Remove crypto polyfill code from polyfills.js
- Create lib/uuid.ts utility using expo-crypto.randomUUID()
- Update conversations.ts and messages.ts to use new utility
- Remove react-native-get-random-values and expo-random dependencies
- Add getPlatformAwareUrl() helper to convert localhost/127.0.0.1 to 10.0.2.2 on Android
- Android emulator uses 10.0.2.2 as alias for host machine's localhost
- Apply conversion to config.backendApiUrl automatically
- Update generateAPIUrl() to use platform-aware config

Fixes network errors:
ERROR ❌ [Grid Client] Sign-in start error:
[TypeError: Network request failed]
- Add Platform.OS check before using window.addEventListener/removeEventListener
- Add typeof window checks before window.dispatchEvent calls
- Window API doesn't exist in React Native, only on web

Fixes runtime error:
ERROR [TypeError: window.addEventListener is not a function (it is undefined)]

Affects:
- ChatManager.tsx: window event listeners for chat events
- useChatState.ts: window.dispatchEvent for chat state updates
- Detect Grid account not found errors (expected when wallet not set up)
- Log as warnings instead of errors for expected 404s
- Provide clearer error messages for Grid account setup flow
- Reduce error noise in console for expected scenarios

Fixes verbose error logging:
- Grid API error: 404 (expected when Grid wallet not initialized)
- Now logged as warnings with helpful context

Improves user experience during onboarding when Grid wallet is not yet set up.
Fix chat message sending on React Native by exposing ChatManager functions
through cache instead of relying on window events.

- Expose sendMessage, stop, and regenerate functions in chat cache
- Update useChatState to use cache functions on React Native
- Add CustomEvent check to prevent errors on React Native
- Improve Grid API error handling (warnings for expected 404s)

Fixes chat functionality on Android React Native where window events
are not available.
- Add useRef guard in wallet screen to prevent infinite retry loops when Grid sign-in fails
- Fix AuthContext navigation to allow authenticated users to stay on /verify-otp when completing Grid OTP
- Improve Google Sign-In error handling and response parsing
- Add crypto.getRandomValues polyfill for Grid SDK keypair generation
- Improve backend Grid sign-in error logging and handling
@vercel
Copy link

vercel bot commented Nov 14, 2025

@lopeselio is attempting to deploy a commit to the dark Team on Vercel.

A member of the Team first needs to authorize it.

- Fix OTP screen race condition with robust polling mechanism
- Add preloader during Grid sign-in initialization
- Improve Grid sign-in flow to trigger immediately after Google sign-in
- Fix navigation logic to handle OTP screen correctly
- Add comprehensive session storage cleanup on logout
- Fix platform-aware URL conversion for Android emulator
- Improve error handling in Grid backend routes
- Add crypto polyfill for Android UUID generation
- Fix wallet data loading to check Grid account before triggering sign-in
- Improve server startup resilience with error handlers
@lopeselio lopeselio force-pushed the fix/android-expo-errors branch from 4fe7763 to b2e8e3e Compare November 17, 2025 21:22
…ility

   - Add Gradle task to patch graphicsConversions.h
   - Replace std::format with std::to_string for Android NDK 26.1.10909125 compatibility
   - Fixes C++20 compilation error in React Native 0.81.4
})}
</View>
</Pressable>

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The handleResendCode function uses params.email directly without a fallback, but the instruction text correctly uses params.email || user?.email. If params.email is undefined, resending OTP will fail with an unclear error.

View Details
📝 Patch Details
diff --git a/apps/client/app/(auth)/verify-otp.tsx b/apps/client/app/(auth)/verify-otp.tsx
index 5ba9947..4dca2e4 100644
--- a/apps/client/app/(auth)/verify-otp.tsx
+++ b/apps/client/app/(auth)/verify-otp.tsx
@@ -366,7 +366,7 @@ export default function VerifyOtpScreen() {
       console.log('🔄 [OTP Screen] Resending OTP - starting new sign-in flow...');
       
       // Start sign-in again to get new OTP (Grid sends new email)
-      const { otpSession: newOtpSession } = await gridClientService.startSignIn(params.email);
+      const { otpSession: newOtpSession } = await gridClientService.startSignIn(params.email || user?.email || '');
       
       // Update LOCAL state with new OTP session
       setOtpSession(newOtpSession);

Analysis

Missing fallback for email parameter in handleResendCode

What fails: The handleResendCode() function in apps/client/app/(auth)/verify-otp.tsx passes params.email directly to gridClientService.startSignIn() without a fallback. If params.email is undefined, the API request fails with an unclear error message instead of gracefully using the authenticated user's email.

How to reproduce:

  1. Navigate to the OTP verification screen with an incomplete route parameter object where email is missing
  2. User enters 6-digit code (or clicks to trigger resend if error occurs)
  3. Click "Resend Code" button
  4. The function calls gridClientService.startSignIn(undefined), sending { email: undefined } to the backend

Result: Backend returns an error response with unclear error message since email is undefined

Expected: Should use params.email || user?.email || '' fallback pattern (consistent with line 542 instruction text and line 156 initialization logic in the same file)

Evidence of intentional fallback pattern:

  • Line 156: const hasEmail = autoInitiateEmail || params.email || user?.email;
  • Line 542: `We've sent a 6-digit code to

These demonstrate that developers already recognize params.email can be undefined and should have fallbacks. The missing fallback at line 369 is an inconsistency.

Reference: Expo Router useLocalSearchParams returns Partial - hook is typed to allow undefined for all parameters

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant