chore: wire Carplace into dev and production stacks
Build & Deploy / Build & Push Docker Image (push) Successful in 2m55s
Test / Type Check (all packages) (push) Successful in 54s
Build & Deploy / Deploy to VPS (push) Successful in 4s
Test / API Unit Tests (push) Failing after 48s
Test / Homepage Unit Tests (push) Successful in 43s
Test / Storefront Unit Tests (push) Failing after 40s
Test / Admin Unit Tests (push) Successful in 40s
Test / Dashboard Unit Tests (push) Failing after 42s
Test / API Integration Tests (push) Successful in 1m0s

This commit is contained in:
root
2026-07-02 18:15:42 -04:00
parent ad5f5ebab7
commit 7ff2dbb139
214 changed files with 5258 additions and 5906 deletions
+3 -1
View File
@@ -6,7 +6,9 @@ function normalizeApiBase(value: string): string {
export const API_BASE = normalizeApiBase(
typeof window === 'undefined'
? (process.env.API_INTERNAL_URL || 'http://localhost:4000/api/v1')
: (process.env.NEXT_PUBLIC_API_URL || '/dashboard/api/v1'),
: (process.env.NEXT_PUBLIC_DASHBOARD_DIRECT_API === 'true' && process.env.NEXT_PUBLIC_API_URL
? process.env.NEXT_PUBLIC_API_URL
: '/dashboard/api/v1'),
)
export const EMPLOYEE_PROFILE_KEY = 'employee_profile'
+22 -44
View File
@@ -1,64 +1,42 @@
import { afterEach, describe, expect, it, vi } from 'vitest'
function installWindow(hostname: string, protocol = 'https:') {
Object.defineProperty(globalThis, 'window', {
configurable: true,
value: { location: { hostname, protocol } },
})
}
async function loadUrls(env: Record<string, string | undefined> = {}) {
vi.resetModules()
for (const key of ['NEXT_PUBLIC_STOREFRONT_URL', 'NEXT_PUBLIC_ADMIN_URL']) {
if (env[key] === undefined) {
delete process.env[key]
} else {
process.env[key] = env[key]
}
for (const key of ['NEXT_PUBLIC_WEBSITE_URL', 'NEXT_PUBLIC_CARPLACE_URL', 'NEXT_PUBLIC_ADMIN_URL']) {
delete process.env[key]
}
Object.assign(process.env, env)
return import('./urls')
}
afterEach(() => {
Reflect.deleteProperty(globalThis, 'window')
delete process.env.NEXT_PUBLIC_STOREFRONT_URL
delete process.env.NEXT_PUBLIC_ADMIN_URL
vi.resetModules()
for (const key of ['NEXT_PUBLIC_WEBSITE_URL', 'NEXT_PUBLIC_CARPLACE_URL', 'NEXT_PUBLIC_ADMIN_URL']) {
delete process.env[key]
}
})
describe('dashboard cross-app URLs', () => {
it('uses default storefront and admin bases on the server', async () => {
const { storefrontUrl, adminUrl } = await loadUrls()
expect(storefrontUrl).toBe('http://localhost:3000')
describe('application URLs', () => {
it('uses the website as the canonical public origin', async () => {
const { websiteUrl, carplaceUrl, adminUrl } = await loadUrls()
expect(websiteUrl).toBe('http://localhost:3000')
expect(carplaceUrl).toBe('http://localhost:3000/carplace')
expect(adminUrl).toBe('http://localhost:3000/admin')
})
it('strips trailing slashes from configured absolute URLs', async () => {
const { storefrontUrl, adminUrl } = await loadUrls({
NEXT_PUBLIC_STOREFRONT_URL: 'https://market.example.com/',
NEXT_PUBLIC_ADMIN_URL: 'https://ops.example.com/admin/',
it('accepts explicit Carplace and admin URLs', async () => {
const { websiteUrl, carplaceUrl, adminUrl } = await loadUrls({
NEXT_PUBLIC_WEBSITE_URL: 'https://rentaldrivego.ma/',
NEXT_PUBLIC_CARPLACE_URL: 'https://rentaldrivego.ma/carplace/',
NEXT_PUBLIC_ADMIN_URL: 'https://rentaldrivego.ma/admin/',
})
expect(storefrontUrl).toBe('https://market.example.com')
expect(adminUrl).toBe('https://ops.example.com/admin')
expect(websiteUrl).toBe('https://rentaldrivego.ma')
expect(carplaceUrl).toBe('https://rentaldrivego.ma/carplace')
expect(adminUrl).toBe('https://rentaldrivego.ma/admin')
})
it('rewrites local browser fallbacks onto the current production host', async () => {
installWindow('tenant.rentaldrivego.com', 'https:')
const { storefrontUrl, adminUrl } = await loadUrls()
expect(storefrontUrl).toBe('https://tenant.rentaldrivego.com')
expect(adminUrl).toBe('https://tenant.rentaldrivego.com/admin')
})
it('preserves non-URL values after normalizing their trailing slash', async () => {
const { storefrontUrl, adminUrl } = await loadUrls({
NEXT_PUBLIC_STOREFRONT_URL: '/storefront/',
NEXT_PUBLIC_ADMIN_URL: '/admin/',
})
expect(storefrontUrl).toBe('/storefront')
expect(adminUrl).toBe('/admin')
it('adds the Carplace path when only an origin is supplied', async () => {
const { carplaceUrl } = await loadUrls({ NEXT_PUBLIC_CARPLACE_URL: 'https://market.example.com' })
expect(carplaceUrl).toBe('https://market.example.com/carplace')
})
})
+14 -5
View File
@@ -2,17 +2,26 @@ import { resolveBrowserAppUrl } from '@/lib/appUrls'
function toAppBase(url: string): string {
try {
const u = new URL(url)
return (u.origin + u.pathname).replace(/\/$/, '')
const parsed = new URL(url)
return (parsed.origin + parsed.pathname).replace(/\/$/, '')
} catch {
return url.replace(/\/$/, '')
}
}
export const storefrontUrl = toAppBase(
resolveBrowserAppUrl(process.env.NEXT_PUBLIC_STOREFRONT_URL ?? 'http://localhost:3000'),
function withCarplacePath(url: string): string {
const base = toAppBase(url)
return /\/carplace$/i.test(base) ? base : `${base}/carplace`
}
export const websiteUrl = toAppBase(
resolveBrowserAppUrl(process.env.NEXT_PUBLIC_WEBSITE_URL ?? 'http://localhost:3000'),
)
export const carplaceUrl = withCarplacePath(
resolveBrowserAppUrl(process.env.NEXT_PUBLIC_CARPLACE_URL ?? websiteUrl),
)
export const adminUrl = toAppBase(
resolveBrowserAppUrl(process.env.NEXT_PUBLIC_ADMIN_URL ?? 'http://localhost:3000/admin'),
resolveBrowserAppUrl(process.env.NEXT_PUBLIC_ADMIN_URL ?? `${websiteUrl}/admin`),
)