fix production prerender without auth config
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
import { Suspense } from "react";
|
||||
|
||||
export default function AdminLayout({ children }: LayoutProps<"/admin">) {
|
||||
return <Suspense fallback={null}>{children}</Suspense>;
|
||||
}
|
||||
@@ -1,15 +1,14 @@
|
||||
"use client"
|
||||
|
||||
import { Suspense, useEffect, useRef, useState } from "react"
|
||||
import { usePathname, useSearchParams } from "next/navigation"
|
||||
import { useEffect, useRef, useState } from "react"
|
||||
import { Progress } from "@/components/ui/progress"
|
||||
|
||||
function PageProgressContent() {
|
||||
const pathname = usePathname()
|
||||
const searchParams = useSearchParams()
|
||||
const [progress, setProgress] = useState(0)
|
||||
const [isVisible, setIsVisible] = useState(false)
|
||||
const [navigationKey, setNavigationKey] = useState(0)
|
||||
const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null)
|
||||
const navigationUrlRef = useRef<string | null>(null)
|
||||
|
||||
// Start progress on click
|
||||
useEffect(() => {
|
||||
@@ -26,6 +25,7 @@ function PageProgressContent() {
|
||||
|
||||
// Only show progress for actual page transitions
|
||||
if (isInternal && !isSamePage && target.getAttribute("target") !== "_blank") {
|
||||
navigationUrlRef.current = window.location.href
|
||||
setIsVisible(true)
|
||||
setProgress(15)
|
||||
|
||||
@@ -48,6 +48,26 @@ function PageProgressContent() {
|
||||
return () => document.removeEventListener("click", handleClick)
|
||||
}, [])
|
||||
|
||||
// Detect completion without reading Next.js URL hooks during prerendering.
|
||||
useEffect(() => {
|
||||
if (!isVisible || !navigationUrlRef.current) return
|
||||
const initialUrl = navigationUrlRef.current
|
||||
const checkInterval = window.setInterval(() => {
|
||||
if (window.location.href !== initialUrl) {
|
||||
window.clearInterval(checkInterval)
|
||||
setNavigationKey((key) => key + 1)
|
||||
}
|
||||
}, 50)
|
||||
const fallback = window.setTimeout(() => {
|
||||
window.clearInterval(checkInterval)
|
||||
setNavigationKey((key) => key + 1)
|
||||
}, 10_000)
|
||||
return () => {
|
||||
window.clearInterval(checkInterval)
|
||||
window.clearTimeout(fallback)
|
||||
}
|
||||
}, [isVisible])
|
||||
|
||||
// Finish progress on route change
|
||||
useEffect(() => {
|
||||
if (intervalRef.current) {
|
||||
@@ -60,6 +80,7 @@ function PageProgressContent() {
|
||||
const timeout = setTimeout(() => {
|
||||
setIsVisible(false)
|
||||
setTimeout(() => setProgress(0), 300) // Reset after hiding
|
||||
navigationUrlRef.current = null
|
||||
}, 400)
|
||||
return () => {
|
||||
clearTimeout(finishTimeout)
|
||||
@@ -67,7 +88,7 @@ function PageProgressContent() {
|
||||
}
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [pathname, searchParams])
|
||||
}, [navigationKey])
|
||||
|
||||
if (!isVisible && progress === 0) return null
|
||||
|
||||
@@ -82,9 +103,5 @@ function PageProgressContent() {
|
||||
}
|
||||
|
||||
export function PageProgress() {
|
||||
return (
|
||||
<Suspense fallback={null}>
|
||||
<PageProgressContent />
|
||||
</Suspense>
|
||||
)
|
||||
return <PageProgressContent />
|
||||
}
|
||||
|
||||
@@ -26,6 +26,12 @@ function required(name: string): string {
|
||||
return value;
|
||||
}
|
||||
|
||||
function hasAuthConfiguration(): boolean {
|
||||
return ["DATABASE_URL", "BETTER_AUTH_URL", "BETTER_AUTH_SECRET", "ADMIN_EMAIL"].every(
|
||||
(name) => Boolean(process.env[name]),
|
||||
);
|
||||
}
|
||||
|
||||
function createAuth() {
|
||||
const adminEmail = required("ADMIN_EMAIL");
|
||||
|
||||
@@ -109,6 +115,11 @@ export async function getAdminSession(): Promise<AdminSession | null> {
|
||||
};
|
||||
}
|
||||
|
||||
// Public pages can be prerendered without the runtime auth secret. In that
|
||||
// case the header simply omits the admin link; auth routes still fail loudly
|
||||
// through getAuth() when authentication is actually used.
|
||||
if (!hasAuthConfiguration()) return null;
|
||||
|
||||
const session = await getAuth().api.getSession({ headers: await headers() });
|
||||
if (
|
||||
!session?.session ||
|
||||
|
||||
Reference in New Issue
Block a user