Fix Android app connectivity issues and add detailed logging

- Add CORS headers to backend server to allow mobile app requests
- Implement request timeout (10s) in capacitor-bridge.js to prevent hanging
- Add comprehensive logging throughout authentication flow
- Add detailed error reporting in initApp for better debugging
- Log all API requests with request IDs for traceability

This fixes the 'Loading Plugin Compass...' infinite loop issue caused by
missing CORS headers and unhandled network timeouts.
This commit is contained in:
southseact-3d
2026-02-17 10:20:11 +00:00
parent 103951eb3c
commit 0c954449d3
3 changed files with 121 additions and 11 deletions

View File

@@ -116,9 +116,24 @@ async function clearAuth() {
}
}
// API client with authentication
// API client with authentication and timeout
const REQUEST_TIMEOUT = 10000; // 10 second timeout
function fetchWithTimeout(url, options, timeout = REQUEST_TIMEOUT) {
return Promise.race([
fetch(url, options),
new Promise((_, reject) =>
setTimeout(() => reject(new Error(`Request timeout after ${timeout}ms`)), timeout)
)
]);
}
async function apiClient(endpoint, options = {}) {
const url = endpoint.startsWith('http') ? endpoint : `${BACKEND_BASE_URL}${endpoint}`;
const requestId = Math.random().toString(36).substring(7);
console.log(`[API:${requestId}] Starting request to ${endpoint}`);
console.log(`[API:${requestId}] Full URL: ${url}`);
const token = await getAuthToken();
const headers = {
@@ -128,20 +143,28 @@ async function apiClient(endpoint, options = {}) {
};
try {
const response = await fetch(url, {
console.log(`[API:${requestId}] Sending ${options.method || 'GET'} request...`);
const startTime = Date.now();
const response = await fetchWithTimeout(url, {
...options,
headers,
credentials: 'include'
});
const duration = Date.now() - startTime;
console.log(`[API:${requestId}] Response received in ${duration}ms - Status: ${response.status}`);
// Handle token expiration
if (response.status === 401) {
console.log(`[API:${requestId}] Token expired, attempting refresh...`);
const refreshed = await refreshAccessToken();
if (refreshed) {
console.log(`[API:${requestId}] Token refreshed, retrying request...`);
// Retry with new token
const newToken = await getAuthToken();
headers['Authorization'] = `Bearer ${newToken}`;
const retryResponse = await fetch(url, {
const retryResponse = await fetchWithTimeout(url, {
...options,
headers,
credentials: 'include'
@@ -149,6 +172,7 @@ async function apiClient(endpoint, options = {}) {
return handleResponse(retryResponse);
} else {
// Token refresh failed, clear auth
console.error(`[API:${requestId}] Token refresh failed`);
await clearAuth();
throw new Error('Session expired. Please sign in again.');
}
@@ -156,7 +180,12 @@ async function apiClient(endpoint, options = {}) {
return handleResponse(response);
} catch (error) {
console.error(`[API] Request failed: ${endpoint}`, error);
console.error(`[API:${requestId}] Request failed: ${endpoint}`, error);
console.error(`[API:${requestId}] Error details:`, {
message: error.message,
name: error.name,
stack: error.stack
});
throw error;
}
}
@@ -282,16 +311,21 @@ export async function logout() {
}
export async function getCurrentUser() {
console.log('[AUTH] Getting current user...');
try {
// First check stored user
console.log('[AUTH] Checking stored user...');
const { value } = await Preferences.get({ key: STORAGE_KEYS.USER });
if (value) {
const user = JSON.parse(value);
console.log('[AUTH] Found stored user:', user.email || user.id);
// Verify token is still valid by fetching fresh user data
try {
console.log('[AUTH] Fetching fresh user data from /api/me...');
const freshUser = await apiClient('/api/me');
if (freshUser) {
console.log('[AUTH] Fresh user data received:', freshUser.email || freshUser.id);
await Preferences.set({
key: STORAGE_KEYS.USER,
value: JSON.stringify(freshUser)
@@ -300,23 +334,39 @@ export async function getCurrentUser() {
}
} catch (e) {
console.warn('[AUTH] Could not refresh user data:', e.message);
console.log('[AUTH] Falling back to cached user data');
}
return user;
}
console.log('[AUTH] No stored user found');
return null;
} catch (e) {
console.error('[AUTH] Failed to get current user:', e);
console.error('[AUTH] Error details:', {
message: e.message,
name: e.name,
stack: e.stack
});
return null;
}
}
export async function isAuthenticated() {
console.log('[AUTH] Checking authentication status...');
const token = await getAuthToken();
if (!token) return false;
console.log('[AUTH] Token exists:', !!token);
if (!token) {
console.log('[AUTH] No token found, user is not authenticated');
return false;
}
console.log('[AUTH] Token found, fetching current user...');
const user = await getCurrentUser();
return !!user;
const isAuth = !!user;
console.log('[AUTH] Authentication result:', isAuth, user ? `(User: ${user.email || user.id})` : '');
return isAuth;
}
// OAuth helpers

View File

@@ -610,28 +610,48 @@ async function createMobileIndex() {
// Initialize app
async function initApp() {
console.log('[APP] Initializing...');
console.log('[APP] ===========================================');
console.log('[APP] Starting app initialization...');
console.log('[APP] Current time:', new Date().toISOString());
console.log('[APP] User agent:', navigator.userAgent);
console.log('[APP] Platform:', navigator.platform);
try {
// Check if user is authenticated
console.log('[APP] Step 1/4: Checking authentication...');
const authenticated = await isAuthenticated();
console.log('[APP] Authenticated:', authenticated);
console.log('[APP] Step 1/4 complete - Authenticated:', authenticated);
if (authenticated) {
console.log('[APP] Step 2/4: Getting current user...');
const user = await getCurrentUser();
console.log('[APP] Step 2/4 complete - User:', user ? user.email || user.id : 'null');
console.log('[APP] Step 3/4: Checking onboarding status...');
const onboardingDone = await isOnboardingComplete();
console.log('[APP] Step 3/4 complete - Onboarding done:', onboardingDone);
if (!onboardingDone) {
console.log('[APP] Step 4/4: Showing onboarding screen');
showScreen('onboarding');
} else {
console.log('[APP] Step 4/4: Showing main screen');
showScreen('main');
updateWelcome(user);
}
} else {
console.log('[APP] Step 2/2: User not authenticated, showing auth screen');
showScreen('auth');
}
console.log('[APP] ===========================================');
console.log('[APP] Initialization complete!');
} catch (error) {
console.error('[APP] Initialization error:', error);
console.error('[APP] ===========================================');
console.error('[APP] FATAL: Initialization error:', error);
console.error('[APP] Error name:', error.name);
console.error('[APP] Error message:', error.message);
console.error('[APP] Error stack:', error.stack);
console.error('[APP] ===========================================');
showScreen('auth');
}
}
@@ -747,6 +767,10 @@ async function createMobileIndex() {
// Event listeners
document.addEventListener('DOMContentLoaded', () => {
console.log('[APP] ===========================================');
console.log('[APP] DOMContentLoaded event fired!');
console.log('[APP] Starting app in 500ms...');
console.log('[APP] ===========================================');
// Auth form - Sign In
const authSubmitBtn = document.getElementById('auth-submit');
const authSignupBtn = document.getElementById('auth-signup');