From 96d1d2d0d653b1ae7b7f5192643b26579d482336 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 29 Jul 2026 01:15:38 -0400 Subject: [PATCH] fix login issue in production --- apps/homepage/next.config.ts | 6 ++ apps/homepage/src/lib/api.ts | 18 ++++-- apps/homepage/tests/unit/api.test.ts | 61 ++++++++++++++++++-- apps/homepage/tests/unit/next-config.test.ts | 18 ++++++ 4 files changed, 93 insertions(+), 10 deletions(-) create mode 100644 apps/homepage/tests/unit/next-config.test.ts diff --git a/apps/homepage/next.config.ts b/apps/homepage/next.config.ts index 32874a6..d584e93 100644 --- a/apps/homepage/next.config.ts +++ b/apps/homepage/next.config.ts @@ -50,6 +50,8 @@ const nextConfig: NextConfig = { }, async rewrites() { + const apiOrigin = + (process.env.API_INTERNAL_URL ?? process.env.API_URL ?? 'http://api:4000').replace(/\/api\/v1\/?$/, ''); const dashboardOrigin = process.env.DASHBOARD_INTERNAL_URL ?? 'http://dashboard:3001'; const adminOrigin = @@ -58,6 +60,10 @@ const nextConfig: NextConfig = { process.env.CARPLACE_INTERNAL_URL ?? 'http://carplace:3004'; return [ + { + source: '/api/:path*', + destination: `${apiOrigin}/api/:path*`, + }, { source: '/carplace', destination: `${carplaceOrigin}`, diff --git a/apps/homepage/src/lib/api.ts b/apps/homepage/src/lib/api.ts index d027147..657d426 100644 --- a/apps/homepage/src/lib/api.ts +++ b/apps/homepage/src/lib/api.ts @@ -3,10 +3,18 @@ export function normalizeApiBase(value: string): string { return /\/api\/v1$/.test(base) ? base : `${base}/api/v1` } -export const API_BASE = normalizeApiBase( - typeof window === 'undefined' - ? (process.env.API_INTERNAL_URL || 'http://localhost:4000/api/v1') - : (process.env.NEXT_PUBLIC_API_URL || '/api/v1'), -) +function resolveApiBase(): string { + if (typeof window === 'undefined') { + return normalizeApiBase(process.env.API_INTERNAL_URL || 'http://localhost:4000/api/v1') + } + + if (process.env.NEXT_PUBLIC_HOMEPAGE_DIRECT_API === 'true' && process.env.NEXT_PUBLIC_API_URL) { + return normalizeApiBase(process.env.NEXT_PUBLIC_API_URL) + } + + return '/api/v1' +} + +export const API_BASE = resolveApiBase() export const EMPLOYEE_PROFILE_KEY = 'employee_profile' diff --git a/apps/homepage/tests/unit/api.test.ts b/apps/homepage/tests/unit/api.test.ts index 5b385f2..52b5b66 100644 --- a/apps/homepage/tests/unit/api.test.ts +++ b/apps/homepage/tests/unit/api.test.ts @@ -1,17 +1,68 @@ -import { describe, expect, it } from 'vitest'; +import { afterEach, describe, expect, it, vi } from 'vitest'; -import { normalizeApiBase } from '@/lib/api'; +function installBrowser() { + Object.defineProperty(globalThis, 'window', { + configurable: true, + value: { + location: { + origin: 'https://rentaldrivego.ma', + hostname: 'rentaldrivego.ma', + }, + }, + }); +} + +afterEach(() => { + Reflect.deleteProperty(globalThis, 'window'); + delete process.env.API_INTERNAL_URL; + delete process.env.NEXT_PUBLIC_API_URL; + delete process.env.NEXT_PUBLIC_HOMEPAGE_DIRECT_API; + vi.resetModules(); +}); describe('homepage API base URL', () => { - it('keeps API URLs that already include the version prefix', () => { + it('keeps API URLs that already include the version prefix', async () => { + const { normalizeApiBase } = await import('@/lib/api'); + expect(normalizeApiBase('https://api.rentaldrivego.ma/api/v1')).toBe('https://api.rentaldrivego.ma/api/v1'); }); - it('adds the version prefix when production env only contains the API host', () => { + it('adds the version prefix when production env only contains the API host', async () => { + const { normalizeApiBase } = await import('@/lib/api'); + expect(normalizeApiBase('https://api.rentaldrivego.ma')).toBe('https://api.rentaldrivego.ma/api/v1'); }); - it('normalizes trailing slashes before appending the version prefix', () => { + it('normalizes trailing slashes before appending the version prefix', async () => { + const { normalizeApiBase } = await import('@/lib/api'); + expect(normalizeApiBase('https://api.rentaldrivego.ma/')).toBe('https://api.rentaldrivego.ma/api/v1'); }); + + it('uses the same-origin API proxy in browsers by default', async () => { + installBrowser(); + process.env.NEXT_PUBLIC_API_URL = 'https://api.rentaldrivego.ma/api/v1'; + + const { API_BASE } = await import('@/lib/api'); + + expect(API_BASE).toBe('/api/v1'); + }); + + it('allows direct browser API calls only when explicitly enabled', async () => { + installBrowser(); + process.env.NEXT_PUBLIC_API_URL = 'https://api.rentaldrivego.ma'; + process.env.NEXT_PUBLIC_HOMEPAGE_DIRECT_API = 'true'; + + const { API_BASE } = await import('@/lib/api'); + + expect(API_BASE).toBe('https://api.rentaldrivego.ma/api/v1'); + }); + + it('uses the internal API URL on the server', async () => { + process.env.API_INTERNAL_URL = 'http://api:4000/api/v1'; + + const { API_BASE } = await import('@/lib/api'); + + expect(API_BASE).toBe('http://api:4000/api/v1'); + }); }); diff --git a/apps/homepage/tests/unit/next-config.test.ts b/apps/homepage/tests/unit/next-config.test.ts new file mode 100644 index 0000000..2c0e95b --- /dev/null +++ b/apps/homepage/tests/unit/next-config.test.ts @@ -0,0 +1,18 @@ +import { describe, expect, it } from 'vitest'; + +import nextConfig from '../../next.config'; + +describe('homepage next config', () => { + it('proxies same-origin API requests to the API service before app rewrites', async () => { + const rewrites = await nextConfig.rewrites?.(); + + expect(rewrites).toEqual( + expect.arrayContaining([ + { + source: '/api/:path*', + destination: 'http://api:4000/api/:path*', + }, + ]), + ); + }); +});