changed the navbar to work.
All checks were successful
Build Frontend / Build Frontend (push) Successful in 35s
All checks were successful
Build Frontend / Build Frontend (push) Successful in 35s
This commit is contained in:
225
DEPLOY_NAVBAR_FIX.md
Normal file
225
DEPLOY_NAVBAR_FIX.md
Normal file
@@ -0,0 +1,225 @@
|
||||
# Deploy Navbar Login Fix - Quick Checklist
|
||||
|
||||
## 🎯 What This Fixes
|
||||
|
||||
**Problem:** After logging in via Steam, the navbar doesn't update to show the logged-in state (avatar, username, balance).
|
||||
|
||||
**Solution:** WebSocket now triggers auth state refresh when connection is established.
|
||||
|
||||
---
|
||||
|
||||
## ✅ Pre-Deployment Checklist
|
||||
|
||||
- [x] Source code changes committed
|
||||
- [x] Frontend build successful
|
||||
- [x] Verification script passed
|
||||
- [ ] Backend is running
|
||||
- [ ] Ready to deploy
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Quick Deploy (Production)
|
||||
|
||||
### On Your Server
|
||||
|
||||
```bash
|
||||
# 1. Navigate to project
|
||||
cd /path/to/TurboTrades
|
||||
|
||||
# 2. Pull latest changes
|
||||
git pull origin main
|
||||
|
||||
# 3. Build frontend
|
||||
cd frontend
|
||||
npm install # only if package.json changed
|
||||
npm run build
|
||||
|
||||
# 4. Deploy to web root
|
||||
sudo cp -r dist/* /var/www/html/turbotrades/
|
||||
|
||||
# 5. Verify deployment
|
||||
curl -I https://turbotrades.dev # Should return 200
|
||||
|
||||
# Done! 🎉
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Testing After Deployment
|
||||
|
||||
### 1. Clear Browser Cache
|
||||
|
||||
- **Chrome/Edge:** `Ctrl + Shift + R` (Windows/Linux) or `Cmd + Shift + R` (Mac)
|
||||
- **Firefox:** `Ctrl + Shift + R` (Windows/Linux) or `Cmd + Shift + R` (Mac)
|
||||
- **Or use Incognito/Private mode**
|
||||
|
||||
### 2. Open Browser Console
|
||||
|
||||
Press `F12` → **Console** tab
|
||||
|
||||
### 3. Clear All Site Data
|
||||
|
||||
In DevTools:
|
||||
- **Application** tab → **Clear storage** → **Clear site data**
|
||||
|
||||
### 4. Test Login Flow
|
||||
|
||||
1. Click "Login to Steam" button
|
||||
2. Complete Steam authentication
|
||||
3. Watch console for these logs:
|
||||
|
||||
```
|
||||
🔵 Auth store initialize called - isInitialized: false
|
||||
🔵 fetchUser called - fetching user from /api/auth/me
|
||||
✅ fetchUser response: { success: true, user: {...} }
|
||||
✅ Setting user in auth store: { steamId: "...", ... }
|
||||
🔵 fetchUser complete - isAuthenticated: true
|
||||
|
||||
Connecting to WebSocket: wss://api.turbotrades.dev/ws
|
||||
WebSocket connected
|
||||
🟢 WebSocket received 'connected' message: { ... }
|
||||
🔵 Calling authStore.fetchUser() from WebSocket connected handler
|
||||
🔵 fetchUser called - fetching user from /api/auth/me
|
||||
✅ fetchUser response: { success: true, user: {...} }
|
||||
```
|
||||
|
||||
### 5. Verify Navbar
|
||||
|
||||
Should now show:
|
||||
- ✅ Your Steam avatar
|
||||
- ✅ Your username
|
||||
- ✅ Your balance with deposit button
|
||||
- ✅ User dropdown menu (Profile, Inventory, etc.)
|
||||
|
||||
---
|
||||
|
||||
## 🔧 If It Doesn't Work
|
||||
|
||||
### Common Issues
|
||||
|
||||
#### Navbar Still Not Updating
|
||||
|
||||
```bash
|
||||
# 1. Hard refresh browser (clear all cache)
|
||||
Ctrl + Shift + Delete → Clear all browsing data
|
||||
|
||||
# 2. Check if build was actually deployed
|
||||
curl -I https://turbotrades.dev/assets/index-*.js
|
||||
|
||||
# 3. Check console for errors
|
||||
# Look for CORS errors, 404s, or auth failures
|
||||
```
|
||||
|
||||
#### WebSocket Not Connecting
|
||||
|
||||
```bash
|
||||
# Check Nginx config has WebSocket proxy
|
||||
sudo cat /etc/nginx/sites-available/turbotrades-api
|
||||
|
||||
# Should have:
|
||||
location /ws {
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_pass http://127.0.0.1:3000/ws;
|
||||
}
|
||||
|
||||
# Reload Nginx if changed
|
||||
sudo nginx -t
|
||||
sudo systemctl reload nginx
|
||||
```
|
||||
|
||||
#### Backend Issues
|
||||
|
||||
```bash
|
||||
# Check backend is running
|
||||
pm2 status
|
||||
|
||||
# Check logs
|
||||
pm2 logs turbotrades-backend --lines 50
|
||||
|
||||
# Restart if needed
|
||||
pm2 restart turbotrades-backend
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Verification Script
|
||||
|
||||
Run this to check everything is ready:
|
||||
|
||||
```bash
|
||||
node scripts/verify-login-fix.cjs
|
||||
```
|
||||
|
||||
**Expected output:**
|
||||
```
|
||||
✅ WebSocket store has the navbar login fix
|
||||
✅ Frontend build exists and looks valid
|
||||
✅ API Health Endpoint: Reachable
|
||||
✅ WebSocket: Connection successful
|
||||
All checks passed! ✨
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Rollback (If Needed)
|
||||
|
||||
```bash
|
||||
# Revert commits
|
||||
git revert HEAD~2..HEAD
|
||||
git push origin main
|
||||
|
||||
# Rebuild and redeploy
|
||||
cd frontend
|
||||
npm run build
|
||||
sudo cp -r dist/* /var/www/html/turbotrades/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📝 Files Changed
|
||||
|
||||
- `frontend/src/stores/websocket.js` - Added `authStore.fetchUser()` call on WebSocket connected
|
||||
- `frontend/src/stores/auth.js` - Added debug logging for troubleshooting
|
||||
|
||||
---
|
||||
|
||||
## 🎓 How It Works
|
||||
|
||||
1. **User logs in** → Steam OAuth → Backend sets session cookie
|
||||
2. **Frontend loads** → `App.vue` calls `authStore.initialize()`
|
||||
3. **WebSocket connects** → Server sends `{ type: "connected", data: {...} }`
|
||||
4. **NEW:** WebSocket handler calls `authStore.fetchUser()`
|
||||
5. **Auth store updates** → `isAuthenticated = true`
|
||||
6. **Navbar reactively updates** → Shows logged-in UI
|
||||
|
||||
---
|
||||
|
||||
## ✨ Success Criteria
|
||||
|
||||
- [x] Source code has the fix
|
||||
- [x] Frontend build is recent
|
||||
- [x] API endpoints reachable
|
||||
- [x] WebSocket connection works
|
||||
- [ ] **User can login and see navbar update**
|
||||
|
||||
---
|
||||
|
||||
**Status:** Ready to Deploy
|
||||
**Build Date:** 2025-01-10
|
||||
**Estimated Deploy Time:** 5 minutes
|
||||
**Risk Level:** Low (only frontend changes)
|
||||
|
||||
---
|
||||
|
||||
## 🆘 Need Help?
|
||||
|
||||
Check these docs:
|
||||
- Full details: `NAVBAR_LOGIN_FIX.md`
|
||||
- Troubleshooting: `DEPLOYMENT_FIXES.md`
|
||||
- Environment setup: `ENV_SETUP.md`
|
||||
|
||||
Or check the logs:
|
||||
```bash
|
||||
pm2 logs turbotrades-backend
|
||||
```
|
||||
337
NAVBAR_LOGIN_FIX.md
Normal file
337
NAVBAR_LOGIN_FIX.md
Normal file
@@ -0,0 +1,337 @@
|
||||
# Navbar Login Fix - WebSocket Authentication State Update
|
||||
|
||||
## Problem Description
|
||||
|
||||
After successfully logging in via Steam, the WebSocket would connect and receive user data from the server, but the navbar would not update to show the logged-in state.
|
||||
|
||||
### Root Cause
|
||||
|
||||
The WebSocket `connected` message handler was receiving user data (steamId, username, userId) but was only logging it to the console. It was **not updating the auth store**, which the navbar component relies on to display authentication state.
|
||||
|
||||
**Console logs showed:**
|
||||
```
|
||||
🔵 AnnouncementBanner mounted - loading announcements...
|
||||
WebSocket connected
|
||||
WebSocket message received: { type: "connected", data: {...} }
|
||||
Server confirmed connection: { steamId: "...", username: "...", userId: "..." }
|
||||
```
|
||||
|
||||
But the navbar remained in logged-out state because `authStore.isAuthenticated` was still `false`.
|
||||
|
||||
---
|
||||
|
||||
## Solution
|
||||
|
||||
### Changes Made
|
||||
|
||||
#### 1. WebSocket Store (`frontend/src/stores/websocket.js`)
|
||||
- **Modified the `"connected"` message handler** to call `authStore.fetchUser()` when the WebSocket connection is confirmed
|
||||
- **Fixed duplicate `authStore` declarations** by declaring it once at the top of `handleMessage` function
|
||||
- **Added debug logging** to trace the authentication flow
|
||||
|
||||
**Before:**
|
||||
```javascript
|
||||
case "connected":
|
||||
console.log("Server confirmed connection:", payload);
|
||||
break;
|
||||
```
|
||||
|
||||
**After:**
|
||||
```javascript
|
||||
const handleMessage = (data) => {
|
||||
const { type, data: payload, timestamp } = data;
|
||||
const authStore = useAuthStore(); // Declared once at top
|
||||
|
||||
switch (type) {
|
||||
case "connected":
|
||||
console.log("🟢 WebSocket received 'connected' message:", payload);
|
||||
// Fetch updated user data from the auth endpoint
|
||||
console.log("🔵 Calling authStore.fetchUser() from WebSocket connected handler");
|
||||
authStore.fetchUser();
|
||||
break;
|
||||
|
||||
case "balance_update":
|
||||
// Now uses authStore declared at top
|
||||
if (payload?.balance !== undefined) {
|
||||
authStore.updateBalance(payload.balance);
|
||||
}
|
||||
break;
|
||||
// ... rest of cases
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
#### 2. Auth Store (`frontend/src/stores/auth.js`)
|
||||
- **Added debug logging** to trace authentication initialization and user fetch operations
|
||||
|
||||
**Added logs:**
|
||||
```javascript
|
||||
console.log("🔵 fetchUser called - fetching user from /api/auth/me");
|
||||
console.log("✅ fetchUser response:", response.data);
|
||||
console.log("✅ Setting user in auth store:", response.data.user);
|
||||
console.log("🔵 fetchUser complete - isAuthenticated:", isAuthenticated.value);
|
||||
console.log("🔵 Auth store initialize called - isInitialized:", isInitialized.value);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## How It Works Now
|
||||
|
||||
### Authentication Flow After Steam Login
|
||||
|
||||
1. **User clicks "Login to Steam"** button
|
||||
- Frontend redirects to: `${VITE_API_URL}/api/auth/steam`
|
||||
|
||||
2. **Steam OAuth flow completes**
|
||||
- Backend receives callback from Steam
|
||||
- Backend creates session and sets HTTP-only cookie
|
||||
- Backend redirects user back to frontend
|
||||
|
||||
3. **Frontend loads** (`App.vue` `onMounted`)
|
||||
- `authStore.initialize()` → calls `fetchUser()` → requests `/api/auth/me`
|
||||
- `wsStore.connect()` → establishes WebSocket connection
|
||||
|
||||
4. **WebSocket connects successfully**
|
||||
- Backend sends `{ type: "connected", data: { steamId, username, userId } }`
|
||||
|
||||
5. **WebSocket receives "connected" message** ✨ **NEW**
|
||||
- Handler calls `authStore.fetchUser()`
|
||||
- Fetches user data from `/api/auth/me` with credentials
|
||||
- Updates `authStore.user` and sets `isAuthenticated = true`
|
||||
|
||||
6. **Navbar reactively updates** 🎉
|
||||
- `authStore.isAuthenticated` changes from `false` → `true`
|
||||
- Vue's reactivity triggers navbar to show user menu, avatar, balance, etc.
|
||||
|
||||
---
|
||||
|
||||
## Deployment Instructions
|
||||
|
||||
### 1. Build the Frontend
|
||||
|
||||
```bash
|
||||
cd frontend
|
||||
npm run build
|
||||
```
|
||||
|
||||
**Expected output:**
|
||||
```
|
||||
✓ 1588 modules transformed.
|
||||
✓ built in 2.80s
|
||||
```
|
||||
|
||||
### 2. Deploy to Production
|
||||
|
||||
**Option A: Manual deployment on server**
|
||||
```bash
|
||||
# SSH into your server
|
||||
ssh user@your-server
|
||||
|
||||
# Navigate to project
|
||||
cd /path/to/TurboTrades/frontend
|
||||
|
||||
# Pull latest changes
|
||||
git pull origin main
|
||||
|
||||
# Build
|
||||
npm install # if dependencies changed
|
||||
npm run build
|
||||
|
||||
# Copy to web root
|
||||
sudo cp -r dist/* /var/www/html/turbotrades/
|
||||
```
|
||||
|
||||
**Option B: CI/CD Pipeline**
|
||||
```bash
|
||||
# Commit and push changes
|
||||
git add frontend/src/stores/websocket.js frontend/src/stores/auth.js
|
||||
git commit -m "Fix navbar not updating after Steam login - WebSocket auth state sync"
|
||||
git push origin main
|
||||
|
||||
# Your CI/CD pipeline will automatically:
|
||||
# 1. Pull changes
|
||||
# 2. Build frontend
|
||||
# 3. Deploy to production
|
||||
```
|
||||
|
||||
### 3. Clear Browser Cache
|
||||
|
||||
After deployment, users need to hard-refresh to get the new JavaScript bundle:
|
||||
|
||||
- **Windows/Linux:** `Ctrl + Shift + R` or `Ctrl + F5`
|
||||
- **Mac:** `Cmd + Shift + R`
|
||||
- **Or use Incognito/Private mode** for testing
|
||||
|
||||
---
|
||||
|
||||
## Testing the Fix
|
||||
|
||||
### 1. Open Browser Console
|
||||
|
||||
Press `F12` to open DevTools and go to Console tab.
|
||||
|
||||
### 2. Clear Cookies and Storage
|
||||
|
||||
In DevTools:
|
||||
- Go to **Application** tab
|
||||
- Click **Clear storage** → **Clear site data**
|
||||
|
||||
### 3. Attempt Login
|
||||
|
||||
Click "Login to Steam" button and complete authentication.
|
||||
|
||||
### 4. Watch Console Logs
|
||||
|
||||
You should see this sequence:
|
||||
|
||||
```
|
||||
🔵 Auth store initialize called - isInitialized: false
|
||||
🔵 fetchUser called - fetching user from /api/auth/me
|
||||
✅ fetchUser response: { success: true, user: {...} }
|
||||
✅ Setting user in auth store: { steamId: "...", username: "...", ... }
|
||||
🔵 fetchUser complete - isAuthenticated: true
|
||||
|
||||
Connecting to WebSocket: wss://api.turbotrades.dev/ws
|
||||
WebSocket connected
|
||||
🟢 WebSocket received 'connected' message: { steamId: "...", username: "...", userId: "..." }
|
||||
🔵 Calling authStore.fetchUser() from WebSocket connected handler
|
||||
🔵 fetchUser called - fetching user from /api/auth/me
|
||||
✅ fetchUser response: { success: true, user: {...} }
|
||||
✅ Setting user in auth store: { steamId: "...", username: "...", ... }
|
||||
🔵 fetchUser complete - isAuthenticated: true
|
||||
```
|
||||
|
||||
### 5. Verify Navbar Updates
|
||||
|
||||
The navbar should now show:
|
||||
- ✅ Your Steam avatar
|
||||
- ✅ Your username
|
||||
- ✅ Your balance with deposit button
|
||||
- ✅ User dropdown menu with Profile, Inventory, etc.
|
||||
|
||||
---
|
||||
|
||||
## Rollback Plan
|
||||
|
||||
If issues occur after deployment:
|
||||
|
||||
### Quick Rollback
|
||||
```bash
|
||||
# Revert the commits
|
||||
git revert HEAD~2..HEAD
|
||||
|
||||
# Rebuild and redeploy
|
||||
cd frontend
|
||||
npm run build
|
||||
sudo cp -r dist/* /var/www/html/turbotrades/
|
||||
```
|
||||
|
||||
### Remove Debug Logs (Production Cleanup)
|
||||
|
||||
Once confirmed working, you may want to remove the verbose debug logs:
|
||||
|
||||
**In `frontend/src/stores/auth.js`** - remove all `console.log` statements added
|
||||
|
||||
**In `frontend/src/stores/websocket.js`** - remove or reduce debug logs:
|
||||
```javascript
|
||||
case "connected":
|
||||
// Keep minimal logging
|
||||
console.log("WebSocket connected");
|
||||
authStore.fetchUser();
|
||||
break;
|
||||
```
|
||||
|
||||
Then rebuild and redeploy.
|
||||
|
||||
---
|
||||
|
||||
## Additional Notes
|
||||
|
||||
### Why Two `fetchUser()` Calls?
|
||||
|
||||
You might notice `fetchUser()` is called twice:
|
||||
|
||||
1. **On App Mount** (`App.vue` → `authStore.initialize()`)
|
||||
- Handles the case where user already has a valid session
|
||||
- Runs immediately when page loads
|
||||
|
||||
2. **On WebSocket Connected** (new addition)
|
||||
- Handles the case where user just logged in via Steam
|
||||
- Ensures auth state is fresh after Steam OAuth redirect
|
||||
- Provides a fallback if the initial fetch happened before the session cookie was set
|
||||
|
||||
This redundancy is intentional and ensures authentication works reliably in all scenarios.
|
||||
|
||||
### Session Persistence
|
||||
|
||||
The authentication uses HTTP-only cookies set by the backend. These persist across:
|
||||
- Page refreshes
|
||||
- Browser restarts (unless expired)
|
||||
- Tab closures
|
||||
|
||||
The WebSocket connection authenticates using the same session cookie.
|
||||
|
||||
---
|
||||
|
||||
## Related Files
|
||||
|
||||
- `frontend/src/stores/websocket.js` - WebSocket message handling
|
||||
- `frontend/src/stores/auth.js` - Authentication state management
|
||||
- `frontend/src/components/NavBar.vue` - Navbar component (reactive to auth state)
|
||||
- `frontend/src/App.vue` - App initialization flow
|
||||
- `backend/routes/auth.js` - Steam OAuth and session management
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Navbar Still Not Updating
|
||||
|
||||
1. **Clear browser cache completely** (not just refresh)
|
||||
2. **Check browser console for errors**
|
||||
3. **Verify `/api/auth/me` returns user data:**
|
||||
```bash
|
||||
curl -s https://api.turbotrades.dev/api/auth/me -b cookies.txt | jq
|
||||
```
|
||||
4. **Check WebSocket connection:**
|
||||
- Look for "WebSocket connected" in console
|
||||
- Verify no CORS errors
|
||||
|
||||
### "fetchUser called" But No Response
|
||||
|
||||
- **Backend issue:** Check PM2 logs
|
||||
```bash
|
||||
pm2 logs turbotrades-backend --lines 50
|
||||
```
|
||||
- **CORS issue:** Check for CORS errors in browser console
|
||||
- **Session cookie not set:** Check backend logs for Steam OAuth errors
|
||||
|
||||
### WebSocket Doesn't Receive "connected" Message
|
||||
|
||||
- **Backend WebSocket handler issue:** Check `backend/services/websocket.js`
|
||||
- **Nginx not proxying WS correctly:** Verify Nginx config has:
|
||||
```nginx
|
||||
location /ws {
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_pass http://127.0.0.1:3000/ws;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Success Criteria
|
||||
|
||||
✅ User can click "Login to Steam" and complete OAuth flow
|
||||
✅ Upon redirect back to site, navbar shows logged-in state
|
||||
✅ User's avatar, username, and balance are displayed
|
||||
✅ WebSocket connects and shows user data in console
|
||||
✅ User can access protected routes (Inventory, Profile, etc.)
|
||||
✅ No console errors related to authentication or WebSocket
|
||||
|
||||
---
|
||||
|
||||
**Status:** Ready for deployment
|
||||
**Last Updated:** 2025-01-10
|
||||
**Build Tested:** ✅ Success
|
||||
**Files Modified:** 2 (websocket.js, auth.js)
|
||||
@@ -44,26 +44,35 @@ export const useAuthStore = defineStore("auth", () => {
|
||||
const fetchUser = async () => {
|
||||
if (isLoading.value) return;
|
||||
|
||||
console.log("🔵 fetchUser called - fetching user from /api/auth/me");
|
||||
isLoading.value = true;
|
||||
try {
|
||||
const response = await axios.get("/api/auth/me", {
|
||||
withCredentials: true,
|
||||
});
|
||||
|
||||
console.log("✅ fetchUser response:", response.data);
|
||||
|
||||
if (response.data.success && response.data.user) {
|
||||
console.log("✅ Setting user in auth store:", response.data.user);
|
||||
setUser(response.data.user);
|
||||
return response.data.user;
|
||||
} else {
|
||||
console.log("❌ No user in response, clearing auth");
|
||||
clearUser();
|
||||
return null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch user:", error);
|
||||
console.error("❌ Failed to fetch user:", error);
|
||||
clearUser();
|
||||
return null;
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
isInitialized.value = true;
|
||||
console.log(
|
||||
"🔵 fetchUser complete - isAuthenticated:",
|
||||
isAuthenticated.value
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -229,6 +238,10 @@ export const useAuthStore = defineStore("auth", () => {
|
||||
|
||||
// Initialize on store creation
|
||||
const initialize = async () => {
|
||||
console.log(
|
||||
"🔵 Auth store initialize called - isInitialized:",
|
||||
isInitialized.value
|
||||
);
|
||||
if (!isInitialized.value) {
|
||||
await fetchUser();
|
||||
}
|
||||
|
||||
@@ -208,10 +208,16 @@ export const useWebSocketStore = defineStore("websocket", () => {
|
||||
|
||||
const handleMessage = (data) => {
|
||||
const { type, data: payload, timestamp } = data;
|
||||
const authStore = useAuthStore();
|
||||
|
||||
switch (type) {
|
||||
case "connected":
|
||||
console.log("Server confirmed connection:", payload);
|
||||
console.log("🟢 WebSocket received 'connected' message:", payload);
|
||||
// Fetch updated user data from the auth endpoint
|
||||
console.log(
|
||||
"🔵 Calling authStore.fetchUser() from WebSocket connected handler"
|
||||
);
|
||||
authStore.fetchUser();
|
||||
break;
|
||||
|
||||
case "pong":
|
||||
@@ -226,7 +232,6 @@ export const useWebSocketStore = defineStore("websocket", () => {
|
||||
|
||||
case "balance_update":
|
||||
// Update user balance
|
||||
const authStore = useAuthStore();
|
||||
if (payload?.balance !== undefined) {
|
||||
authStore.updateBalance(payload.balance);
|
||||
}
|
||||
|
||||
314
scripts/verify-login-fix.cjs
Normal file
314
scripts/verify-login-fix.cjs
Normal file
@@ -0,0 +1,314 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Verification Script for Navbar Login Fix
|
||||
*
|
||||
* This script verifies that the WebSocket authentication state synchronization
|
||||
* is working correctly after the navbar login fix deployment.
|
||||
*
|
||||
* Usage:
|
||||
* node scripts/verify-login-fix.js
|
||||
*/
|
||||
|
||||
const https = require('https');
|
||||
const http = require('http');
|
||||
|
||||
const API_URL = process.env.VITE_API_URL || 'https://api.turbotrades.dev';
|
||||
const WS_URL = process.env.VITE_WS_URL || 'wss://api.turbotrades.dev/ws';
|
||||
|
||||
const colors = {
|
||||
reset: '\x1b[0m',
|
||||
bright: '\x1b[1m',
|
||||
green: '\x1b[32m',
|
||||
red: '\x1b[31m',
|
||||
yellow: '\x1b[33m',
|
||||
blue: '\x1b[34m',
|
||||
cyan: '\x1b[36m',
|
||||
};
|
||||
|
||||
function log(message, color = colors.reset) {
|
||||
console.log(`${color}${message}${colors.reset}`);
|
||||
}
|
||||
|
||||
function success(message) {
|
||||
log(`✅ ${message}`, colors.green);
|
||||
}
|
||||
|
||||
function error(message) {
|
||||
log(`❌ ${message}`, colors.red);
|
||||
}
|
||||
|
||||
function warning(message) {
|
||||
log(`⚠️ ${message}`, colors.yellow);
|
||||
}
|
||||
|
||||
function info(message) {
|
||||
log(`ℹ️ ${message}`, colors.cyan);
|
||||
}
|
||||
|
||||
function section(message) {
|
||||
log(`\n${colors.bright}${message}${colors.reset}`);
|
||||
log('='.repeat(60));
|
||||
}
|
||||
|
||||
// Check if endpoint is reachable
|
||||
function checkEndpoint(url, description) {
|
||||
return new Promise((resolve) => {
|
||||
const urlObj = new URL(url);
|
||||
const client = urlObj.protocol === 'https:' ? https : http;
|
||||
|
||||
const options = {
|
||||
hostname: urlObj.hostname,
|
||||
port: urlObj.port || (urlObj.protocol === 'https:' ? 443 : 80),
|
||||
path: urlObj.pathname,
|
||||
method: 'GET',
|
||||
timeout: 5000,
|
||||
};
|
||||
|
||||
const req = client.request(options, (res) => {
|
||||
if (res.statusCode >= 200 && res.statusCode < 400) {
|
||||
success(`${description}: Reachable (Status: ${res.statusCode})`);
|
||||
resolve(true);
|
||||
} else {
|
||||
warning(`${description}: Returned status ${res.statusCode}`);
|
||||
resolve(false);
|
||||
}
|
||||
});
|
||||
|
||||
req.on('error', (err) => {
|
||||
error(`${description}: ${err.message}`);
|
||||
resolve(false);
|
||||
});
|
||||
|
||||
req.on('timeout', () => {
|
||||
error(`${description}: Request timed out`);
|
||||
req.destroy();
|
||||
resolve(false);
|
||||
});
|
||||
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
|
||||
// Check WebSocket endpoint
|
||||
function checkWebSocket(url) {
|
||||
return new Promise((resolve) => {
|
||||
try {
|
||||
const WebSocket = require('ws');
|
||||
const ws = new WebSocket(url);
|
||||
|
||||
const timeout = setTimeout(() => {
|
||||
ws.close();
|
||||
error('WebSocket: Connection timeout');
|
||||
resolve(false);
|
||||
}, 5000);
|
||||
|
||||
ws.on('open', () => {
|
||||
clearTimeout(timeout);
|
||||
success('WebSocket: Connection successful');
|
||||
ws.close();
|
||||
resolve(true);
|
||||
});
|
||||
|
||||
ws.on('error', (err) => {
|
||||
clearTimeout(timeout);
|
||||
error(`WebSocket: ${err.message}`);
|
||||
resolve(false);
|
||||
});
|
||||
|
||||
} catch (err) {
|
||||
error(`WebSocket: ws module not available (${err.message})`);
|
||||
warning('Install with: npm install ws');
|
||||
resolve(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Read and verify frontend build files
|
||||
function checkFrontendBuild() {
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const distPath = path.join(__dirname, '..', 'frontend', 'dist');
|
||||
const indexPath = path.join(distPath, 'index.html');
|
||||
|
||||
if (!fs.existsSync(distPath)) {
|
||||
error('Frontend dist directory not found');
|
||||
warning('Run: cd frontend && npm run build');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!fs.existsSync(indexPath)) {
|
||||
error('Frontend index.html not found in dist/');
|
||||
return false;
|
||||
}
|
||||
|
||||
const indexContent = fs.readFileSync(indexPath, 'utf8');
|
||||
|
||||
// Check for recent build by looking for assets
|
||||
const hasAssets = indexContent.includes('/assets/');
|
||||
const hasModernJS = indexContent.includes('type="module"');
|
||||
|
||||
if (hasAssets && hasModernJS) {
|
||||
success('Frontend build exists and looks valid');
|
||||
|
||||
// Get build timestamp from file modification time
|
||||
const stats = fs.statSync(indexPath);
|
||||
const buildTime = stats.mtime;
|
||||
const now = new Date();
|
||||
const ageMinutes = Math.floor((now - buildTime) / 1000 / 60);
|
||||
|
||||
if (ageMinutes < 60) {
|
||||
success(`Build age: ${ageMinutes} minutes (recent)`);
|
||||
} else if (ageMinutes < 1440) {
|
||||
info(`Build age: ${Math.floor(ageMinutes / 60)} hours`);
|
||||
} else {
|
||||
warning(`Build age: ${Math.floor(ageMinutes / 1440)} days (consider rebuilding)`);
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
error('Frontend build appears invalid');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check source files for the fix
|
||||
function checkSourceCode() {
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const websocketStorePath = path.join(__dirname, '..', 'frontend', 'src', 'stores', 'websocket.js');
|
||||
const authStorePath = path.join(__dirname, '..', 'frontend', 'src', 'stores', 'auth.js');
|
||||
|
||||
if (!fs.existsSync(websocketStorePath)) {
|
||||
error('WebSocket store not found');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!fs.existsSync(authStorePath)) {
|
||||
error('Auth store not found');
|
||||
return false;
|
||||
}
|
||||
|
||||
const websocketCode = fs.readFileSync(websocketStorePath, 'utf8');
|
||||
const authCode = fs.readFileSync(authStorePath, 'utf8');
|
||||
|
||||
// Check for the fix in websocket store
|
||||
const hasConnectedHandler = websocketCode.includes('case "connected":');
|
||||
const callsFetchUser = websocketCode.includes('authStore.fetchUser()');
|
||||
const declaresAuthStore = websocketCode.includes('const authStore = useAuthStore()');
|
||||
|
||||
if (hasConnectedHandler && callsFetchUser && declaresAuthStore) {
|
||||
success('WebSocket store has the navbar login fix');
|
||||
} else {
|
||||
error('WebSocket store missing the fix');
|
||||
if (!hasConnectedHandler) warning(' - Missing "connected" case handler');
|
||||
if (!callsFetchUser) warning(' - Not calling authStore.fetchUser()');
|
||||
if (!declaresAuthStore) warning(' - Not declaring authStore');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for debug logging (optional)
|
||||
const hasDebugLogs = websocketCode.includes('🟢 WebSocket received') ||
|
||||
authCode.includes('🔵 fetchUser called');
|
||||
|
||||
if (hasDebugLogs) {
|
||||
info('Debug logging is present (helpful for troubleshooting)');
|
||||
} else {
|
||||
info('Debug logging not present (clean for production)');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Main verification flow
|
||||
async function main() {
|
||||
log('\n' + '='.repeat(60), colors.bright);
|
||||
log(' NAVBAR LOGIN FIX - VERIFICATION SCRIPT', colors.bright);
|
||||
log('='.repeat(60) + '\n', colors.bright);
|
||||
|
||||
let allChecks = true;
|
||||
|
||||
// 1. Check source code
|
||||
section('1. Checking Source Code');
|
||||
const sourceCheck = checkSourceCode();
|
||||
allChecks = allChecks && sourceCheck;
|
||||
|
||||
// 2. Check frontend build
|
||||
section('2. Checking Frontend Build');
|
||||
const buildCheck = checkFrontendBuild();
|
||||
allChecks = allChecks && buildCheck;
|
||||
|
||||
// 3. Check API endpoints
|
||||
section('3. Checking API Endpoints');
|
||||
|
||||
const apiHealthCheck = await checkEndpoint(
|
||||
`${API_URL}/api/health`,
|
||||
'API Health Endpoint'
|
||||
);
|
||||
|
||||
const apiAuthCheck = await checkEndpoint(
|
||||
`${API_URL}/api/auth/me`,
|
||||
'Auth Endpoint (/api/auth/me)'
|
||||
);
|
||||
|
||||
const publicConfigCheck = await checkEndpoint(
|
||||
`${API_URL}/api/config/public`,
|
||||
'Public Config Endpoint'
|
||||
);
|
||||
|
||||
allChecks = allChecks && apiHealthCheck && apiAuthCheck && publicConfigCheck;
|
||||
|
||||
// 4. Check WebSocket
|
||||
section('4. Checking WebSocket Connection');
|
||||
const wsCheck = await checkWebSocket(WS_URL);
|
||||
allChecks = allChecks && wsCheck;
|
||||
|
||||
// Summary
|
||||
section('Verification Summary');
|
||||
|
||||
if (allChecks) {
|
||||
success('All checks passed! ✨');
|
||||
log('\n📋 Next Steps:', colors.bright);
|
||||
log(' 1. Deploy the frontend build to production');
|
||||
log(' 2. Clear browser cache (Ctrl+Shift+R)');
|
||||
log(' 3. Test Steam login in browser');
|
||||
log(' 4. Verify navbar updates after login\n');
|
||||
} else {
|
||||
error('Some checks failed!');
|
||||
log('\n📋 Recommended Actions:', colors.bright);
|
||||
|
||||
if (!sourceCheck) {
|
||||
log(' • Verify the code changes are committed');
|
||||
log(' • Pull latest changes: git pull origin main');
|
||||
}
|
||||
|
||||
if (!buildCheck) {
|
||||
log(' • Rebuild frontend: cd frontend && npm run build');
|
||||
}
|
||||
|
||||
if (!apiHealthCheck || !apiAuthCheck || !publicConfigCheck) {
|
||||
log(' • Check backend is running: pm2 status');
|
||||
log(' • Check backend logs: pm2 logs turbotrades-backend');
|
||||
log(' • Verify Nginx configuration');
|
||||
}
|
||||
|
||||
if (!wsCheck) {
|
||||
log(' • Check WebSocket endpoint in Nginx config');
|
||||
log(' • Verify backend WebSocket service is running');
|
||||
log(' • Check firewall rules for WebSocket connections');
|
||||
}
|
||||
|
||||
log('');
|
||||
}
|
||||
|
||||
process.exit(allChecks ? 0 : 1);
|
||||
}
|
||||
|
||||
// Run the script
|
||||
main().catch((err) => {
|
||||
error(`Unexpected error: ${err.message}`);
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user