Skip to main content
Glama

mcp-gsheets

validation-helpers.ts5.8 kB
import { ERROR_MESSAGES } from './error-messages.js'; import { validateSpreadsheetId, validateRange } from './validators.js'; /** * Common validation fields that can be used with withCommonValidation */ export type ValidationField = | 'spreadsheetId' | 'range' | 'sheetId' | 'values' | 'title' | 'ranges' | 'data'; /** * Interface for validation configuration */ export interface ValidationConfig { requiredFields?: ValidationField[]; defaults?: Record<string, any>; } /** * Higher-order function that adds common validation to any validator function */ export function withCommonValidation<T>( validator: (input: any) => T, config: ValidationConfig ): (input: any) => T { return (input: any): T => { // Validate required fields if (config.requiredFields) { for (const field of config.requiredFields) { validateField(input, field); } } // Apply defaults if (config.defaults) { const enrichedInput = { ...input }; for (const [key, value] of Object.entries(config.defaults)) { if (enrichedInput[key] === undefined) { enrichedInput[key] = value; } } return validator(enrichedInput); } return validator(input); }; } /** * Validates a specific field based on its type */ function validateField(input: any, field: ValidationField): void { switch (field) { case 'spreadsheetId': if (!input.spreadsheetId || typeof input.spreadsheetId !== 'string') { throw new Error(ERROR_MESSAGES.SPREADSHEET_ID_REQUIRED); } if (!validateSpreadsheetId(input.spreadsheetId)) { throw new Error('Invalid spreadsheet ID format'); } break; case 'range': if (!input.range || typeof input.range !== 'string') { throw new Error(ERROR_MESSAGES.REQUIRED_STRING('range')); } if (!validateRange(input.range)) { throw new Error(ERROR_MESSAGES.INVALID_RANGE); } break; case 'sheetId': if (input.sheetId === undefined || typeof input.sheetId !== 'number') { throw new Error(ERROR_MESSAGES.SHEET_ID_REQUIRED); } break; case 'values': if (!input.values || !Array.isArray(input.values)) { throw new Error(ERROR_MESSAGES.VALUES_REQUIRED); } break; case 'title': if (!input.title || typeof input.title !== 'string') { throw new Error(ERROR_MESSAGES.TITLE_REQUIRED); } break; case 'ranges': if (!input.ranges || !Array.isArray(input.ranges) || input.ranges.length === 0) { throw new Error(ERROR_MESSAGES.BATCH_RANGES_REQUIRED); } for (const range of input.ranges) { if (!validateRange(range)) { throw new Error(`Invalid range format: ${range}. ${ERROR_MESSAGES.INVALID_RANGE}`); } } break; case 'data': if (!input.data || !Array.isArray(input.data) || input.data.length === 0) { throw new Error(ERROR_MESSAGES.BATCH_DATA_REQUIRED); } for (const item of input.data) { if (!item.range || !item.values) { throw new Error('Each data item must have range and values properties'); } if (!validateRange(item.range)) { throw new Error(`Invalid range format: ${item.range}. ${ERROR_MESSAGES.INVALID_RANGE}`); } } break; } } /** * Common default values for Google Sheets API */ export const COMMON_DEFAULTS = { majorDimension: 'ROWS', valueRenderOption: 'FORMATTED_VALUE', valueInputOption: 'USER_ENTERED', insertDataOption: 'OVERWRITE', dateTimeRenderOption: 'SERIAL_NUMBER', rowCount: 1000, columnCount: 26, } as const; /** * Creates a validator with common spreadsheet+range validation */ export function createRangeValidator<T>( additionalValidation?: (input: any) => void, defaults?: Record<string, any> ): (input: any) => T { return withCommonValidation( (input: any): T => { if (additionalValidation) { additionalValidation(input); } return input as T; }, { requiredFields: ['spreadsheetId', 'range'], ...(defaults && { defaults }), } ); } /** * Creates a validator with common spreadsheet+sheetId validation */ export function createSheetValidator<T>( additionalValidation?: (input: any) => void, defaults?: Record<string, any> ): (input: any) => T { return withCommonValidation( (input: any): T => { if (additionalValidation) { additionalValidation(input); } return input as T; }, { requiredFields: ['spreadsheetId', 'sheetId'], ...(defaults && { defaults }), } ); } /** * Validates that a value is within a specific range */ export function validateNumberInRange( value: number | undefined, fieldName: string, min: number, max: number ): void { if (value !== undefined) { if (typeof value !== 'number' || value < min || value > max) { throw new Error(`${fieldName} must be between ${min} and ${max}`); } } } /** * Validates color values (0-1 range) */ export function validateColor(color: any, fieldName: string): void { if (color !== undefined) { if (typeof color !== 'object') { throw new Error(`${fieldName} must be an object`); } const colorFields = ['red', 'green', 'blue', 'alpha']; for (const field of colorFields) { if (color[field] !== undefined) { validateNumberInRange(color[field], `${fieldName}.${field}`, 0, 1); } } } } /** * Validates enum values */ export function validateEnum<T extends string>( value: any, _fieldName: string, validValues: readonly T[], errorMessage: string ): void { if (value !== undefined && !validValues.includes(value)) { throw new Error(errorMessage); } }

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/freema/mcp-gsheets'

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