Openstatus www.openstatus.dev
at main 244 lines 7.2 kB view raw
1import { withSentryConfig } from "@sentry/nextjs"; 2import type { NextConfig } from "next"; 3 4// REMINDER: avoid Clickjacking attacks by setting the X-Frame-Options header 5const securityHeaders = [ 6 { 7 key: "X-Frame-Options", 8 value: "SAMEORIGIN", 9 }, 10]; 11 12/** @type {import('next').NextConfig} */ 13const nextConfig: NextConfig = { 14 reactStrictMode: true, 15 transpilePackages: ["@openstatus/ui", "@openstatus/api"], 16 outputFileTracingIncludes: { 17 "/": [ 18 "./node_modules/.pnpm/@google-cloud/tasks/build/esm/src/**/*.json", 19 "./node_modules/@google-cloud/tasks/build/esm/src/**/*.js", 20 ], 21 }, 22 experimental: { 23 turbopackScopeHoisting: false, 24 // serverMinification:false, 25 }, 26 serverExternalPackages: ["@google-cloud/tasks"], 27 expireTime: 180, // 3 minutes 28 logging: { 29 fetches: { 30 fullUrl: true, 31 }, 32 }, 33 images: { 34 remotePatterns: [ 35 { 36 protocol: "https", 37 hostname: "**.public.blob.vercel-storage.com", 38 }, 39 { 40 protocol: "https", 41 hostname: "screenshot.openstat.us", 42 }, 43 { 44 protocol: "https", 45 hostname: "www.openstatus.dev", 46 }, 47 ], 48 }, 49 async headers() { 50 return [{ source: "/(.*)", headers: securityHeaders }]; 51 }, 52 async redirects() { 53 return [ 54 { 55 source: "/legal/terms", 56 destination: "/terms", 57 permanent: true, 58 }, 59 { 60 source: "/legal/privacy", 61 destination: "/privacy", 62 permanent: true, 63 }, 64 { 65 source: "/features/monitoring", 66 destination: "/uptime-monitoring", 67 permanent: true, 68 }, 69 { 70 source: "/features/status-page", 71 destination: "/status-page", 72 permanent: true, 73 }, 74 { 75 source: "/app/:path*", 76 destination: "https://app.openstatus.dev/", 77 permanent: true, 78 }, 79 ]; 80 }, 81 async rewrites() { 82 return { 83 beforeFiles: [ 84 { 85 source: "/status-page/themes/:path*", 86 destination: "https://www.stpg.dev/:path*", 87 }, 88 { 89 source: "/:path*", 90 has: [ 91 { 92 type: "host", 93 value: "themes.openstatus.dev", 94 }, 95 ], 96 destination: "https://www.stpg.dev/:path*", 97 }, 98 // New design: proxy app routes to external host with slug prefix 99 { 100 source: "/:path*", 101 has: [ 102 { type: "cookie", key: "sp_mode", value: "new" }, 103 { 104 type: "host", 105 value: "(?<slug>[^.]+)\\.(openstatus\\.dev|localhost)", 106 }, 107 ], 108 destination: "https://:slug.stpg.dev/:path*", 109 }, 110 // Handle custom domains (e.g., status.mxkaske.dev) 111 { 112 source: 113 "/:path((?!api|assets|_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt).*)", 114 has: [ 115 { type: "cookie", key: "sp_mode", value: "new" }, 116 { 117 type: "host", 118 value: "^(?!.*\\.openstatus\\.dev$)(?!openstatus\\.dev$)$", 119 }, 120 ], 121 destination: "https://www.stpg.dev/:path*", 122 }, 123 // enfore routes to avoid infinite redirects - https://github.com/vercel/vercel/issues/6126#issuecomment-823523122 124 // testing with https://validator.w3.org/feed/check.cgi 125 { 126 source: "/feed/rss", 127 has: [ 128 { type: "cookie", key: "sp_mode", value: "new" }, 129 { 130 type: "host", 131 value: "^(?!.*\\.openstatus\\.dev$)(?!openstatus\\.dev$)$", 132 }, 133 ], 134 destination: "https://www.stpg.dev/:domain/feed/rss", 135 }, 136 { 137 source: "/feed/atom", 138 has: [ 139 { type: "cookie", key: "sp_mode", value: "new" }, 140 { 141 type: "host", 142 value: "^(?!.*\\.openstatus\\.dev$)(?!openstatus\\.dev$)$", 143 }, 144 ], 145 destination: "https://www.stpg.dev/:domain/feed/atom", 146 }, 147 { 148 source: "/feed/rss", 149 has: [ 150 { type: "cookie", key: "sp_mode", value: "new" }, 151 { 152 type: "host", 153 value: "^(?<domain>.+)$", 154 }, 155 ], 156 destination: "https://www.stpg.dev/:domain/feed/rss", 157 }, 158 { 159 source: "/feed/atom", 160 has: [ 161 { type: "cookie", key: "sp_mode", value: "new" }, 162 { 163 type: "host", 164 value: "^(?<domain>.+)$", 165 }, 166 ], 167 destination: "https://www.stpg.dev/:domain/feed/atom", 168 }, 169 { 170 source: 171 "/:path((?!api|assets|_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt|badge|feed|events|monitors|protected|verify).*)", 172 has: [ 173 { type: "cookie", key: "sp_mode", value: "new" }, 174 { 175 type: "host", 176 value: "^(?<domain>.+)$", 177 }, 178 ], 179 destination: "https://www.stpg.dev/:domain*", 180 }, 181 { 182 source: 183 "/:path((?!api|assets|_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt).*)", 184 has: [ 185 { type: "cookie", key: "sp_mode", value: "new" }, 186 { 187 type: "host", 188 value: "^(?<domain>.+)$", 189 }, 190 ], 191 destination: "https://www.stpg.dev/:domain/:path*", 192 }, 193 // Handle API routes for custom domains 194 { 195 source: "/api/:path*", 196 has: [ 197 { type: "cookie", key: "sp_mode", value: "new" }, 198 { 199 type: "host", 200 value: 201 "^(?!.*\\.openstatus\\.dev$)(?!openstatus\\.dev$)(?<domain>.+)$", 202 }, 203 ], 204 destination: "https://www.stpg.dev/api/:path*", 205 }, 206 // Handle static assets for custom domains 207 { 208 source: "/_next/:path*", 209 has: [ 210 { type: "cookie", key: "sp_mode", value: "new" }, 211 { 212 type: "host", 213 value: 214 "^(?!.*\\.openstatus\\.dev$)(?!openstatus\\.dev$)(?<domain>.+)$", 215 }, 216 ], 217 destination: "https://www.stpg.dev/_next/:path*", 218 }, 219 ], 220 }; 221 }, 222}; 223 224// For detailed options, refer to the official documentation: 225// - Webpack plugin options: https://github.com/getsentry/sentry-webpack-plugin#options 226// - Next.js Sentry setup guide: https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/ 227const sentryConfig = { 228 // Prevent log output unless running in a CI environment (helps reduce noise in logs) 229 silent: !process.env.CI, 230 org: "openstatus", 231 project: "openstatus", 232 authToken: process.env.SENTRY_AUTH_TOKEN, 233 234 // Upload a larger set of source maps for improved stack trace accuracy (increases build time) 235 widenClientFileUpload: true, 236 237 // If set to true, transpiles Sentry SDK to be compatible with IE11 (increases bundle size) 238 transpileClientSDK: false, 239 240 // Tree-shake Sentry logger statements to reduce bundle size 241 disableLogger: true, 242}; 243 244export default withSentryConfig(nextConfig, sentryConfig);