diff options
Diffstat (limited to 'next.config.ts')
| -rw-r--r-- | next.config.ts | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/next.config.ts b/next.config.ts new file mode 100644 index 0000000..99dcca0 --- /dev/null +++ b/next.config.ts @@ -0,0 +1,202 @@ +import 'dotenv/config'; +import pkg from './package.json' with { type: 'json' }; + +const TRACKER_SCRIPT = '/script.js'; + +const basePath = process.env.BASE_PATH || ''; +const cloudMode = process.env.CLOUD_MODE || ''; +const cloudUrl = process.env.CLOUD_URL || ''; +const collectApiEndpoint = process.env.COLLECT_API_ENDPOINT || ''; +const corsMaxAge = process.env.CORS_MAX_AGE || ''; +const defaultLocale = process.env.DEFAULT_LOCALE || ''; +const forceSSL = process.env.FORCE_SSL || ''; +const frameAncestors = process.env.ALLOWED_FRAME_URLS || ''; +const trackerScriptName = process.env.TRACKER_SCRIPT_NAME || ''; +const trackerScriptURL = process.env.TRACKER_SCRIPT_URL || ''; + +const contentSecurityPolicy = ` + default-src 'self'; + img-src 'self' https: data:; + script-src 'self' 'unsafe-eval' 'unsafe-inline'; + style-src 'self' 'unsafe-inline'; + connect-src 'self' https:; + frame-ancestors 'self' ${frameAncestors}; +`; + +const defaultHeaders = [ + { + key: 'X-DNS-Prefetch-Control', + value: 'on', + }, + { + key: 'Content-Security-Policy', + value: contentSecurityPolicy.replace(/\s{2,}/g, ' ').trim(), + }, +]; + +if (forceSSL) { + defaultHeaders.push({ + key: 'Strict-Transport-Security', + value: 'max-age=63072000; includeSubDomains; preload', + }); +} + +const trackerHeaders = [ + { + key: 'Access-Control-Allow-Origin', + value: '*', + }, + { + key: 'Cache-Control', + value: 'public, max-age=86400, must-revalidate', + }, +]; + +const apiHeaders = [ + { + key: 'Access-Control-Allow-Origin', + value: '*', + }, + { + key: 'Access-Control-Allow-Headers', + value: '*', + }, + { + key: 'Access-Control-Allow-Methods', + value: 'GET, DELETE, POST, PUT', + }, + { + key: 'Access-Control-Max-Age', + value: corsMaxAge || '86400', + }, + { + key: 'Cache-Control', + value: 'no-cache', + }, +]; + +const headers = [ + { + source: '/api/:path*', + headers: apiHeaders, + }, + { + source: '/:path*', + headers: defaultHeaders, + }, + { + source: TRACKER_SCRIPT, + headers: trackerHeaders, + }, +]; + +const rewrites = []; + +if (trackerScriptURL) { + rewrites.push({ + source: TRACKER_SCRIPT, + destination: trackerScriptURL, + }); +} + +if (collectApiEndpoint) { + headers.push({ + source: collectApiEndpoint, + headers: apiHeaders, + }); + + rewrites.push({ + source: collectApiEndpoint, + destination: '/api/send', + }); +} + +const redirects = [ + { + source: '/settings', + destination: '/settings/preferences', + permanent: false, + }, + { + source: '/teams/:id', + destination: '/teams/:id/websites', + permanent: false, + }, + { + source: '/teams/:id/settings', + destination: '/teams/:id/settings/preferences', + permanent: false, + }, + { + source: '/admin', + destination: '/admin/users', + permanent: false, + }, +]; + +// Adding rewrites + headers for all alternative tracker script names. +if (trackerScriptName) { + const names = trackerScriptName?.split(',').map(name => name.trim()); + + if (names) { + names.forEach(name => { + const normalizedSource = `/${name.replace(/^\/+/, '')}`; + + rewrites.push({ + source: normalizedSource, + destination: TRACKER_SCRIPT, + }); + + headers.push({ + source: normalizedSource, + headers: trackerHeaders, + }); + }); + } +} + +if (cloudMode) { + rewrites.push({ + source: '/script.js', + destination: 'https://cloud.umami.is/script.js', + }); +} + +/** @type {import('next').NextConfig} */ +export default { + reactStrictMode: false, + env: { + basePath, + cloudMode, + cloudUrl, + currentVersion: pkg.version, + defaultLocale, + }, + basePath, + output: 'standalone', + eslint: { + ignoreDuringBuilds: true, + }, + typescript: { + ignoreBuildErrors: true, + }, + async headers() { + return headers; + }, + async rewrites() { + return [ + ...rewrites, + { + source: '/telemetry.js', + destination: '/api/scripts/telemetry', + }, + { + source: '/teams/:teamId/:path*', + destination: '/:path*', + }, + ]; + }, + async redirects() { + return [...redirects]; + }, +}; |