lokalise-mcp
Version:
The Lokalise MCP Server brings Lokalise's localization power to Claude and AI assistants—manage projects, keys, and translations by chat.
373 lines (372 loc) • 15.2 kB
JavaScript
import { createApiError, createUnexpectedError, } from "../../shared/utils/error.util.js";
import { Logger } from "../../shared/utils/logger.util.js";
import { getLokaliseApi } from "../../shared/utils/lokalise-api.util.js";
// Create a contextualized logger for this file
const serviceLogger = Logger.forContext("services/vendor.lokalise.com.keys.service.ts");
// Log service initialization
serviceLogger.debug("Lokalise Keys API service initialized");
/**
* @function getKeys
* @description Fetches a list of keys from a Lokalise project with optional filtering and pagination.
* @memberof VendorLokaliseKeysService
* @param {CursorPaginatedResult} options - Parameters including project ID, filters, and pagination options
* @returns {Promise<CursorPaginatedResult<Key>>} A promise that resolves to the API response containing the keys list
* @throws {McpError} Throws an McpError with details if the API call fails
*/
export async function getKeys(options) {
const methodLogger = serviceLogger.forMethod("getKeys");
try {
methodLogger.debug("Calling Lokalise Keys API - list", {
projectId: options.project_id,
limit: options.limit,
page: options.page,
includeTranslations: options.include_translations,
pagination: options.pagination,
cursor: options.cursor ? "present" : "none",
});
const api = getLokaliseApi();
// Prepare API parameters
const apiParams = {
project_id: options.project_id,
limit: options.limit || 100,
pagination: options.pagination || "cursor",
};
if (options.page) {
apiParams.page = options.page;
}
if (options.cursor) {
apiParams.cursor = options.cursor;
}
if (options.include_translations) {
apiParams.include_translations = 1;
}
if (options.filter_keys && options.filter_keys.length > 0) {
apiParams.filter_keys = options.filter_keys.join(",");
}
if (options.filter_platforms && options.filter_platforms.length > 0) {
apiParams.filter_platforms = options.filter_platforms.join(",");
}
if (options.filter_tags && options.filter_tags.length > 0) {
apiParams.filter_tags = options.filter_tags.join(",");
}
const result = await api.keys().list(apiParams);
methodLogger.debug("Lokalise Keys API call successful", {
projectId: options.project_id,
keysCount: result.items?.length || 0,
hasNextCursor: !!result.nextCursor,
});
return result;
}
catch (error) {
methodLogger.error("Lokalise Keys API call failed - list", {
error: error.message,
projectId: options.project_id,
});
if (error.code === 404) {
throw createApiError(`Project not found: ${options.project_id}`, 404);
}
if (error.code === 403) {
throw createApiError("Access denied to this project", 403);
}
if (error.code === 401) {
throw createApiError("Invalid API key", 401);
}
throw createUnexpectedError(`Failed to fetch keys from project ${options.project_id}: ${error.message}`);
}
}
/**
* @function createKeys
* @description Creates multiple keys in a Lokalise project
* @memberof VendorLokaliseKeysService
* @param {CreateKeysParams} options - Parameters including project ID and keys data
* @returns {Promise<BulkResult<Key>>} A promise that resolves to the API response containing created keys
* @throws {McpError} Throws an McpError with details if the API call fails
*/
export async function createKeys(options) {
const methodLogger = serviceLogger.forMethod("createKeys");
try {
methodLogger.debug("Calling Lokalise Keys API - create", {
projectId: options.project_id,
keysCount: options.keys.length,
});
const api = getLokaliseApi();
// Prepare API parameters
const apiParams = {
keys: options.keys.map((key) => ({
key_name: key.key_name,
description: key.description,
platforms: key.platforms,
translations: key.translations || [],
tags: key.tags || [],
})),
};
const result = await api
.keys()
.create(apiParams, { project_id: options.project_id });
methodLogger.debug("Lokalise Keys API call successful - create", {
projectId: options.project_id,
createdCount: result.items?.length || 0,
errorsCount: result.errors?.length || 0,
});
return result;
}
catch (error) {
methodLogger.error("Lokalise Keys API call failed - create", {
error: error.message,
projectId: options.project_id,
});
if (error.code === 404) {
throw createApiError(`Project not found: ${options.project_id}`, 404);
}
if (error.code === 403) {
throw createApiError("Access denied to this project", 403);
}
if (error.code === 401) {
throw createApiError("Invalid API key", 401);
}
throw createUnexpectedError(`Failed to create keys in project ${options.project_id}: ${error.message}`);
}
}
/**
* @function getKey
* @description Fetches a single key from a Lokalise project
* @memberof VendorLokaliseKeysService
* @param {GetKeyParams} options - Parameters including project ID and key ID
* @returns {Promise<LokaliseKey>} A promise that resolves to the key data
* @throws {McpError} Throws an McpError with details if the API call fails
*/
export async function getKey(options) {
const methodLogger = serviceLogger.forMethod("getKey");
try {
methodLogger.debug("Calling Lokalise Keys API - get", {
projectId: options.project_id,
keyId: options.key_id,
});
const api = getLokaliseApi();
const result = await api
.keys()
.get(options.key_id, { project_id: options.project_id });
methodLogger.debug("Lokalise Keys API call successful - get", {
projectId: options.project_id,
keyId: options.key_id,
keyName: result.key_name,
});
return result;
}
catch (error) {
methodLogger.error("Lokalise Keys API call failed - get", {
error: error.message,
projectId: options.project_id,
keyId: options.key_id,
});
if (error.code === 404) {
throw createApiError(`Key not found: ${options.key_id} in project ${options.project_id}`, 404);
}
if (error.code === 403) {
throw createApiError("Access denied to this project", 403);
}
if (error.code === 401) {
throw createApiError("Invalid API key", 401);
}
throw createUnexpectedError(`Failed to fetch key ${options.key_id} from project ${options.project_id}: ${error.message}`);
}
}
/**
* @function updateKey
* @description Updates a single key in a Lokalise project
* @memberof VendorLokaliseKeysService
* @param {UpdateKeyParams} options - Parameters including project ID, key ID and update data
* @returns {Promise<LokaliseKey>} A promise that resolves to the updated key data
* @throws {McpError} Throws an McpError with details if the API call fails
*/
export async function updateKey(options) {
const methodLogger = serviceLogger.forMethod("updateKey");
try {
methodLogger.debug("Calling Lokalise Keys API - update", {
projectId: options.project_id,
keyId: options.key_id,
});
const api = getLokaliseApi();
// Prepare update data
const updateData = {};
if (options.description !== undefined) {
updateData.description = options.description;
}
if (options.platforms !== undefined) {
updateData.platforms = options.platforms;
}
if (options.tags !== undefined) {
updateData.tags = options.tags;
}
const result = await api
.keys()
.update(options.key_id, updateData, { project_id: options.project_id });
methodLogger.debug("Lokalise Keys API call successful - update", {
projectId: options.project_id,
keyId: options.key_id,
keyName: result.key_name,
});
return result;
}
catch (error) {
methodLogger.error("Lokalise Keys API call failed - update", {
error: error.message,
projectId: options.project_id,
keyId: options.key_id,
});
if (error.code === 404) {
throw createApiError(`Key not found: ${options.key_id} in project ${options.project_id}`, 404);
}
if (error.code === 403) {
throw createApiError("Access denied to this project", 403);
}
if (error.code === 401) {
throw createApiError("Invalid API key", 401);
}
throw createUnexpectedError(`Failed to update key ${options.key_id} in project ${options.project_id}: ${error.message}`);
}
}
/**
* @function deleteKey
* @description Deletes a single key from a Lokalise project
* @memberof VendorLokaliseKeysService
* @param {DeleteKeyParams} options - Parameters including project ID and key ID
* @returns {Promise<KeysBulkDeleted>} A promise that resolves to the deletion confirmation
* @throws {McpError} Throws an McpError with details if the API call fails
*/
export async function deleteKey(options) {
const methodLogger = serviceLogger.forMethod("deleteKey");
try {
methodLogger.debug("Calling Lokalise Keys API - delete", {
projectId: options.project_id,
keyId: options.key_id,
});
const api = getLokaliseApi();
const result = await api
.keys()
.delete(options.key_id, { project_id: options.project_id });
methodLogger.debug("Lokalise Keys API call successful - delete", {
projectId: options.project_id,
keyId: options.key_id,
});
return result;
}
catch (error) {
methodLogger.error("Lokalise Keys API call failed - delete", {
error: error.message,
projectId: options.project_id,
keyId: options.key_id,
});
if (error.code === 404) {
throw createApiError(`Key not found: ${options.key_id} in project ${options.project_id}`, 404);
}
if (error.code === 403) {
throw createApiError("Access denied to this project", 403);
}
if (error.code === 401) {
throw createApiError("Invalid API key", 401);
}
throw createUnexpectedError(`Failed to delete key ${options.key_id} from project ${options.project_id}: ${error.message}`);
}
}
/**
* @function bulkUpdateKeys
* @description Updates multiple keys in a Lokalise project
* @memberof VendorLokaliseKeysService
* @param {BulkUpdateKeysParams} options - Parameters including project ID and keys update data
* @returns {Promise<any>} A promise that resolves to the bulk update results
* @throws {McpError} Throws an McpError with details if the API call fails
*/
export async function bulkUpdateKeys(options) {
const methodLogger = serviceLogger.forMethod("bulkUpdateKeys");
try {
methodLogger.debug("Calling Lokalise Keys API - bulk update", {
projectId: options.project_id,
keysCount: options.keys.length,
});
const api = getLokaliseApi();
// Prepare API parameters
const apiParams = {
keys: options.keys.map((key) => {
const updateData = { key_id: key.key_id };
if (key.description !== undefined) {
updateData.description = key.description;
}
if (key.platforms !== undefined) {
updateData.platforms = key.platforms;
}
if (key.tags !== undefined) {
updateData.tags = key.tags;
}
return updateData;
}),
};
const result = await api
.keys()
.bulk_update(apiParams, { project_id: options.project_id });
methodLogger.debug("Lokalise Keys API call successful - bulk update", {
projectId: options.project_id,
updatedCount: result.items?.length || 0,
errorsCount: result.errors?.length || 0,
});
return result;
}
catch (error) {
methodLogger.error("Lokalise Keys API call failed - bulk update", {
error: error.message,
projectId: options.project_id,
});
if (error.code === 404) {
throw createApiError(`Project not found: ${options.project_id}`, 404);
}
if (error.code === 403) {
throw createApiError("Access denied to this project", 403);
}
if (error.code === 401) {
throw createApiError("Invalid API key", 401);
}
throw createUnexpectedError(`Failed to bulk update keys in project ${options.project_id}: ${error.message}`);
}
}
/**
* @function bulkDeleteKeys
* @description Deletes multiple keys from a Lokalise project
* @memberof VendorLokaliseKeysService
* @param {BulkDeleteKeysParams} options - Parameters including project ID and key IDs
* @returns {Promise<any>} A promise that resolves to the bulk deletion results
* @throws {McpError} Throws an McpError with details if the API call fails
*/
export async function bulkDeleteKeys(options) {
const methodLogger = serviceLogger.forMethod("bulkDeleteKeys");
try {
methodLogger.debug("Calling Lokalise Keys API - bulk delete", {
projectId: options.project_id,
keysCount: options.key_ids.length,
});
const api = getLokaliseApi();
const result = await api
.keys()
.bulk_delete(options.key_ids, { project_id: options.project_id });
methodLogger.debug("Lokalise Keys API call successful - bulk delete", {
projectId: options.project_id,
deletedCount: options.key_ids.length,
});
return result;
}
catch (error) {
methodLogger.error("Lokalise Keys API call failed - bulk delete", {
error: error.message,
projectId: options.project_id,
});
if (error.code === 404) {
throw createApiError(`Project not found: ${options.project_id}`, 404);
}
if (error.code === 403) {
throw createApiError("Access denied to this project", 403);
}
if (error.code === 401) {
throw createApiError("Invalid API key", 401);
}
throw createUnexpectedError(`Failed to bulk delete keys in project ${options.project_id}: ${error.message}`);
}
}