Fix build issues and update dependencies

🔧 Build Fixes:
- Update Node.js version from 18.x to 22.x (required by Vercel)
- Remove debug endpoints to get under 12 function limit for Hobby plan
- Downgrade React from 19.x to 18.x for better compatibility
- Update react-router-dom to v6.28.0 (compatible with Node 22)
- Update TypeScript to v5.7.3
- Update React types to match React version

Functions count: 12/12 (at limit for Hobby plan)

Core API endpoints:
 auth/login.js, auth/register.js
 collections/index.js, collections/add-card.js
 cards/find-or-create.js
 admin/users.js, admin/promote-user.js
 setup-auth.js, simple.js
 Legacy: migrate.ts, v1/cards/[id].ts, v1/cards/index.ts
This commit is contained in:
Randall Stillwell 2025-07-22 08:18:51 -05:00
parent e4b00ea227
commit 7dc8718512
5 changed files with 7 additions and 245 deletions

View file

@ -1,18 +0,0 @@
export default function handler(req, res) {
res.status(200).json({
success: true,
message: 'Debug endpoint - latest version',
timestamp: new Date().toISOString(),
method: req.method,
environment: process.env.NODE_ENV || 'unknown',
vercel_env: process.env.VERCEL_ENV || 'unknown',
has_database_url: !!process.env.DATABASE_URL,
has_jwt_secret: !!process.env.JWT_SECRET,
database_url_length: process.env.DATABASE_URL ? process.env.DATABASE_URL.length : 0,
database_url_starts_with: process.env.DATABASE_URL ?
process.env.DATABASE_URL.substring(0, 20) + '...' : 'not set',
all_env_keys: Object.keys(process.env).filter(key =>
key.includes('DATABASE') || key.includes('JWT') || key.includes('NEON')
)
});
}

View file

@ -1,49 +0,0 @@
const { Pool } = require('pg');
export default async function handler(req, res) {
try {
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
ssl: process.env.NODE_ENV === 'production' ? { rejectUnauthorized: false } : false,
});
const client = await pool.connect();
// Simple promotion - just add user 1 to admin role
const result = await client.query(`
INSERT INTO user_roles (user_id, role_id)
SELECT 1, id FROM roles WHERE name = 'admin'
ON CONFLICT DO NOTHING
RETURNING *
`);
// Check current roles
const userRoles = await client.query(`
SELECT
u.username,
ARRAY_AGG(r.name) as roles
FROM users u
LEFT JOIN user_roles ur ON u.id = ur.user_id
LEFT JOIN roles r ON ur.role_id = r.id
WHERE u.id = 1
GROUP BY u.username
`);
client.release();
res.status(200).json({
success: true,
message: 'Admin promotion complete',
inserted: result.rows.length > 0,
user: userRoles.rows[0] || null,
timestamp: new Date().toISOString()
});
} catch (error) {
res.status(500).json({
success: false,
error: error.message,
timestamp: new Date().toISOString()
});
}
}

View file

@ -1,108 +0,0 @@
const { Pool } = require('pg');
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
ssl: process.env.NODE_ENV === 'production' ? { rejectUnauthorized: false } : false,
});
export default async function handler(req, res) {
if (req.method !== 'POST') {
return res.status(405).json({ error: 'Method not allowed' });
}
const client = await pool.connect();
try {
// Get the test user (ID 1)
const userResult = await client.query(
'SELECT id, username, email FROM users WHERE id = $1',
[1]
);
if (userResult.rows.length === 0) {
return res.status(404).json({
error: 'Test user not found'
});
}
const user = userResult.rows[0];
// Check if user is already an admin
const adminCheckQuery = `
SELECT ur.user_id
FROM user_roles ur
JOIN roles r ON ur.role_id = r.id
WHERE ur.user_id = $1 AND r.name = 'admin'
`;
const adminCheck = await client.query(adminCheckQuery, [user.id]);
if (adminCheck.rows.length > 0) {
return res.status(200).json({
success: true,
message: 'User is already an admin',
user: {
id: user.id,
username: user.username,
email: user.email
}
});
}
// Get admin role ID
const roleResult = await client.query(
'SELECT id FROM roles WHERE name = $1',
['admin']
);
if (roleResult.rows.length === 0) {
return res.status(500).json({
error: 'Admin role not found in database'
});
}
const adminRoleId = roleResult.rows[0].id;
// Add user to admin role
await client.query(
'INSERT INTO user_roles (user_id, role_id) VALUES ($1, $2)',
[user.id, adminRoleId]
);
// Get updated user info with roles
const updatedUserQuery = `
SELECT
u.id, u.username, u.email, u.first_name, u.last_name,
ARRAY_AGG(DISTINCT r.name) as roles
FROM users u
LEFT JOIN user_roles ur ON u.id = ur.user_id
LEFT JOIN roles r ON ur.role_id = r.id
WHERE u.id = $1
GROUP BY u.id, u.username, u.email, u.first_name, u.last_name
`;
const updatedUser = await client.query(updatedUserQuery, [user.id]);
res.status(200).json({
success: true,
message: 'Test user successfully promoted to admin',
user: {
id: updatedUser.rows[0].id,
username: updatedUser.rows[0].username,
email: updatedUser.rows[0].email,
firstName: updatedUser.rows[0].first_name,
lastName: updatedUser.rows[0].last_name,
roles: updatedUser.rows[0].roles || []
}
});
} catch (error) {
console.error('Promote test user error:', error);
res.status(500).json({
error: 'Internal server error',
details: error.message
});
} finally {
client.release();
}
}

