Files
flxn-app/src/lib/tanstack-query/utils/to-server-result.ts
yohlo 2551ff8bb3
Some checks failed
CI/CD Pipeline / Build and Push PocketBase Docker Image (push) Has been cancelled
CI/CD Pipeline / Deploy to Kubernetes (push) Has been cancelled
CI/CD Pipeline / Build and Push App Docker Image (push) Has been cancelled
more auth ree
2026-03-02 22:25:01 -06:00

158 lines
4.0 KiB
TypeScript

import { logger } from "../../logger";
import { ErrorType, ServerError, ServerResult } from "../types";
import { pbAdmin } from "../../pocketbase/client";
import { getRequest } from "@tanstack/react-start/server";
export const createServerError = (
type: ErrorType,
message: string,
userMessage: string,
statusCode?: number,
context?: Record<string, any>
): ServerError => ({
code: type,
message,
userMessage,
statusCode,
context,
});
export const toServerResult = async <T>(
serverFn: () => Promise<T>
): Promise<ServerResult<T>> => {
const startTime = Date.now();
try {
const data = await serverFn();
return { success: true, data };
} catch (error) {
if (error && typeof error === 'object' && 'options' in error) {
const redirectError = error as any;
if (redirectError.options?.to && redirectError.options?.statusCode) {
logger.info('toServerResult: Re-throwing TanStack Router redirect', redirectError.options);
throw error;
}
}
if (error instanceof Response && error.status === 440) {
logger.info('toServerResult: Re-throwing 440 Response for session refresh');
throw error;
}
const duration = Date.now() - startTime;
logger.error('Server Fn Error', error);
const mappedError = mapKnownError(error);
let fnName = 'unknown';
try {
const request = getRequest();
const url = new URL(request.url);
const functionId = url.searchParams.get('_serverFnId') || url.pathname;
if (functionId.includes('--')) {
const match = functionId.match(/--([^_]+)_/);
fnName = match?.[1] || functionId.split('--')[1]?.split('_')[0] || 'unknown';
} else {
fnName = serverFn.name || 'unknown';
}
} catch {
fnName = serverFn.name || 'unknown';
}
try {
await pbAdmin.authPromise;
await pbAdmin.createActivity({
name: fnName,
duration,
success: false,
error: mappedError.message,
arguments: {
errorType: mappedError.code,
statusCode: mappedError.statusCode,
userMessage: mappedError.userMessage,
},
});
} catch (activityError) {
}
return { success: false, error: mappedError };
}
};
const mapKnownError = (error: unknown): ServerError => {
if (error && typeof error === "object" && "status" in error) {
const pbError = error as {
status: number;
message: string;
data?: unknown;
};
switch (pbError.status) {
case 400:
return createServerError(
ErrorType.VALIDATION,
pbError.message,
"Invalid request",
400,
{ originalError: pbError.data }
);
case 401:
return createServerError(
ErrorType.UNAUTHORIZED,
pbError.message,
"You are not authorized to perform this action",
401
);
case 403:
return createServerError(
ErrorType.FORBIDDEN,
pbError.message,
"Access denied",
403
);
case 404:
return createServerError(
ErrorType.NOT_FOUND,
pbError.message,
"The requested resource was not found",
404
);
default:
return createServerError(
ErrorType.POCKETBASE,
pbError.message,
"Something went wrong. Please try again.",
pbError.status
);
}
}
if (error instanceof TypeError && error.message.includes("fetch")) {
return createServerError(
ErrorType.NETWORK,
error.message,
"Network error. Please check your connection and try again."
);
}
if (error instanceof Error) {
return createServerError(
ErrorType.UNKNOWN,
error.message,
"An unexpected error occurred. Please try again.",
undefined,
{ stack: error.stack }
);
}
return createServerError(
ErrorType.UNKNOWN,
String(error),
"An unexpected error occurred. Please try again.",
undefined,
{ originalError: error }
);
};