88 lines
2.6 KiB
JavaScript
88 lines
2.6 KiB
JavaScript
/** @type {import('next').NextConfig} */
|
|
|
|
const securityHeaders = [
|
|
{ key: 'Strict-Transport-Security', value: 'max-age=31536000; includeSubDomains' },
|
|
{ key: 'X-Content-Type-Options', value: 'nosniff' },
|
|
{ key: 'X-Frame-Options', value: 'DENY' },
|
|
{ key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
|
|
{ key: 'Permissions-Policy', value: 'camera=(), microphone=(), geolocation=()' },
|
|
{
|
|
key: 'Content-Security-Policy',
|
|
value: [
|
|
"default-src 'self'",
|
|
"script-src 'self' 'unsafe-inline'",
|
|
"style-src 'self' 'unsafe-inline'",
|
|
"img-src 'self' data: blob: https:",
|
|
"font-src 'self' data:",
|
|
"connect-src 'self' https: wss:",
|
|
"frame-ancestors 'none'",
|
|
"base-uri 'self'",
|
|
"form-action 'self'",
|
|
"object-src 'none'",
|
|
].join('; '),
|
|
},
|
|
]
|
|
const apiOrigin = (process.env.API_INTERNAL_URL ?? process.env.API_URL ?? 'http://localhost:4000').replace(/\/api\/v1\/?$/, '')
|
|
const apiUrl = new URL(apiOrigin)
|
|
const ADMIN_BASE_PATH = '/admin'
|
|
|
|
function ensureAdminAssetPrefix(rawValue) {
|
|
if (!rawValue) return undefined
|
|
|
|
try {
|
|
const url = new URL(rawValue)
|
|
const pathname = url.pathname.replace(/\/$/, '')
|
|
if (!pathname.endsWith(ADMIN_BASE_PATH)) {
|
|
url.pathname = `${pathname}${ADMIN_BASE_PATH}`
|
|
}
|
|
return url.toString().replace(/\/$/, '')
|
|
} catch {
|
|
const trimmed = rawValue.replace(/\/$/, '')
|
|
return trimmed.endsWith(ADMIN_BASE_PATH) ? trimmed : `${trimmed}${ADMIN_BASE_PATH}`
|
|
}
|
|
}
|
|
|
|
// In Docker dev the admin app runs on port 3002 while the marketplace proxy
|
|
// serves it from port 3000. When ADMIN_ASSET_PREFIX is set, Next emits
|
|
// absolute chunk URLs so /admin pages load their JS/CSS and HMR directly from
|
|
// port 3002, bypassing the proxy (which can't upgrade WebSocket connections).
|
|
const assetPrefix = ensureAdminAssetPrefix(process.env.ADMIN_ASSET_PREFIX)
|
|
|
|
const nextConfig = {
|
|
basePath: ADMIN_BASE_PATH,
|
|
...(assetPrefix ? { assetPrefix } : {}),
|
|
images: {
|
|
remotePatterns: [
|
|
{
|
|
protocol: 'https',
|
|
hostname: 'res.cloudinary.com',
|
|
},
|
|
{
|
|
protocol: apiUrl.protocol.replace(':', ''),
|
|
hostname: apiUrl.hostname,
|
|
...(apiUrl.port ? { port: apiUrl.port } : {}),
|
|
pathname: '/storage/**',
|
|
},
|
|
],
|
|
},
|
|
transpilePackages: ['@rentaldrivego/types'],
|
|
async headers() {
|
|
return [
|
|
{
|
|
source: '/:path*',
|
|
headers: securityHeaders,
|
|
},
|
|
]
|
|
},
|
|
async rewrites() {
|
|
return [
|
|
{
|
|
source: '/api/:path*',
|
|
destination: `${apiOrigin}/api/:path*`,
|
|
},
|
|
]
|
|
},
|
|
}
|
|
|
|
module.exports = nextConfig
|