feat(core)!: introduce runtime extension registry and flat module conventions

BREAKING CHANGE: sup config now derives entries from package.json#exports and a server/client glob instead of manual lists; module structure follows flat + barrel convention with .server.js/.client.js runtime suffixes
This commit is contained in:
2026-04-22 14:13:30 -04:00
parent 61388f04a6
commit 0106bc4ea0
35 changed files with 917 additions and 528 deletions
+85 -8
View File
@@ -1,12 +1,89 @@
'use client';
/**
* Auth Pages Export for Next.js App Router
*
* This exports the auth client components.
* Users must create their own server component wrapper that imports the actions.
*/
import { useRouter } from 'next/navigation';
import { useEffect, useState } from 'react';
import LoginPage from './pages/LoginPage.client.js';
import RegisterPage from './pages/RegisterPage.client.js';
import ForgotPasswordPage from './pages/ForgotPasswordPage.client.js';
import ResetPasswordPage from './pages/ResetPasswordPage.client.js';
import ConfirmEmailPage from './pages/ConfirmEmailPage.client.js';
import LogoutPage from './pages/LogoutPage.client.js';
export { default as AuthPagesClient } from './components/AuthPages.js';
export { default as AuthPagesLayout } from './components/AuthPagesLayout.js';
const PAGE_COMPONENTS = {
login: LoginPage,
register: RegisterPage,
forgot: ForgotPasswordPage,
reset: ResetPasswordPage,
confirm: ConfirmEmailPage,
logout: LogoutPage,
};
export default function AuthPage({
params,
searchParams,
registerAction,
loginAction,
forgotPasswordAction,
resetPasswordAction,
verifyEmailAction,
logoutAction,
setSessionCookieAction,
redirectAfterLogin = '/',
currentUser = null,
}) {
const router = useRouter();
const [currentPage, setCurrentPage] = useState(null);
const [email, setEmail] = useState('');
const [token, setToken] = useState('');
useEffect(() => {
const fromParams = params?.auth?.[0];
if (fromParams) { setCurrentPage(fromParams); return; }
if (typeof window !== 'undefined') {
const match = window.location.pathname.match(/\/auth\/([^\/?]+)/);
setCurrentPage(match ? match[1] : 'login');
} else {
setCurrentPage('login');
}
}, [params]);
useEffect(() => {
const run = async () => {
// searchParams became a Promise in Next.js 15 — resolve both forms.
const resolved = searchParams && typeof searchParams.then === 'function'
? await searchParams
: searchParams;
const urlParams = typeof window !== 'undefined'
? new URLSearchParams(window.location.search)
: null;
setEmail(resolved?.email || urlParams?.get('email') || '');
setToken(resolved?.token || urlParams?.get('token') || '');
};
run();
}, [searchParams]);
const navigate = (page) => router.push(`/auth/${page}`);
if (!currentPage) return null;
const Page = PAGE_COMPONENTS[currentPage] || LoginPage;
const common = { onNavigate: navigate, currentUser };
switch (Page) {
case LoginPage:
return <Page {...common} onSubmit={loginAction} onSetSessionCookie={setSessionCookieAction} redirectAfterLogin={redirectAfterLogin} />;
case RegisterPage:
return <Page {...common} onSubmit={registerAction} />;
case ForgotPasswordPage:
return <Page {...common} onSubmit={forgotPasswordAction} />;
case ResetPasswordPage:
return <Page {...common} onSubmit={resetPasswordAction} email={email} token={token} />;
case ConfirmEmailPage:
return <Page {...common} onSubmit={verifyEmailAction} email={email} token={token} />;
case LogoutPage:
return <Page onLogout={logoutAction} onSetSessionCookie={setSessionCookieAction} />;
default:
return null;
}
}