UNPKG

@channel.io/be-user-chat-mcp

Version:

Backend UserChat Model Context Protocol server for Channel.io

120 lines 5 kB
import { DynamoDBClient, GetItemCommand, QueryCommand, } from "@aws-sdk/client-dynamodb"; import { marshall, unmarshall, } from "@aws-sdk/util-dynamodb"; let client = null; // Get or initialize the DynamoDB client (Lazy Singleton for stdio, per-request for HTTP) function getClient(context) { // For HTTP transport, always create new client with context credentials if (context.awsRegion && context.awsAccessKeyId && context.awsSecretAccessKey) { return new DynamoDBClient({ region: context.awsRegion, credentials: { accessKeyId: context.awsAccessKeyId, secretAccessKey: context.awsSecretAccessKey, ...(context.awsSessionToken && { sessionToken: context.awsSessionToken, }), }, }); } // For stdio transport, use singleton with default credential provider chain // (when context has awsProfile but no direct credentials) if (client) { return client; } // Initialize client without explicit credentials // SDK will use the default credential provider chain // (Environment variables, ~/.aws/credentials, ~/.aws/config, IAM role, etc.) client = new DynamoDBClient({}); console.error("Initialized DynamoDBClient using default credential provider chain."); return client; } /** * Type guard to check if an object is not empty. */ function isNotEmptyObject(obj) { return typeof obj === "object" && obj !== null && Object.keys(obj).length > 0; } /** * Fetches a single item from a DynamoDB table by its key. * * @template T The expected type of the unmarshalled item. * @param tableName The name of the DynamoDB table. * @param key The primary key of the item to fetch (use NativeAttributeValue format). * @param options Optional GetItemCommandInput options (e.g., ProjectionExpression). * @param context RequestContext containing AWS credentials. * @returns The requested item, unmarshalled to type T, or null if not found. */ export async function getDynamoDBItem(tableName, key, options = {}, context) { const commandInput = { TableName: tableName, Key: marshall(key), ...options, }; try { const dbClient = getClient(context); const { Item } = await dbClient.send(new GetItemCommand(commandInput)); return Item ? unmarshall(Item) : null; } catch (error) { handleDynamoDBError(error, `GetItem from ${tableName}`); throw error; } } /** * Queries a DynamoDB table or index. * * @template T The expected type of the unmarshalled items. * @param tableName The name of the DynamoDB table. * @param queryInput Query parameters (KeyConditionExpression, etc.). * Use ExpressionAttributeValues with NativeAttributeValue format for easier use. * Example: ExpressionAttributeValues: { ':val': 'someValue', ':num': 123 } * @param context RequestContext containing AWS credentials. * @returns An array of items matching the query, unmarshalled to type T[]. */ export async function queryDynamoDB(tableName, queryInput, context) { const marshalledAttributes = queryInput.ExpressionAttributeValues && isNotEmptyObject(queryInput.ExpressionAttributeValues) ? marshall(queryInput.ExpressionAttributeValues) : undefined; const commandInput = { TableName: tableName, ...queryInput, ExpressionAttributeValues: marshalledAttributes, }; try { const dbClient = getClient(context); const { Items } = await dbClient.send(new QueryCommand(commandInput)); return Items ? Items.map((item) => unmarshall(item)) : []; } catch (error) { handleDynamoDBError(error, `Query on ${tableName}`); throw error; } } // Centralized error handler function handleDynamoDBError(error, context) { // Keep basic logging console.error(`DynamoDB error during operation (${context}):`, error); let suggestion = ""; if (error instanceof Error) { // Adjust credential hint logic for default provider chain const errorMessage = error.message.toLowerCase(); const errorName = error.name.toLowerCase(); if (errorMessage.includes("credentials") || errorMessage.includes("profile") || errorMessage.includes("token") || errorMessage.includes("region") || // Also check for region errors errorName.includes("credential") || errorName.includes("token")) { suggestion = "Hint: Check AWS credentials configuration (environment variables, ~/.aws/credentials, ~/.aws/config, IAM role, SSO session) and ensure the AWS region is correctly set."; } console.error(`Error Name: ${error.name}, Message: ${error.message}`); } if (suggestion) { console.error("💡", suggestion); } } //# sourceMappingURL=dynamodb.service.js.map