Skip to main content
Glama

Tinder API MCP Server

zod-error-adapter.ts8.72 kB
/** * Zod Error Adapter * * Converts Zod validation errors to API errors. * Provides utilities for formatting and handling Zod errors. */ import { z } from 'zod'; import { ApiError } from './error-handler'; import { ErrorCodes } from '../types'; import logger from './logger'; /** * Error format options */ export interface ErrorFormatOptions { includePathInMessage?: boolean; flattenErrors?: boolean; prefixFieldName?: boolean; /** * Sanitize sensitive fields in error messages * Default: true */ sanitizeSensitiveFields?: boolean; /** * Fields to treat as sensitive (passwords, tokens, etc.) */ sensitiveFields?: string[]; } /** * Default sensitive fields that should be sanitized in error messages */ export const DEFAULT_SENSITIVE_FIELDS = [ 'password', 'token', 'secret', 'apiKey', 'key', 'auth', 'credential', 'pin', 'otp', 'cvv', 'ssn', 'hash', 'salt' ]; /** * Formatted validation error */ export interface FormattedValidationError { path: (string | number)[]; message: string; code: z.ZodIssueCode; details?: Record<string, any>; } /** * Zod Error Adapter class */ export class ZodErrorAdapter { /** * Convert a Zod error to an API error * * @param error - Zod error * @param message - Optional custom message * @param statusCode - HTTP status code (default: 400) * @returns API error */ /** * Convert a Zod error to an API error with sanitized messages * * @param error - Zod error * @param message - Optional custom message * @param statusCode - HTTP status code (default: 400) * @param options - Error format options * @returns API error */ public static toApiError( error: z.ZodError, message: string = 'Validation failed', statusCode: number = 400, options: ErrorFormatOptions = {} ): ApiError { // Set default options const mergedOptions: ErrorFormatOptions = { sanitizeSensitiveFields: true, sensitiveFields: DEFAULT_SENSITIVE_FIELDS, ...options }; const formattedErrors = this.formatZodError(error, mergedOptions); return new ApiError( ErrorCodes.VALIDATION_ERROR, message, { validationErrors: formattedErrors }, statusCode ); } /** * Format a Zod error into a structured object * * @param error - Zod error * @param options - Format options * @returns Formatted validation errors */ /** * Format a Zod error into a structured object with sanitized messages * * @param error - Zod error * @param options - Format options * @returns Formatted validation errors */ public static formatZodError( error: z.ZodError, options: ErrorFormatOptions = {} ): FormattedValidationError[] { // Set default options const { includePathInMessage = true, flattenErrors = true, sanitizeSensitiveFields = true, sensitiveFields = DEFAULT_SENSITIVE_FIELDS } = options; try { return error.errors.map(issue => { const path = issue.path; const pathString = path.join('.'); // Check if this is a sensitive field const isSensitiveField = sanitizeSensitiveFields && this.isSensitivePath(path, sensitiveFields); // Sanitize message if it's a sensitive field let message = issue.message; if (isSensitiveField) { message = this.sanitizeErrorMessage(message); } if (includePathInMessage && pathString) { message = `${pathString}: ${message}`; } return { path: path, message: message, code: issue.code, // Sanitize details for sensitive fields details: isSensitiveField ? undefined : this.getIssueDetails(issue) }; }); } catch (err) { logger.error('Error formatting Zod error:', err); return [{ path: [], message: 'Error processing validation errors', code: z.ZodIssueCode.custom }]; } } /** * Get detailed information from a Zod issue * * @param issue - Zod issue * @returns Issue details */ /** * Check if a path contains sensitive information * * @param path - Path to check * @param sensitiveFields - List of sensitive field names * @returns True if the path contains sensitive information */ private static isSensitivePath(path: (string | number)[], sensitiveFields: string[]): boolean { if (!path || path.length === 0) return false; // Convert path to string for easier checking const pathString = path.join('.').toLowerCase(); // Check if any sensitive field name is in the path return sensitiveFields.some(field => pathString.includes(field.toLowerCase()) ); } /** * Sanitize error message for sensitive fields * * @param message - Original error message * @returns Sanitized error message */ private static sanitizeErrorMessage(message: string): string { // Replace specific values with generic message return 'Invalid value provided for sensitive field'; } /** * Perform constant-time comparison of strings * Helps prevent timing attacks when comparing sensitive values * * @param a - First string * @param b - Second string * @returns True if strings are equal */ public static constantTimeCompare(a: string, b: string): boolean { // If lengths are different, strings are not equal // But still perform the comparison to maintain constant time const result = a.length === b.length; // Calculate maximum length to compare const len = Math.max(a.length, b.length); // Perform constant-time comparison let diff = 0; for (let i = 0; i < len; i++) { // XOR the character codes (will be 0 if equal) diff |= (a.charCodeAt(i % a.length) ^ b.charCodeAt(i % b.length)); } // Return true only if lengths match and all characters match return result && diff === 0; } private static getIssueDetails(issue: z.ZodIssue): Record<string, any> | undefined { const details: Record<string, any> = {}; switch (issue.code) { case z.ZodIssueCode.invalid_type: details.expectedType = issue.expected; details.receivedType = issue.received; break; case z.ZodIssueCode.invalid_literal: details.expected = issue.expected; break; case z.ZodIssueCode.unrecognized_keys: details.keys = issue.keys; break; case z.ZodIssueCode.invalid_union: details.unionErrors = issue.unionErrors.map(e => this.formatZodError(e) ); break; case z.ZodIssueCode.invalid_enum_value: details.options = issue.options; details.received = issue.received; break; case z.ZodIssueCode.invalid_arguments: if ('argumentsError' in issue && issue.argumentsError) { details.argumentsError = this.formatZodError(issue.argumentsError); } break; case z.ZodIssueCode.invalid_return_type: if ('returnTypeError' in issue && issue.returnTypeError) { details.returnTypeError = this.formatZodError(issue.returnTypeError); } break; case z.ZodIssueCode.too_small: if ('minimum' in issue) { details.minimum = issue.minimum; details.type = issue.type; details.inclusive = issue.inclusive; if ('exact' in issue) details.exact = issue.exact; } break; case z.ZodIssueCode.too_big: if ('maximum' in issue) { details.maximum = issue.maximum; details.type = issue.type; details.inclusive = issue.inclusive; if ('exact' in issue) details.exact = issue.exact; } break; default: // For other issue types, include any non-standard properties Object.keys(issue).forEach(key => { if (!['code', 'path', 'message'].includes(key)) { details[key] = (issue as any)[key]; } }); } return Object.keys(details).length > 0 ? details : undefined; } /** * Create a simple error message from a Zod error * * @param error - Zod error * @returns Simple error message */ public static createErrorMessage(error: z.ZodError): string { return error.errors .map(err => { const path = err.path.join('.'); const prefix = path ? `${path}: ` : ''; return `${prefix}${err.message}`; }) .join('; '); } } export default ZodErrorAdapter;

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/glassBead-tc/tinder-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server