From 2959285425d1f7ec141ecde03da235ec3b195662 Mon Sep 17 00:00:00 2001 From: root Date: Thu, 2 Jul 2026 22:01:16 -0400 Subject: [PATCH] fix redirect 2nd time --- apps/dashboard/src/lib/api.test.ts | 25 +++++++++++++++++++++++ apps/dashboard/src/lib/api.ts | 32 +++++++++++++++++++++++++----- 2 files changed, 52 insertions(+), 5 deletions(-) diff --git a/apps/dashboard/src/lib/api.test.ts b/apps/dashboard/src/lib/api.test.ts index c0917bc..cdc247f 100644 --- a/apps/dashboard/src/lib/api.test.ts +++ b/apps/dashboard/src/lib/api.test.ts @@ -4,6 +4,9 @@ function installBrowser(token?: string) { Object.defineProperty(globalThis, 'window', { configurable: true, value: { + location: { + hostname: 'localhost', + }, localStorage: { getItem: vi.fn(() => token ?? null), }, @@ -11,6 +14,10 @@ function installBrowser(token?: string) { }) } +function setBrowserHostname(hostname: string) { + ;(globalThis.window as any).location.hostname = hostname +} + afterEach(() => { vi.restoreAllMocks() Reflect.deleteProperty(globalThis, 'window') @@ -55,6 +62,24 @@ describe('dashboard apiFetch', () => { expect(fetchMock).toHaveBeenCalledWith('https://api.rentaldrivego.ma/api/v1/auth/account/start', expect.any(Object)) }) + it('uses the dashboard proxy on production hosts when the public API URL is cross-host', async () => { + installBrowser() + setBrowserHostname('rentaldrivego.ma') + process.env.NEXT_PUBLIC_API_URL = 'https://api.rentaldrivego.ma/api/v1' + const fetchMock = vi.fn(async () => ({ + ok: true, + json: async () => ({ data: { ok: true } }), + })) + Object.defineProperty(globalThis, 'fetch', { configurable: true, value: fetchMock }) + + const { apiFetch } = await import('./api') + await apiFetch('/auth/employee/login', { method: 'POST', body: JSON.stringify({}) }) + + expect(fetchMock).toHaveBeenCalledWith('/dashboard/api/v1/auth/employee/login', expect.objectContaining({ + credentials: 'include', + })) + }) + it.each([ ['https://api.rentaldrivego.ma', 'https://api.rentaldrivego.ma/api/v1/auth/account/start'], ['https://api.rentaldrivego.ma/', 'https://api.rentaldrivego.ma/api/v1/auth/account/start'], diff --git a/apps/dashboard/src/lib/api.ts b/apps/dashboard/src/lib/api.ts index dd8d974..baa1c79 100644 --- a/apps/dashboard/src/lib/api.ts +++ b/apps/dashboard/src/lib/api.ts @@ -4,12 +4,34 @@ export function normalizeApiBase(value: string): string { return /\/api\/v1$/.test(base) ? base : `${base}/api/v1` } -export function resolveApiBase(): string { - const value = typeof window === 'undefined' - ? (process.env.API_INTERNAL_URL || 'http://localhost:4000/api/v1') - : (process.env.NEXT_PUBLIC_API_URL || '/dashboard/api/v1') +const DASHBOARD_PROXY_API_BASE = '/dashboard/api/v1' - return normalizeApiBase(value) +function isLocalBrowserHost(hostname: string): boolean { + return hostname === 'localhost' || hostname === '127.0.0.1' || hostname === '::1' +} + +function shouldUseDashboardProxy(configuredApiBase?: string): boolean { + if (typeof window === 'undefined') return false + if (!configuredApiBase) return true + if (configuredApiBase.startsWith('/')) return false + + const currentHostname = window.location?.hostname + if (!currentHostname || isLocalBrowserHost(currentHostname)) return false + + try { + return new URL(configuredApiBase).hostname !== currentHostname + } catch { + return false + } +} + +export function resolveApiBase(): string { + if (typeof window === 'undefined') { + return normalizeApiBase(process.env.API_INTERNAL_URL || 'http://localhost:4000/api/v1') + } + + const configuredApiBase = process.env.NEXT_PUBLIC_API_URL + return normalizeApiBase(shouldUseDashboardProxy(configuredApiBase) ? DASHBOARD_PROXY_API_BASE : (configuredApiBase || DASHBOARD_PROXY_API_BASE)) } export const API_BASE = resolveApiBase()