View file

@ -1,63 +0,0 @@
const { Pool } = require('pg');
export default async function handler(req, res) {
try {
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
ssl: process.env.NODE_ENV === 'production' ? { rejectUnauthorized: false } : false,
});
const client = await pool.connect();
// Test basic connection
const result = await client.query('SELECT NOW() as current_time');
// Test if users table exists
const tableCheck = await client.query(`
SELECT table_name
FROM information_schema.tables
WHERE table_schema = 'public'
AND table_name IN ('users', 'roles', 'user_roles')
`);
// If users table exists, check for test user
let userCheck = null;
if (tableCheck.rows.some(row => row.table_name === 'users')) {
try {
userCheck = await client.query(
'SELECT id, username, email FROM users WHERE username = $1',
['testuser']
);
} catch (err) {
userCheck = { error: err.message };
}
}
client.release();
res.status(200).json({
success: true,
message: 'Database connection test',
timestamp: result.rows[0].current_time,
environment: {
NODE_ENV: process.env.NODE_ENV,
has_database_url: !!process.env.DATABASE_URL,
has_jwt_secret: !!process.env.JWT_SECRET
},
tables: tableCheck.rows.map(row => row.table_name),
testUser: userCheck ? {
exists: userCheck.rows ? userCheck.rows.length > 0 : false,
data: userCheck.rows ? userCheck.rows[0] : null,
error: userCheck.error || null
} : null
});
} catch (error) {
console.error('Database test error:', error);
res.status(500).json({
success: false,
error: error.message,
stack: error.stack
});
}
}

View file

@ -3,7 +3,7 @@
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"engines": { "engines": {
"node": "18.x" "node": "22.x"
}, },
"dependencies": { "dependencies": {
"@stackframe/stack": "^2.8.22", "@stackframe/stack": "^2.8.22",
@ -18,8 +18,8 @@
"@types/next": "^8.0.7", "@types/next": "^8.0.7",
"@types/node": "^16.18.126", "@types/node": "^16.18.126",
"@types/pg": "^8.15.4", "@types/pg": "^8.15.4",
"@types/react": "^19.1.8", "@types/react": "^18.3.17",
"@types/react-dom": "^19.1.6", "@types/react-dom": "^18.3.5",
"@types/react-router-dom": "^5.3.3", "@types/react-router-dom": "^5.3.3",
"@vercel/analytics": "^1.5.0", "@vercel/analytics": "^1.5.0",
"@vercel/blob": "^1.1.1", "@vercel/blob": "^1.1.1",
@ -29,12 +29,12 @@
"jsonwebtoken": "^9.0.2", "jsonwebtoken": "^9.0.2",
"next": "^15.4.2", "next": "^15.4.2",
"pg": "^8.16.3", "pg": "^8.16.3",
"react": "^19.1.0", "react": "^18.3.1",
"react-dom": "^19.1.0", "react-dom": "^18.3.1",
"react-router-dom": "^7.7.0", "react-router-dom": "^6.28.0",
"react-scripts": "5.0.1", "react-scripts": "5.0.1",
"tesseract.js": "^6.0.1", "tesseract.js": "^6.0.1",
"typescript": "^4.9.5", "typescript": "^5.7.3",
"web-vitals": "^2.1.4" "web-vitals": "^2.1.4"
}, },
"scripts": { "scripts": {