Files
carmanagement/apps/dashboard/src/middleware.ts
T
root 8aab968e09
Build & Deploy / Build & Push Docker Image (push) Successful in 1m2s
Test / Type Check (all packages) (push) Failing after 28s
Test / API Unit Tests (push) Has been skipped
Test / Homepage Unit Tests (push) Has been skipped
Test / Storefront Unit Tests (push) Has been skipped
Test / Admin Unit Tests (push) Has been skipped
Test / Dashboard Unit Tests (push) Has been skipped
Test / API Integration Tests (push) Has been skipped
Build & Deploy / Deploy to VPS (push) Successful in 3s
refactor: rename marketplace to storefront across the entire monorepo
Comprehensive rename of all marketplace references to storefront:
- API module: apps/api/src/modules/marketplace/ → storefront/
- Components: MarketplaceHeader → StorefrontHeader, MarketplaceShell →
  StorefrontShell, MarketplaceFooter → StorefrontFooter
- Types: marketplace-homepage.ts → storefront-homepage.ts
- Test files: employee-marketplace-* → employee-storefront-*
- All source code identifiers, imports, route paths, and strings
- Documentation (docs/), CI config (.gitlab-ci.yml), scripts
- Dashboard, admin, storefront workspace references
- Prisma field names preserved (isListedOnMarketplace, marketplaceRating,
  marketplaceFunnelEvent) as they map to database schema

Validation:
- API type-check: 0 errors
- Storefront type-check: 0 errors
- Dashboard type-check: 0 errors
- Full monorepo type-check: only pre-existing admin TS18046
2026-06-28 01:14:46 -04:00

104 lines
3.7 KiB
TypeScript

import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
const STOREFRONT_URL = process.env.NEXT_PUBLIC_STOREFRONT_URL ?? 'http://localhost:3000'
const DASHBOARD_BASE_PATH = '/dashboard'
function toDashboardAppPath(pathname: string): string {
let normalized = pathname || '/'
while (normalized === DASHBOARD_BASE_PATH || normalized.startsWith(`${DASHBOARD_BASE_PATH}/`)) {
normalized = normalized.slice(DASHBOARD_BASE_PATH.length) || '/'
}
return normalized
}
function toPublicDashboardPath(pathname: string): string {
const appPath = toDashboardAppPath(pathname)
return appPath === '/' ? DASHBOARD_BASE_PATH : `${DASHBOARD_BASE_PATH}${appPath}`
}
function deduplicatePublicDashboardPath(pathname: string): string | null {
if (!pathname.startsWith(`${DASHBOARD_BASE_PATH}${DASHBOARD_BASE_PATH}`)) return null
let normalized = pathname
while (normalized.startsWith(`${DASHBOARD_BASE_PATH}${DASHBOARD_BASE_PATH}`)) {
normalized = normalized.slice(DASHBOARD_BASE_PATH.length)
}
return normalized || DASHBOARD_BASE_PATH
}
function resolveProxyUrl(req: NextRequest, pathname: string): URL {
const forwardedHost = req.headers.get('x-forwarded-host')
const forwardedProto = req.headers.get('x-forwarded-proto')
const storefrontOrigin = new URL(STOREFRONT_URL)
const url = new URL(pathname, req.nextUrl.origin)
if (forwardedHost && !isInternalHost(forwardedHost)) {
url.host = forwardedHost
url.protocol = (forwardedProto ?? 'http') + ':'
} else if (!isInternalHost(req.nextUrl.host)) {
url.host = req.nextUrl.host
url.protocol = req.nextUrl.protocol
} else {
url.host = storefrontOrigin.host
url.protocol = storefrontOrigin.protocol
}
return url
}
function isInternalHost(host: string | null): boolean {
if (!host) return false
const hostname = host.split(':')[0]?.toLowerCase()
return ['host.docker.internal', 'dashboard', 'admin', 'api', 'homepage', 'storefront'].includes(hostname)
}
function isProtectedRoute(req: NextRequest) {
const pathname = toDashboardAppPath(req.nextUrl.pathname)
if (['/sign-in', '/sign-up', '/forgot-password', '/reset-password', '/onboarding', '/verify-email'].some((p) => pathname === p || pathname.startsWith(p + '/'))) return false
return pathname === '/' || (pathname.startsWith('/') && !pathname.startsWith('/_next'))
}
function localJwtMiddleware(req: NextRequest): NextResponse {
const token = req.cookies.get('employee_session')?.value
const pathname = toDashboardAppPath(req.nextUrl.pathname)
// Redirect signed-in users from sign-in to dashboard (through storefront proxy)
if (token && pathname === '/sign-in') {
const dashboardUrl = resolveProxyUrl(req, DASHBOARD_BASE_PATH)
return NextResponse.redirect(dashboardUrl)
}
if (!isProtectedRoute(req)) return NextResponse.next()
if (!token) {
const signInUrl = resolveProxyUrl(req, toPublicDashboardPath('/sign-in'))
signInUrl.searchParams.set('redirect', req.nextUrl.pathname)
return NextResponse.redirect(signInUrl)
}
return NextResponse.next()
}
export default function middleware(req: NextRequest) {
if (req.headers.has('x-middleware-subrequest')) {
return new NextResponse('Unsupported internal request header', { status: 400 })
}
const dedupedPath = deduplicatePublicDashboardPath(req.nextUrl.pathname)
if (dedupedPath) {
const redirectUrl = req.nextUrl.clone()
redirectUrl.pathname = dedupedPath
return NextResponse.redirect(redirectUrl)
}
return localJwtMiddleware(req)
}
export const config = {
matcher: [
'/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)',
'/(api|trpc)(.*)',
],
}