added splash page

This commit is contained in:
makearmy 2025-09-30 22:38:25 -04:00
parent 41614a96cd
commit 6abe450f1d
2 changed files with 66 additions and 141 deletions

View file

@ -5,7 +5,11 @@ import { NextResponse, NextRequest } from "next/server";
* Public pages that should remain reachable without being signed in.
* Everything else is considered protected (including most /api/*).
*/
const PUBLIC_PAGES = new Set<string>(["/auth/sign-in", "/auth/sign-up"]);
const PUBLIC_PAGES = new Set<string>([
"/", // ← splash page is public
"/auth/sign-in",
"/auth/sign-up",
]);
/**
* API paths that are explicitly allowed without auth.
@ -17,8 +21,7 @@ import { NextResponse, NextRequest } from "next/server";
];
/** Directus base (used to remotely validate the token after restarts). */
const DIRECTUS =
(process.env.NEXT_PUBLIC_API_BASE_URL || process.env.DIRECTUS_URL || "").replace(/\/$/, "");
const DIRECTUS = (process.env.NEXT_PUBLIC_API_BASE_URL || process.env.DIRECTUS_URL || "").replace(/\/$/, "");
/** Helper: does the path start with any prefix in a list? */
function startsWithAny(pathname: string, prefixes: string[]) {
@ -47,22 +50,32 @@ import { NextResponse, NextRequest } from "next/server";
}
}
/** Build redirect to /auth/sign-in?reauth=1&next=<original>, and clear auth markers. */
function kickToSignIn(req: NextRequest) {
/**
* Build redirect to /auth/sign-in?next=<original>.
* Only set reauth=1 (and clear cookies) when opts.reauth === true.
*/
function kickToSignIn(req: NextRequest, opts?: { reauth?: boolean }) {
const wantReauth = !!opts?.reauth;
const orig = new URL(req.url);
const next = orig.pathname + (orig.search || "");
const url = new URL(req.url);
url.pathname = "/auth/sign-in";
url.search = "";
url.searchParams.set("reauth", "1");
if (wantReauth) url.searchParams.set("reauth", "1");
url.searchParams.set("next", next);
const res = NextResponse.redirect(url);
// Clear tokens so the very next /auth/* request is truly unauthenticated
res.cookies.set("ma_at", "", { maxAge: 0, path: "/" });
res.cookies.set("ma_v", "", { maxAge: 0, path: "/" }); // throttle marker
// If you also use a refresh token, clear it here too:
// res.cookies.set("ma_rt", "", { maxAge: 0, path: "/" });
// Only clear auth markers in true re-auth scenarios
if (wantReauth) {
res.cookies.set("ma_at", "", { maxAge: 0, path: "/" });
res.cookies.set("ma_v", "", { maxAge: 0, path: "/" }); // throttle marker
// If you also use a refresh token, clear it here too:
// res.cookies.set("ma_rt", "", { maxAge: 0, path: "/" });
}
return res;
}
@ -90,9 +103,9 @@ import { NextResponse, NextRequest } from "next/server";
isAuthRoute &&
(url.searchParams.get("reauth") === "1" || url.searchParams.get("force") === "1");
// If unauthenticated and the route is protected, send to sign-in (with next + reauth)
// If unauthenticated and the route is protected, send to sign-in WITHOUT reauth
if (!token && isProtected) {
return kickToSignIn(req);
return kickToSignIn(req, { reauth: false });
}
// If we have a token, perform local expiry check.
@ -100,8 +113,7 @@ import { NextResponse, NextRequest } from "next/server";
const exp = jwtExp(token);
const expired = !exp || exp * 1000 <= Date.now();
// If it's an auth route and token looks valid, keep your existing UX:
// bounce away from auth pages — unless this is a forced reauth.
// If it's an auth route and token looks valid, bounce away from auth pages — unless this is a forced reauth.
if (isAuthRoute && !expired && !forceAuth) {
url.pathname = "/portal";
url.search = "";
@ -111,7 +123,8 @@ import { NextResponse, NextRequest } from "next/server";
// If protected route: enforce validity
if (isProtected) {
if (expired) {
return kickToSignIn(req);
// True reauth
return kickToSignIn(req, { reauth: true });
}
// ── Throttled remote validation (catches server restarts / revoked tokens)
@ -131,8 +144,8 @@ import { NextResponse, NextRequest } from "next/server";
});
if (!r.ok) {
// Token no longer valid on the server → force re-auth, carry next
return kickToSignIn(req);
// Token no longer valid on the server → true reauth, carry next
return kickToSignIn(req, { reauth: true });
}
// Cache the success for ~1 minute to avoid hammering Directus
@ -146,7 +159,7 @@ import { NextResponse, NextRequest } from "next/server";
return res;
} catch {
// If Directus is unreachable, be conservative and require re-auth
return kickToSignIn(req);
return kickToSignIn(req, { reauth: true });
}
}
}
@ -213,7 +226,7 @@ import { NextResponse, NextRequest } from "next/server";
}
function isPublicPath(pathname: string): boolean {
// 1) Public pages (auth screens)
// 1) Public pages (root splash & auth screens)
if (PUBLIC_PAGES.has(pathname)) return true;
// 2) Static assets / internals