FrontendData Fetching
Server Actions
Server-side functions for auth and data operations.
Server actions are async functions marked with "use server" that run on the server. HyperSaaS uses them primarily for authentication flows.
Auth Actions
loginAction
// lib/auth/actions.ts
"use server";
export async function loginAction(formData: LoginFormData) {
const validated = userLoginSchema.safeParse(formData);
if (!validated.success) {
return { error: "Invalid input" };
}
const result = await signIn("credentials", {
email: validated.data.email,
password: validated.data.password,
redirect: false,
});
if (result?.error) {
return { error: "Invalid email or password" };
}
return { success: true };
}Used by the login form:
const result = await loginAction({ email, password });
if (result.error) {
toast.error(result.error);
} else {
router.push("/dashboard");
}signOutAction
export async function signOutAction() {
await signOut({ redirectTo: "/" });
}Data Fetching Functions
While not technically "use server" actions, these async functions run on the server in server components:
getCurrentUserServer
Fetches the authenticated user's profile:
// lib/auth/session.ts
export async function getCurrentUserServer(): Promise<UserDetails | null> {
const token = await getAccessToken();
if (!token) return null;
const res = await fetch(`${BACKEND_URL}/auth/users/me/`, {
headers: { Authorization: `JWT ${token}` },
cache: "no-store",
});
if (!res.ok) return null;
return res.json();
}getUserWorkspaces
Fetches all workspaces the user belongs to:
export async function getUserWorkspaces(): Promise<Workspace[]> {
const { data } = await fetchApiListData("/api/workspaces/", workspaceSchema);
return data ?? [];
}getWorkspaceChatSessions
Fetches all chat sessions in a workspace:
export async function getWorkspaceChatSessions(
workspaceId: string
): Promise<ChatSession[]> {
const { data } = await fetchApiListData(
`/api/workspaces/${workspaceId}/chats/`,
chatSessionSchema
);
return data ?? [];
}API Route Authentication Helper
API routes use a combined parse-and-authenticate helper:
// lib/auth/utils.ts
export async function parseContextAndAuthenticate(
params: Promise<Record<string, string>>,
paramsSchema: z.ZodSchema,
req: Request,
bodySchema?: z.ZodSchema
) {
// 1. Parse URL params
const resolvedParams = await params;
const parsedParams = paramsSchema.parse(resolvedParams);
// 2. Get JWT token
const accessToken = await getAccessToken();
if (!accessToken) throw new Error("Unauthorized");
// 3. Parse request body (if provided)
let parsedBody = undefined;
if (bodySchema && req.method !== "GET") {
const body = await req.json();
parsedBody = bodySchema.parse(body);
}
return { ...parsedParams, accessToken, parsedBody };
}Used in API route handlers:
export async function POST(req: Request, { params }) {
const { workspaceId, accessToken, parsedBody } =
await parseContextAndAuthenticate(
params,
z.object({ workspaceId: z.string().uuid() }),
req,
chatCreateSchema
);
const res = await fetch(`${BACKEND_URL}/api/workspaces/${workspaceId}/chats/`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `JWT ${accessToken}`,
},
body: JSON.stringify(parsedBody),
});
return Response.json(await res.json(), { status: res.status });
}