Files
alla-allaos-fullstack/src/proxy.ts
phaichayon 944dbc031d task-d.7.12
2026-07-03 16:09:54 +07:00

98 lines
3.1 KiB
TypeScript

import { auth } from '@/auth';
import { NextResponse } from 'next/server';
const protectedApiPrefixes = ['/api/products', '/api/organizations', '/api/users'];
const superAdminOnlyRoutes = ['/dashboard/workspaces', '/dashboard/administration/setup'];
const organizationAdminRoutes = ['/dashboard/users', '/dashboard/workspaces/team'];
interface BootstrapStatusResponse {
initialized: boolean;
}
function isBootstrapAllowedPath(pathname: string) {
return (
pathname === '/administration/setup' ||
pathname.startsWith('/api/auth/') ||
pathname.startsWith('/api/setup/bootstrap/') ||
pathname === '/api/setup/templates'
);
}
async function getBootstrapInitialized(origin: string): Promise<boolean | null> {
try {
const response = await fetch(new URL('/api/setup/bootstrap/status', origin), {
cache: 'no-store',
headers: {
'x-setup-proxy-check': '1'
}
});
if (!response.ok) return null;
const payload = (await response.json()) as BootstrapStatusResponse;
return payload.initialized;
} catch {
return null;
}
}
export default auth(async (req) => {
const pathname = req.nextUrl.pathname;
const bootstrapAllowedPath = isBootstrapAllowedPath(pathname);
if (bootstrapAllowedPath) {
return NextResponse.next();
}
const isInitialized = await getBootstrapInitialized(req.nextUrl.origin);
if (isInitialized === false) {
if (pathname.startsWith('/api/')) {
return NextResponse.json(
{ message: 'System setup is required before this API is available.', redirectTo: '/administration/setup' },
{ status: 503 }
);
}
return NextResponse.redirect(new URL('/administration/setup', req.nextUrl.origin));
}
const isDashboardRoute = pathname.startsWith('/dashboard');
const isProtectedApiRoute = protectedApiPrefixes.some((prefix) => pathname.startsWith(prefix));
const user = req.auth?.user;
const isSignedIn = Boolean(user);
const isSuperAdmin = user?.systemRole === 'super_admin';
const isOrganizationAdmin =
isSuperAdmin ||
Boolean(
user?.activeOrganizationId &&
(user.activeMembershipRole === 'admin' || user.activePermissions?.includes('users:manage'))
);
if (!isSignedIn && (isDashboardRoute || isProtectedApiRoute)) {
if (isProtectedApiRoute) {
return NextResponse.json({ message: 'Unauthorized' }, { status: 401 });
}
const signInUrl = new URL('/auth/sign-in', req.nextUrl.origin);
signInUrl.searchParams.set('callbackUrl', `${pathname}${req.nextUrl.search}`);
return NextResponse.redirect(signInUrl);
}
if (isSignedIn && superAdminOnlyRoutes.some((prefix) => pathname.startsWith(prefix)) && !isSuperAdmin) {
return NextResponse.redirect(new URL('/dashboard', req.nextUrl.origin));
}
if (isSignedIn && organizationAdminRoutes.some((prefix) => pathname.startsWith(prefix)) && !isOrganizationAdmin) {
return NextResponse.redirect(new URL('/dashboard', req.nextUrl.origin));
}
return NextResponse.next();
});
export const config = {
matcher: [
'/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)'
]
};