Skip to main content
Glama
glossary.controller.ts10.5 kB
import type { ControllerResponse } from "../../shared/types/common.types.js"; import { ErrorType, McpError } from "../../shared/utils/error.util.js"; import { handleControllerError } from "../../shared/utils/error-handler.util.js"; import { Logger } from "../../shared/utils/logger.util.js"; import { formatCreateGlossaryTermsResult, formatDeleteGlossaryTermsResult, formatGlossaryTermDetails, formatGlossaryTermsList, formatUpdateGlossaryTermsResult, } from "./glossary.formatter.js"; import { glossaryService } from "./glossary.service.js"; import type { CreateGlossaryToolArgsType, DeleteGlossaryToolArgsType, GetGlossaryToolArgsType, ListGlossaryToolArgsType, UpdateGlossaryToolArgsType, } from "./glossary.types.js"; /** * @namespace GlossaryController * @description Controller responsible for handling Lokalise Glossary Terms API operations. * It orchestrates calls to the glossary service, manages cursor pagination, * handles bulk operations, and formats the response using the formatter. */ /** * @function listGlossaryTerms * @description Fetches a list of glossary terms from a Lokalise project using cursor pagination. * @memberof GlossaryController * @param {ListGlossaryToolArgsType} args - Arguments containing project ID and pagination options * @returns {Promise<ControllerResponse>} A promise that resolves to the formatted glossary terms list. * @throws {McpError} Throws an McpError if validation fails or service call fails. */ async function listGlossaryTerms( args: ListGlossaryToolArgsType, ): Promise<ControllerResponse> { const methodLogger = Logger.forContext( "glossary.controller.ts", "listGlossaryTerms", ); methodLogger.debug("Getting Lokalise glossary terms list...", args); try { // Validate project ID if (!args.projectId || typeof args.projectId !== "string") { throw new McpError( "Project ID is required and must be a string.", ErrorType.API_ERROR, ); } // Validate limit parameter if (args.limit !== undefined && (args.limit < 1 || args.limit > 5000)) { throw new McpError( "Invalid limit parameter. Must be between 1 and 5000.", ErrorType.API_ERROR, ); } // Call service layer const result = await glossaryService.list(args); // Format response using the formatter const formattedContent = formatGlossaryTermsList(result); methodLogger.debug("Glossary terms list fetched successfully", { projectId: args.projectId, termsCount: result.items?.length || 0, hasNext: result.hasNextCursor(), }); return { content: formattedContent, }; } catch (error: unknown) { throw handleControllerError(error, { source: "GlossaryController.listGlossaryTerms", entityType: "GlossaryTerms", entityId: args.projectId, operation: "listing", }); } } /** * @function getGlossaryTerm * @description Fetches details of a specific glossary term. * @memberof GlossaryController * @param {GetGlossaryToolArgsType} args - Arguments containing project ID and term ID * @returns {Promise<ControllerResponse>} A promise that resolves to the formatted term details. * @throws {McpError} Throws an McpError if validation fails or service call fails. */ async function getGlossaryTerm( args: GetGlossaryToolArgsType, ): Promise<ControllerResponse> { const methodLogger = Logger.forContext( "glossary.controller.ts", "getGlossaryTerm", ); methodLogger.debug("Getting glossary term details...", args); try { // Validate inputs if (!args.projectId || typeof args.projectId !== "string") { throw new McpError( "Project ID is required and must be a string.", ErrorType.API_ERROR, ); } if (!args.termId || typeof args.termId !== "number") { throw new McpError( "Term ID is required and must be a number.", ErrorType.API_ERROR, ); } // Call service layer const result = await glossaryService.get(args); // Format response const formattedContent = formatGlossaryTermDetails(result); methodLogger.debug("Glossary term details fetched successfully", { projectId: args.projectId, termId: args.termId, term: result.term, }); return { content: formattedContent, }; } catch (error: unknown) { throw handleControllerError(error, { source: "GlossaryController.getGlossaryTerm", entityType: "GlossaryTerm", entityId: { project: args.projectId, term: String(args.termId) }, operation: "retrieving", }); } } /** * @function createGlossaryTerms * @description Creates one or more glossary terms in a project (bulk operation). * @memberof GlossaryController * @param {CreateGlossaryToolArgsType} args - Arguments containing project ID and terms data * @returns {Promise<ControllerResponse>} A promise that resolves to the formatted result. * @throws {McpError} Throws an McpError if validation fails or service call fails. */ async function createGlossaryTerms( args: CreateGlossaryToolArgsType, ): Promise<ControllerResponse> { const methodLogger = Logger.forContext( "glossary.controller.ts", "createGlossaryTerms", ); methodLogger.debug("Creating glossary terms...", { projectId: args.projectId, termsCount: args.terms.length, }); try { // Validate inputs if (!args.projectId || typeof args.projectId !== "string") { throw new McpError( "Project ID is required and must be a string.", ErrorType.API_ERROR, ); } if (!args.terms || args.terms.length === 0) { throw new McpError( "At least one glossary term is required.", ErrorType.API_ERROR, ); } // Validate each term for (const term of args.terms) { if (!term.term || !term.description) { throw new McpError( "Each term must have both 'term' and 'description' fields.", ErrorType.API_ERROR, ); } } // Call service layer const result = await glossaryService.create(args); // Format response const formattedContent = formatCreateGlossaryTermsResult(result); methodLogger.debug("Glossary terms created successfully", { projectId: args.projectId, createdCount: result.items.length, errorCount: result.errors?.length || 0, }); return { content: formattedContent, }; } catch (error: unknown) { throw handleControllerError(error, { source: "GlossaryController.createGlossaryTerms", entityType: "GlossaryTerms", entityId: args.projectId, operation: "creating", }); } } /** * @function updateGlossaryTerms * @description Updates one or more glossary terms in a project (bulk operation). * @memberof GlossaryController * @param {UpdateGlossaryToolArgsType} args - Arguments containing project ID and terms to update * @returns {Promise<ControllerResponse>} A promise that resolves to the formatted update result. * @throws {McpError} Throws an McpError if validation fails or service call fails. */ async function updateGlossaryTerms( args: UpdateGlossaryToolArgsType, ): Promise<ControllerResponse> { const methodLogger = Logger.forContext( "glossary.controller.ts", "updateGlossaryTerms", ); methodLogger.debug("Updating glossary terms...", { projectId: args.projectId, termsCount: args.terms.length, }); try { // Validate inputs if (!args.projectId || typeof args.projectId !== "string") { throw new McpError( "Project ID is required and must be a string.", ErrorType.API_ERROR, ); } if (!args.terms || args.terms.length === 0) { throw new McpError( "At least one term update is required.", ErrorType.API_ERROR, ); } // Validate each term has an ID for (const term of args.terms) { if (!term.id || typeof term.id !== "number") { throw new McpError( "Each term update must include a valid term ID.", ErrorType.API_ERROR, ); } } // Call service layer const result = await glossaryService.update(args); // Format response const formattedContent = formatUpdateGlossaryTermsResult(result); methodLogger.debug("Glossary terms updated successfully", { projectId: args.projectId, updatedCount: result.items.length, errorCount: result.errors?.length || 0, }); return { content: formattedContent, }; } catch (error: unknown) { throw handleControllerError(error, { source: "GlossaryController.updateGlossaryTerms", entityType: "GlossaryTerms", entityId: args.projectId, operation: "updating", }); } } /** * @function deleteGlossaryTerms * @description Deletes one or more glossary terms from a project (bulk operation). * @memberof GlossaryController * @param {DeleteGlossaryToolArgsType} args - Arguments containing project ID and term IDs * @returns {Promise<ControllerResponse>} A promise that resolves to the formatted deletion result. * @throws {McpError} Throws an McpError if validation fails or service call fails. */ async function deleteGlossaryTerms( args: DeleteGlossaryToolArgsType, ): Promise<ControllerResponse> { const methodLogger = Logger.forContext( "glossary.controller.ts", "deleteGlossaryTerms", ); methodLogger.debug("Deleting glossary terms...", { projectId: args.projectId, termIds: args.termIds, }); try { // Validate inputs if (!args.projectId || typeof args.projectId !== "string") { throw new McpError( "Project ID is required and must be a string.", ErrorType.API_ERROR, ); } if (!args.termIds || args.termIds.length === 0) { throw new McpError( "At least one term ID is required for deletion.", ErrorType.API_ERROR, ); } // Validate all term IDs are numbers for (const termId of args.termIds) { if (typeof termId !== "number") { throw new McpError( "All term IDs must be numbers.", ErrorType.API_ERROR, ); } } // Call service layer const result = await glossaryService.delete(args); // Format response const formattedContent = formatDeleteGlossaryTermsResult(result); methodLogger.debug("Glossary terms deleted", { projectId: args.projectId, deletedCount: result.deleted.count, failedCount: result.failed?.length || 0, }); return { content: formattedContent, }; } catch (error: unknown) { throw handleControllerError(error, { source: "GlossaryController.deleteGlossaryTerms", entityType: "GlossaryTerms", entityId: args.projectId, operation: "deleting", }); } } /** * Export the controller functions */ const glossaryController = { listGlossaryTerms, getGlossaryTerm, createGlossaryTerms, updateGlossaryTerms, deleteGlossaryTerms, }; export default glossaryController;

Latest Blog Posts

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/AbdallahAHO/lokalise-mcp'

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