import { getAuthenticatedUser } from '@/lib/auth/auth'; import { createSafeActionClient } from 'next-safe-action'; import { z } from 'zod'; /** * Standard error type for safe actions */ export type ActionError = { code: string; message: string; context?: Record; }; /** * Creates a standardized error response */ function createErrorResponse(code: string, message: string, context?: Record): ActionError { return { code, message, context }; } /** * Development-only console logging */ const devLog = { debug: (...args: unknown[]) => { if (process.env.NODE_ENV === 'development') { // biome-ignore lint/suspicious/noConsole: console.debug(...args); } }, error: (...args: unknown[]) => { // biome-ignore lint/suspicious/noConsole: console.error(...args); }, }; /** * Redacts sensitive fields in an object by replacing their values with asterisks */ function redactSensitiveFields(obj: unknown): unknown { if (typeof obj !== 'object' || obj === null) { return obj; } if (Array.isArray(obj)) { return obj.map(redactSensitiveFields); } return Object.fromEntries( Object.entries(obj).map(([key, value]) => { if (key === 'pincode') { return [key, '******']; } if (typeof value === 'object' && value !== null) { return [key, redactSensitiveFields(value)]; } return [key, value]; }) ); } const handleServerError = (error: Error) => { if (error instanceof z.ZodError) { // Handle known error types devLog.error('Server action validation error:', error); return createErrorResponse('VALIDATION_ERROR', 'Invalid input data', { details: error.errors }); } // Handle invalid challenge response error if (error instanceof Error && error.message.includes('Invalid challenge response')) { devLog.error('Server action invalid challenge response error:', error); return createErrorResponse('INVALID_CHALLENGE_RESPONSE', 'Invalid challenge response'); } // Log unexpected errors in development devLog.error('Server action error:', error); // Return sanitized error for client return createErrorResponse( 'INTERNAL_ERROR', 'An unexpected error occurred', process.env.NODE_ENV === 'development' ? { details: error.message } : undefined ); }; export const actionClient = createSafeActionClient({ handleServerError, }) .use(async ({ next, clientInput, metadata }) => { const result = await next({ ctx: undefined }); devLog.debug('Input ->', redactSensitiveFields(clientInput)); devLog.debug('Result ->', result.data); devLog.debug('Metadata ->', metadata); return result; }) .use(async ({ next }) => { const user = await getAuthenticatedUser(); return next({ ctx: { user, }, }); }); export const publicActionClient = createSafeActionClient({ handleServerError, }).use(async ({ next, clientInput, metadata }) => { const result = await next({ ctx: undefined }); devLog.debug('Input ->', redactSensitiveFields(clientInput)); devLog.debug('Result ->', result.data); devLog.debug('Metadata ->', metadata); return result; });