From 5a0f7aa58f88204ee29a9035239ba817b23d894a Mon Sep 17 00:00:00 2001 From: maaz519 Date: Sat, 20 Jun 2026 21:01:05 +0530 Subject: [PATCH] =?UTF-8?q?fix:=20route=20browser=E2=86=92API=20calls=20th?= =?UTF-8?q?rough=20BFF=20to=20avoid=20CORS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Create /api/onboard/request-otp and /api/auth/member/login BFF routes - Update OnboardingForm and member-login page to call BFF instead of API directly - Add vercel.json with monorepo build config and rootDirectory hint - Add .vercelignore to exclude .turbo, node_modules, .next (was uploading 2.3GB) - Add apps/web/.gitignore and update root .gitignore for tsbuildinfo files Co-Authored-By: Claude Sonnet 4.6 --- .gitignore | 1 + .vercelignore | 14 ++++++++++++++ apps/web/.gitignore | 1 + apps/web/app/api/auth/member/login/route.ts | 14 ++++++++++++++ apps/web/app/api/onboard/request-otp/route.ts | 14 ++++++++++++++ apps/web/app/member-login/page.tsx | 4 +--- apps/web/app/onboard/OnboardingForm.tsx | 4 +--- apps/web/vercel.json | 6 ++++++ 8 files changed, 52 insertions(+), 6 deletions(-) create mode 100644 .vercelignore create mode 100644 apps/web/.gitignore create mode 100644 apps/web/app/api/auth/member/login/route.ts create mode 100644 apps/web/app/api/onboard/request-otp/route.ts create mode 100644 apps/web/vercel.json diff --git a/.gitignore b/.gitignore index 9ab55a5..87fbb93 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ coverage .env.production sessions/ *.tsbuildinfo +.vercel diff --git a/.vercelignore b/.vercelignore new file mode 100644 index 0000000..90f3dbc --- /dev/null +++ b/.vercelignore @@ -0,0 +1,14 @@ +node_modules +.turbo +.next +dist +build +coverage +*.tsbuildinfo +.git +apps/worker/sessions +apps/api/sessions +sessions +.env +.env.* +!.env.example diff --git a/apps/web/.gitignore b/apps/web/.gitignore new file mode 100644 index 0000000..e985853 --- /dev/null +++ b/apps/web/.gitignore @@ -0,0 +1 @@ +.vercel diff --git a/apps/web/app/api/auth/member/login/route.ts b/apps/web/app/api/auth/member/login/route.ts new file mode 100644 index 0000000..b277144 --- /dev/null +++ b/apps/web/app/api/auth/member/login/route.ts @@ -0,0 +1,14 @@ +import { getApiBaseUrl, jsonResponse } from '../../../../_lib/api'; + +export const dynamic = 'force-dynamic'; + +export async function POST(req: Request): Promise { + const body = await req.json().catch(() => ({})); + const upstream = await fetch(`${getApiBaseUrl()}/public/auth/member-login`, { + method: 'POST', + headers: { 'Content-Type': 'application/json', Accept: 'application/json' }, + body: JSON.stringify(body), + cache: 'no-store', + }); + return jsonResponse(await upstream.json().catch(() => ({})), upstream.status); +} diff --git a/apps/web/app/api/onboard/request-otp/route.ts b/apps/web/app/api/onboard/request-otp/route.ts new file mode 100644 index 0000000..526050d --- /dev/null +++ b/apps/web/app/api/onboard/request-otp/route.ts @@ -0,0 +1,14 @@ +import { getApiBaseUrl, jsonResponse } from '../../../_lib/api'; + +export const dynamic = 'force-dynamic'; + +export async function POST(req: Request): Promise { + const body = await req.json().catch(() => ({})); + const upstream = await fetch(`${getApiBaseUrl()}/public/auth/request-otp`, { + method: 'POST', + headers: { 'Content-Type': 'application/json', Accept: 'application/json' }, + body: JSON.stringify(body), + cache: 'no-store', + }); + return jsonResponse(await upstream.json().catch(() => ({})), upstream.status); +} diff --git a/apps/web/app/member-login/page.tsx b/apps/web/app/member-login/page.tsx index dcb7eb3..7656d67 100644 --- a/apps/web/app/member-login/page.tsx +++ b/apps/web/app/member-login/page.tsx @@ -11,8 +11,6 @@ import { Input } from '../_components/ui/input'; import { Button } from '../_components/ui/button'; import Link from 'next/link'; -const API_BASE = process.env['NEXT_PUBLIC_API_URL'] ?? 'http://localhost:3001'; - const phoneSchema = z.object({ phone: z.string().min(8, 'Enter your WhatsApp number') }); const otpSchema = z.object({ code: z.string().length(6, 'Enter the 6-digit code') }); type PhoneValues = z.infer; @@ -28,7 +26,7 @@ export default function MemberLoginPage() { const otpForm = useForm({ resolver: zodResolver(otpSchema), defaultValues: { code: '' } }); async function onPhone(values: PhoneValues) { - const res = await fetch(`${API_BASE}/public/auth/member-login`, { + const res = await fetch('/api/auth/member/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ phone: values.phone }), diff --git a/apps/web/app/onboard/OnboardingForm.tsx b/apps/web/app/onboard/OnboardingForm.tsx index 43de356..9fddd3a 100644 --- a/apps/web/app/onboard/OnboardingForm.tsx +++ b/apps/web/app/onboard/OnboardingForm.tsx @@ -43,8 +43,6 @@ const SCOPE_META: ScopeMeta[] = [ }, ]; -const API_BASE = process.env['NEXT_PUBLIC_API_URL'] ?? 'http://localhost:3001'; - export function OnboardingForm({ token, groupName, tenantName, defaultScopes, defaultRetentionDays }: Props) { const [step, setStep] = useState('welcome'); const [phone, setPhone] = useState(''); @@ -62,7 +60,7 @@ export function OnboardingForm({ token, groupName, tenantName, defaultScopes, de setError(null); setBusy(true); try { - const res = await fetch(`${API_BASE}/public/auth/request-otp`, { + const res = await fetch('/api/onboard/request-otp', { method: 'POST', headers: { 'Content-Type': 'application/json', Accept: 'application/json' }, body: JSON.stringify({ onboardingToken: token, phone }), diff --git a/apps/web/vercel.json b/apps/web/vercel.json new file mode 100644 index 0000000..5aab7f5 --- /dev/null +++ b/apps/web/vercel.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://openapi.vercel.sh/vercel.json", + "framework": "nextjs", + "buildCommand": "cd ../.. && pnpm turbo build --filter=@tower/web", + "installCommand": "cd ../.. && pnpm install --frozen-lockfile" +}