Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/openstatusHQ/openstatus. ๐ซ Status page with uptime monitoring & API monitoring as code ๐ซ openstatus.dev
bun drizzle-orm monitoring monitoring-as-code nextjs observability on-call open-source shadcn-ui status-page statuspage synthetic-monitoring tinybird turso uptime uptime-checker uptime-monitor
Something went wrong. Try again.
4.3 kB ยท 121 lines
TypeScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122import { db, eq } from "@openstatus/db";import { user, usersToWorkspaces, workspace } from "@openstatus/db/src/schema";import { getCurrency } from "@openstatus/db/src/schema/plan/utils";import { NextResponse } from "next/server";
import { auth } from "@/lib/auth";import { WORKSPACE_SLUG_COOKIE } from "@/lib/workspace-cookie";
export default auth(async (req) => { const url = req.nextUrl.clone(); const response = NextResponse.next();
const continent = req.headers.get("x-vercel-ip-continent") || "NA"; const country = req.headers.get("x-vercel-ip-country") || "US"; const currency = getCurrency({ continent, country });
// NOTE: used in the pricing table to display the currency based on user's location response.cookies.set("x-currency", currency);
if (url.pathname.includes("api/trpc")) { return response; }
if (!req.auth && url.pathname !== "/login") { if (process.env.NODE_ENV === "development") { console.log("User not authenticated, redirecting to login"); } const newURL = new URL("/login", req.url); // Only worth preserving a non-root destination; tryRedirectToCallback // rejects "/" anyway, so storing it would be a no-op redirect. const encodedSearchParams = url.pathname === "/" ? null : `${url.pathname}${url.search}`;
if (encodedSearchParams) { newURL.searchParams.append("redirectTo", encodedSearchParams); }
const response = NextResponse.redirect(newURL); // Store the redirect URL in a cookie for new users who go through onboarding. // Auth.js may not reliably pass callbackUrl to pages.newUser, so we use a // cookie as a fallback to ensure invite links work correctly. if (encodedSearchParams) { response.cookies.set("auth-redirect", encodedSearchParams, { path: "/", httpOnly: true, secure: process.env.NODE_ENV === "production", sameSite: "lax", maxAge: 60 * 10, // 10 minutes }); } return response; }
if (req.auth && url.pathname === "/login") { const redirectTo = url.searchParams.get("redirectTo"); if (redirectTo) { // Same-origin only: rebuild from path/search/hash so an absolute // redirectTo (e.g. https://evil.com) can't become an open redirect. const target = new URL(redirectTo, req.nextUrl.origin); if ( (target.protocol === "http:" || target.protocol === "https:") && !target.pathname.startsWith("//") ) { const safe = new URL( `${target.pathname}${target.search}${target.hash}`, req.nextUrl.origin, ); if (process.env.NODE_ENV === "development") { console.log("User authenticated, redirecting to", safe); } const res = NextResponse.redirect(safe); res.cookies.delete("auth-redirect"); return res; } } }
const hasWorkspaceSlug = req.cookies.has(WORKSPACE_SLUG_COOKIE);
if (req.auth?.user?.id && !hasWorkspaceSlug) { const [query] = await db .select() .from(usersToWorkspaces) .innerJoin(user, eq(user.id, usersToWorkspaces.userId)) .innerJoin(workspace, eq(workspace.id, usersToWorkspaces.workspaceId)) .where(eq(user.id, Number.parseInt(req.auth.user.id))) .all();
if (!query) { console.error(">> Should not happen, no workspace found for user"); }
response.cookies.set(WORKSPACE_SLUG_COOKIE, query.workspace.slug); }
if (!req.auth && hasWorkspaceSlug) { response.cookies.delete(WORKSPACE_SLUG_COOKIE); }
// auth-redirect is single-use and consumed by the /onboarding Server // Component. Middleware response-cookie writes are reflected into the same // request's cookies(), so deleting it on the /onboarding request itself // would race (and lose) that read. Clear it on the next authenticated // request instead: by then onboarding has redirected to the target, the // cookie's job is done, and the stale back-button re-redirect is killed. if ( req.auth && url.pathname !== "/onboarding" && req.cookies.has("auth-redirect") ) { response.cookies.delete("auth-redirect"); }
return response;});
export const config = { matcher: [ "/((?!api|assets|_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt).*)", ],};