refresh test

This commit is contained in:
yohlo
2025-09-13 00:50:41 -05:00
parent a926dcde07
commit 7d3c0a3fa4
6 changed files with 102 additions and 23 deletions

View File

@@ -65,7 +65,9 @@ export const Route = createRootRouteWithContext<{
errorComponent: (props) => {
return (
<RootDocument>
<DefaultCatchBoundary {...props} />
<Providers>
<DefaultCatchBoundary {...props} />
</Providers>
</RootDocument>
);
},

View File

@@ -18,10 +18,21 @@ function RouteComponent() {
const urlParams = new URLSearchParams(window.location.search)
const redirect = urlParams.get('redirect')
if (redirect && !redirect.startsWith('/_serverFn')) {
const isServerFunction = redirect && (
redirect.startsWith('_serverFn') ||
redirect.startsWith('api/') ||
redirect.includes('_serverFn')
);
if (redirect && !isServerFunction) {
window.location.href = decodeURIComponent(redirect)
} else {
window.location.href = '/'
const referrer = document.referrer;
const referrerUrl = referrer && !referrer.includes('/_serverFn') && !referrer.includes('/api/')
? referrer
: '/';
window.location.href = referrerUrl;
}
} else {
window.location.href = '/login'

View File

@@ -34,7 +34,18 @@ export const useMe = () => {
queryFn,
options: {
staleTime: 0,
refetchOnMount: true
refetchOnMount: true,
retry: (failureCount, error: any) => {
if (error?.response?.status === 401) {
const errorData = error?.response?.data;
if (errorData?.error === "SESSION_REFRESH_REQUIRED") {
const currentUrl = window.location.pathname + window.location.search;
window.location.href = `/refresh-session?redirect=${encodeURIComponent(currentUrl)}`;
return false;
}
}
return failureCount < 3;
}
}
});
};

View File

@@ -23,8 +23,7 @@ export const fetchMe = createServerFn()
metadata: context.metadata
};
} catch (error: any) {
// If getSessionContext throws (unauthenticated or redirect), return empty state
logger.info('fetchMe: No authenticated user or redirect needed');
logger.info('fetchMe: Session error', error.message);
return { user: undefined, roles: [], metadata: {} };
}
})

View File

@@ -23,16 +23,34 @@ export function useServerMutation<TData, TVariables = unknown>(
return useMutation({
...mutationOptions,
mutationFn: async (variables: TVariables) => {
const result = await mutationFn(variables);
if (!result.success) {
if (showErrorToast) {
toast.error(result.error.userMessage);
try {
const result = await mutationFn(variables);
if (!result.success) {
if (showErrorToast) {
toast.error(result.error.userMessage);
}
throw new Error(result.error.userMessage);
}
throw new Error(result.error.userMessage);
return result.data;
} catch (error: any) {
if (error?.response?.status === 401) {
try {
const errorData = typeof error.response.data === 'string'
? JSON.parse(error.response.data)
: error.response.data;
if (errorData?.error === "SESSION_REFRESH_REQUIRED") {
const currentUrl = window.location.pathname + window.location.search;
window.location.href = `/refresh-session?redirect=${encodeURIComponent(currentUrl)}`;
throw new Error("SESSION_REFRESH_REQUIRED");
}
} catch (parseError) {}
}
throw error;
}
return result.data;
},
onSuccess: (data, variables, context) => {
if (showSuccessToast && successMessage) {

View File

@@ -70,10 +70,14 @@ export const verifySuperTokensSession = async (
};
};
export const getSessionContext = async (request: Request): Promise<any> => {
export const getSessionContext = async (request: Request, options?: { isServerFunction?: boolean }): Promise<any> => {
const session = await verifySuperTokensSession(request);
if (session.context.session?.tryRefresh) {
if (options?.isServerFunction) {
throw new Error("SESSION_REFRESH_REQUIRED");
}
const url = new URL(request.url);
const from = encodeURIComponent(url.pathname + url.search);
throw redirect({
@@ -107,22 +111,56 @@ export const superTokensFunctionMiddleware = createMiddleware({
type: "function",
}).server(async ({ next, response }) => {
const request = getWebRequest();
const context = await getSessionContext(request);
return next({ context });
try {
const context = await getSessionContext(request, { isServerFunction: true });
return next({ context });
} catch (error: any) {
if (error.message === "SESSION_REFRESH_REQUIRED") {
throw new Response(
JSON.stringify({
error: "SESSION_REFRESH_REQUIRED",
message: "Session needs to be refreshed"
}),
{
status: 401,
headers: { "Content-Type": "application/json" }
}
);
}
throw error;
}
});
export const superTokensAdminFunctionMiddleware = createMiddleware({
type: "function",
}).server(async ({ next }) => {
const request = getWebRequest();
const context = await getSessionContext(request);
try {
const context = await getSessionContext(request, { isServerFunction: true });
if (context.roles?.includes("Admin")) {
return next({ context });
if (context.roles?.includes("Admin")) {
return next({ context });
}
logger.error("Unauthorized user in admin function.", context);
throw new Error("Unauthorized");
} catch (error: any) {
if (error.message === "SESSION_REFRESH_REQUIRED") {
throw new Response(
JSON.stringify({
error: "SESSION_REFRESH_REQUIRED",
message: "Session needs to be refreshed"
}),
{
status: 401,
headers: { "Content-Type": "application/json" }
}
);
}
throw error;
}
logger.error("Unauthorized user in admin function.", context);
throw new Error("Unauthorized");
});
export const fetchUserRoles = async (userAuthId: string) => {