Openstatus
www.openstatus.dev
1const { withContentCollections } = require("@content-collections/next");
2const { withSentryConfig } = require("@sentry/nextjs");
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 = {
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 serverExternalPackages: ["@google-cloud/tasks"],
23 expireTime: 180, // 3 minutes
24 logging: {
25 fetches: {
26 fullUrl: true,
27 },
28 },
29 images: {
30 remotePatterns: [
31 {
32 protocol: "https",
33 hostname: "**.public.blob.vercel-storage.com",
34 },
35 {
36 protocol: "https",
37 hostname: "screenshot.openstat.us",
38 },
39 {
40 protocol: "https",
41 hostname: "www.openstatus.dev",
42 },
43 ],
44 },
45 async headers() {
46 return [{ source: "/(.*)", headers: securityHeaders }];
47 },
48 async redirects() {
49 return [
50 {
51 source: "/features/monitoring",
52 destination: "/uptime-monitoring",
53 permanent: true,
54 },
55 {
56 source: "/features/status-page",
57 destination: "/status-page",
58 permanent: true,
59 },
60 {
61 source: "/app/:path*",
62 destination: "https://app.openstatus.dev/",
63 permanent: true,
64 },
65 ];
66 },
67 async rewrites() {
68 return {
69 beforeFiles: [
70 {
71 source: "/status-page/themes/:path*",
72 destination: "https://www.stpg.dev/:path*",
73 },
74 {
75 source: "/:path*",
76 has: [
77 {
78 type: "host",
79 value: "themes.openstatus.dev",
80 },
81 ],
82 destination: "https://www.stpg.dev/:path*",
83 },
84 // New design: proxy app routes to external host with slug prefix
85 {
86 source: "/:path*",
87 has: [
88 { type: "cookie", key: "sp_mode", value: "new" },
89 {
90 type: "host",
91 value: "(?<slug>[^.]+)\\.(openstatus\\.dev|localhost)",
92 },
93 ],
94 destination: "https://:slug.stpg.dev/:path*",
95 },
96 // Handle custom domains (e.g., status.mxkaske.dev)
97 {
98 source:
99 "/:path((?!api|assets|_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt).*)",
100 has: [
101 { type: "cookie", key: "sp_mode", value: "new" },
102 {
103 type: "host",
104 value: "^(?!.*\\.openstatus\\.dev$)(?!openstatus\\.dev$)$",
105 },
106 ],
107 destination: "https://www.stpg.dev/:path*",
108 },
109 {
110 source:
111 "/:path((?!api|assets|_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt|events|monitors|protected|verify).*)",
112 has: [
113 { type: "cookie", key: "sp_mode", value: "new" },
114 {
115 type: "host",
116 value: "^(?<domain>.+)$",
117 },
118 ],
119 destination: "https://www.stpg.dev/:domain*",
120 },
121 {
122 source:
123 "/:path((?!api|assets|_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt).*)",
124 has: [
125 { type: "cookie", key: "sp_mode", value: "new" },
126 {
127 type: "host",
128 value: "^(?<domain>.+)$",
129 },
130 ],
131 destination: "https://www.stpg.dev/:domain/:path*",
132 },
133 // Handle API routes for custom domains
134 {
135 source: "/api/:path*",
136 has: [
137 { type: "cookie", key: "sp_mode", value: "new" },
138 {
139 type: "host",
140 value:
141 "^(?!.*\\.openstatus\\.dev$)(?!openstatus\\.dev$)(?<domain>.+)$",
142 },
143 ],
144 destination: "https://www.stpg.dev/api/:path*",
145 },
146 // Handle static assets for custom domains
147 {
148 source: "/_next/:path*",
149 has: [
150 { type: "cookie", key: "sp_mode", value: "new" },
151 {
152 type: "host",
153 value:
154 "^(?!.*\\.openstatus\\.dev$)(?!openstatus\\.dev$)(?<domain>.+)$",
155 },
156 ],
157 destination: "https://www.stpg.dev/_next/:path*",
158 },
159 ],
160 };
161 },
162};
163
164module.exports = withSentryConfig(
165 async () => await withContentCollections(nextConfig),
166 {
167 // For all available options, see:
168 // https://github.com/getsentry/sentry-webpack-plugin#options
169
170 // Only print logs for uploading source maps in CI
171 // Set to `true` to suppress logs
172 silent: !process.env.CI,
173
174 org: "openstatus",
175 project: "openstatus",
176 },
177 {
178 // For all available options, see:
179 // https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/
180
181 // Pass the auth token
182 authToken: process.env.SENTRY_AUTH_TOKEN,
183
184 // Upload a larger set of source maps for prettier stack traces (increases build time)
185 widenClientFileUpload: true,
186
187 // Transpiles SDK to be compatible with IE11 (increases bundle size)
188 transpileClientSDK: false,
189
190 // Automatically tree-shake Sentry logger statements to reduce bundle size
191 disableLogger: true,
192 },
193);