Skip to content

Commit 651778a

Browse files
added: fly.toml
1 parent cd94a9f commit 651778a

5 files changed

Lines changed: 54 additions & 34 deletions

File tree

apps/web/services/api.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
export const BASE_URL = "https://pixel-ui.fly.dev";
2-
3-
// export const BASE_URL = "http://localhost:4000";
1+
// Backend base URL. Configure via NEXT_PUBLIC_API_BASE_URL in envs.
2+
export const BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL || "http://localhost:4000";
43

54
export const API = {
65
auth: {

packages/server/fly.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ app = "pixel-ui"
22
primary_region = "bom"
33

44
[build]
5-
image = "talhadevelopes/pixel-ui-server:latest"
5+
dockerfile = "Dockerfile"
66

77
[env]
88
NODE_ENV = "production"

packages/server/src/controllers/authController.ts

Lines changed: 7 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { GoogleCallbackInput, LoginInput, RegisterInput, googleCallbackSchema, verifyOtpSchema, resendOtpSchema } from "../validation/authValidation";
1+
import { GoogleCallbackInput, LoginInput, RegisterInput, googleCallbackSchema, verifyOtpSchema, resendOtpSchema, loginSchema, registerSchema } from "../validation/authValidation";
2+
23
import { AuthRequest } from "../middleware/authMiddleware";
34
import { Response, NextFunction } from "express";
45
import z from "zod";
@@ -13,7 +14,7 @@ import { prisma } from "../utils/prisma";
1314
export class AuthController {
1415
static async register(req: AuthRequest, res: Response, next: NextFunction) {
1516
try {
16-
const { name, email, password } = req.body as RegisterInput;
17+
const { name, email, password } = registerSchema.parse(req.body);
1718
const emailLower = email.trim().toLowerCase();
1819

1920
const existingUser = await prisma.user.findUnique({ where: { email: emailLower } });
@@ -54,32 +55,16 @@ export class AuthController {
5455

5556
static async login(req: AuthRequest, res: Response, next: NextFunction) {
5657
try {
57-
const { email, password } = req.body as LoginInput;
58+
const { email, password } = loginSchema.parse(req.body);
5859
const emailLower = email.trim().toLowerCase();
5960

6061
console.log(`[Auth] Login attempt for ${emailLower}`);
6162

62-
let user = await prisma.user.findUnique({ where: { email: emailLower } });
63+
const user = await prisma.user.findUnique({ where: { email: emailLower } });
6364

6465
if (!user) {
65-
console.log(`[Auth] No existing user for ${emailLower}. Creating new user.`);
66-
const hashed = await hashPassword(password);
67-
user = await prisma.user.create({
68-
data: {
69-
id: crypto.randomUUID(),
70-
name: emailLower.split("@")[0],
71-
email: emailLower,
72-
password: hashed,
73-
credits: 5,
74-
tier: "free",
75-
dailyCreditsLimit: 5,
76-
lastCreditReset: new Date(),
77-
subscriptionStatus: "inactive",
78-
},
79-
});
80-
console.log(`[Auth] User created with id ${user.id}`);
81-
} else {
82-
console.log(`[Auth] Existing user ${user.id} found for ${emailLower}`);
66+
console.warn(`[Auth] Login failed - user not found for ${emailLower}`);
67+
return sendError(res, "Invalid credentials", 401);
8368
}
8469

8570
const isPasswordValid = await verifyPassword(password, user.password);

packages/server/src/index.ts

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,24 @@ import { prisma } from './utils/prisma'
2121
const app = express();
2222

2323
const corsOrigin = process.env.CLIENT_URL || "http://localhost:3000";
24-
console.log('🔥 CORS ORIGIN BEING USED:', corsOrigin);
24+
const allowedOrigins = (process.env.ALLOWED_ORIGINS || corsOrigin)
25+
.split(',')
26+
.map((s) => s.trim())
27+
.filter(Boolean);
28+
console.log('🔥 CORS ALLOWED ORIGINS:', allowedOrigins);
2529

2630
// Middlewares
2731
app.use(express.json());
2832
app.use(hpp());
2933
app.use(helmet());
3034

3135
app.use(cors({
32-
origin: corsOrigin,
36+
origin: function (origin, callback) {
37+
if (!origin) return callback(null, true);
38+
if (allowedOrigins.includes(origin)) return callback(null, true);
39+
console.warn('❌ CORS blocked origin:', origin);
40+
return callback(new Error('Not allowed by CORS'));
41+
},
3342
credentials: true,
3443
}));
3544

@@ -50,12 +59,32 @@ app.use((req, res, next) => {
5059
app.use('/health', (req, res) => {
5160
res.json({ status: "OK", message: "Server is working" });
5261
});
62+
app.get('/health', async (req, res) => {
63+
try {
64+
// Simple DB connectivity check
65+
// @ts-ignore
66+
await prisma.$queryRaw`SELECT 1`;
67+
res.json({ status: 'ok', db: true });
68+
} catch (e: any) {
69+
console.error('❌ Healthz DB check failed:', e);
70+
res.status(500).json({ status: 'degraded', db: false, error: e?.message || 'db_error' });
71+
}
72+
});
5373
app.use('/api/auth', authRoutes)
5474
app.use('/api/projects', projectRoutes)
5575
app.use('/api/frames', frameRoutes)
5676
app.use('/api/chat', chatRoute)
5777
app.use('/api/subscriptions', subscriptionRoutes)
5878

79+
// Global error handler
80+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
81+
app.use((err: any, req: express.Request, res: express.Response, next: express.NextFunction) => {
82+
const status = err?.status || 500;
83+
const message = err?.message || 'Internal Server Error';
84+
console.error('🔥 Unhandled error:', { status, message, stack: err?.stack });
85+
res.status(status).json({ success: false, message });
86+
});
87+
5988
const PORT = process.env.PORT || 4000;
6089
//@ts-ignore
6190
app.listen(PORT, '0.0.0.0', async () => {

packages/server/src/utils/jwt.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,30 @@ import bcrypt from 'bcryptjs';
33
import dotenv from 'dotenv';
44
dotenv.config();
55

6-
const JWT_REFRESH_SECRET = (process.env.JWT_REFRESH_SECRET as string) || 'dev_refresh_secret';
7-
const JWT_ACCESS_SECRET = (process.env.JWT_ACCESS_SECRET as string) || 'dev_access_secret';
6+
const isProd = process.env.NODE_ENV === 'production';
7+
const JWT_REFRESH_SECRET = process.env.JWT_REFRESH_SECRET as string | undefined;
8+
const JWT_ACCESS_SECRET = process.env.JWT_ACCESS_SECRET as string | undefined;
9+
10+
if (isProd) {
11+
if (!JWT_REFRESH_SECRET || !JWT_ACCESS_SECRET) {
12+
throw new Error('JWT secrets are not configured in production');
13+
}
14+
}
815

916
export function generateAccessToken(payload: any): string {
10-
return jwt.sign(payload, JWT_ACCESS_SECRET, { expiresIn: "60m" });
17+
return jwt.sign(payload, JWT_ACCESS_SECRET || 'dev_access_secret', { expiresIn: "60m" });
1118
}
1219

1320
export function generateRefreshToken(payload: any): string {
14-
return jwt.sign(payload, JWT_REFRESH_SECRET, { expiresIn: "7d" });
21+
return jwt.sign(payload, JWT_REFRESH_SECRET || 'dev_refresh_secret', { expiresIn: "7d" });
1522
}
1623

1724
export function verifyAccessToken(token: string): any {
18-
return jwt.verify(token, JWT_ACCESS_SECRET);
25+
return jwt.verify(token, JWT_ACCESS_SECRET || 'dev_access_secret');
1926
}
2027

2128
export function verifyRefreshToken(token: string): any {
22-
return jwt.verify(token, JWT_REFRESH_SECRET);
29+
return jwt.verify(token, JWT_REFRESH_SECRET || 'dev_refresh_secret');
2330
}
2431

2532
export async function hashPassword(password: string): Promise<string> {

0 commit comments

Comments
 (0)