refresh test
This commit is contained in:
@@ -65,7 +65,9 @@ export const Route = createRootRouteWithContext<{
|
|||||||
errorComponent: (props) => {
|
errorComponent: (props) => {
|
||||||
return (
|
return (
|
||||||
<RootDocument>
|
<RootDocument>
|
||||||
|
<Providers>
|
||||||
<DefaultCatchBoundary {...props} />
|
<DefaultCatchBoundary {...props} />
|
||||||
|
</Providers>
|
||||||
</RootDocument>
|
</RootDocument>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -18,10 +18,21 @@ function RouteComponent() {
|
|||||||
const urlParams = new URLSearchParams(window.location.search)
|
const urlParams = new URLSearchParams(window.location.search)
|
||||||
const redirect = urlParams.get('redirect')
|
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)
|
window.location.href = decodeURIComponent(redirect)
|
||||||
} else {
|
} else {
|
||||||
window.location.href = '/'
|
const referrer = document.referrer;
|
||||||
|
const referrerUrl = referrer && !referrer.includes('/_serverFn') && !referrer.includes('/api/')
|
||||||
|
? referrer
|
||||||
|
: '/';
|
||||||
|
|
||||||
|
window.location.href = referrerUrl;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
window.location.href = '/login'
|
window.location.href = '/login'
|
||||||
|
|||||||
@@ -34,7 +34,18 @@ export const useMe = () => {
|
|||||||
queryFn,
|
queryFn,
|
||||||
options: {
|
options: {
|
||||||
staleTime: 0,
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -23,8 +23,7 @@ export const fetchMe = createServerFn()
|
|||||||
metadata: context.metadata
|
metadata: context.metadata
|
||||||
};
|
};
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
// If getSessionContext throws (unauthenticated or redirect), return empty state
|
logger.info('fetchMe: Session error', error.message);
|
||||||
logger.info('fetchMe: No authenticated user or redirect needed');
|
|
||||||
return { user: undefined, roles: [], metadata: {} };
|
return { user: undefined, roles: [], metadata: {} };
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ export function useServerMutation<TData, TVariables = unknown>(
|
|||||||
return useMutation({
|
return useMutation({
|
||||||
...mutationOptions,
|
...mutationOptions,
|
||||||
mutationFn: async (variables: TVariables) => {
|
mutationFn: async (variables: TVariables) => {
|
||||||
|
try {
|
||||||
const result = await mutationFn(variables);
|
const result = await mutationFn(variables);
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
@@ -33,6 +34,23 @@ export function useServerMutation<TData, TVariables = unknown>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return result.data;
|
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;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onSuccess: (data, variables, context) => {
|
onSuccess: (data, variables, context) => {
|
||||||
if (showSuccessToast && successMessage) {
|
if (showSuccessToast && successMessage) {
|
||||||
|
|||||||
@@ -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);
|
const session = await verifySuperTokensSession(request);
|
||||||
|
|
||||||
if (session.context.session?.tryRefresh) {
|
if (session.context.session?.tryRefresh) {
|
||||||
|
if (options?.isServerFunction) {
|
||||||
|
throw new Error("SESSION_REFRESH_REQUIRED");
|
||||||
|
}
|
||||||
|
|
||||||
const url = new URL(request.url);
|
const url = new URL(request.url);
|
||||||
const from = encodeURIComponent(url.pathname + url.search);
|
const from = encodeURIComponent(url.pathname + url.search);
|
||||||
throw redirect({
|
throw redirect({
|
||||||
@@ -107,15 +111,34 @@ export const superTokensFunctionMiddleware = createMiddleware({
|
|||||||
type: "function",
|
type: "function",
|
||||||
}).server(async ({ next, response }) => {
|
}).server(async ({ next, response }) => {
|
||||||
const request = getWebRequest();
|
const request = getWebRequest();
|
||||||
const context = await getSessionContext(request);
|
|
||||||
|
try {
|
||||||
|
const context = await getSessionContext(request, { isServerFunction: true });
|
||||||
return next({ context });
|
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({
|
export const superTokensAdminFunctionMiddleware = createMiddleware({
|
||||||
type: "function",
|
type: "function",
|
||||||
}).server(async ({ next }) => {
|
}).server(async ({ next }) => {
|
||||||
const request = getWebRequest();
|
const request = getWebRequest();
|
||||||
const context = await getSessionContext(request);
|
|
||||||
|
try {
|
||||||
|
const context = await getSessionContext(request, { isServerFunction: true });
|
||||||
|
|
||||||
if (context.roles?.includes("Admin")) {
|
if (context.roles?.includes("Admin")) {
|
||||||
return next({ context });
|
return next({ context });
|
||||||
@@ -123,6 +146,21 @@ export const superTokensAdminFunctionMiddleware = createMiddleware({
|
|||||||
|
|
||||||
logger.error("Unauthorized user in admin function.", context);
|
logger.error("Unauthorized user in admin function.", context);
|
||||||
throw new Error("Unauthorized");
|
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;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
export const fetchUserRoles = async (userAuthId: string) => {
|
export const fetchUserRoles = async (userAuthId: string) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user