Skip to main content
Glama

Curupira

by drzln
minio.service.ts4.79 kB
/** * MinIO Storage Service - Infrastructure Layer * Service for storing large data like screenshots in MinIO object storage */ import { Client as MinIOClient } from 'minio'; import type { ILogger } from '../../core/interfaces/logger.interface.js'; import { Result } from '../../core/result.js'; export interface MinIOConfig { endPoint: string; port: number; useSSL: boolean; accessKey: string; secretKey: string; bucket: string; region?: string; } export interface StorageResult { url: string; bucket: string; key: string; size: number; etag?: string; } export interface IMinIOService { /** * Store a buffer in MinIO */ store(key: string, buffer: Buffer, metadata?: Record<string, string>): Promise<Result<StorageResult, Error>>; /** * Get a pre-signed URL for accessing an object */ getSignedUrl(key: string, expiry?: number): Promise<Result<string, Error>>; /** * Delete an object from storage */ delete(key: string): Promise<Result<void, Error>>; /** * Check if bucket exists and is accessible */ checkConnection(): Promise<Result<boolean, Error>>; } export class MinIOService implements IMinIOService { private client: MinIOClient; private bucket: string; constructor( private readonly config: MinIOConfig, private readonly logger: ILogger ) { this.client = new MinIOClient({ endPoint: config.endPoint, port: config.port, useSSL: config.useSSL, accessKey: config.accessKey, secretKey: config.secretKey }); this.bucket = config.bucket; } async store( key: string, buffer: Buffer, metadata?: Record<string, string> ): Promise<Result<StorageResult, Error>> { try { // Ensure bucket exists const bucketExists = await this.client.bucketExists(this.bucket); if (!bucketExists) { await this.client.makeBucket(this.bucket, this.config.region || 'us-east-1'); this.logger.info({ bucket: this.bucket }, 'Created MinIO bucket'); } // Upload object const metaData = { 'Content-Type': metadata?.['Content-Type'] || 'application/octet-stream', ...metadata }; const result = await this.client.putObject( this.bucket, key, buffer, buffer.length, metaData ); this.logger.info( { bucket: this.bucket, key, size: buffer.length, etag: result.etag }, 'Stored object in MinIO' ); // Construct result const storageResult: StorageResult = { url: `minio://${this.bucket}/${key}`, bucket: this.bucket, key, size: buffer.length, etag: result.etag }; return Result.ok(storageResult); } catch (error) { this.logger.error( { error, bucket: this.bucket, key }, 'Failed to store object in MinIO' ); return Result.err(error instanceof Error ? error : new Error('Unknown error')); } } async getSignedUrl(key: string, expiry: number = 3600): Promise<Result<string, Error>> { try { const url = await this.client.presignedGetObject( this.bucket, key, expiry ); this.logger.debug( { bucket: this.bucket, key, expiry }, 'Generated signed URL' ); return Result.ok(url); } catch (error) { this.logger.error( { error, bucket: this.bucket, key }, 'Failed to generate signed URL' ); return Result.err(error instanceof Error ? error : new Error('Unknown error')); } } async delete(key: string): Promise<Result<void, Error>> { try { await this.client.removeObject(this.bucket, key); this.logger.info( { bucket: this.bucket, key }, 'Deleted object from MinIO' ); return Result.ok(undefined); } catch (error) { this.logger.error( { error, bucket: this.bucket, key }, 'Failed to delete object from MinIO' ); return Result.err(error instanceof Error ? error : new Error('Unknown error')); } } async checkConnection(): Promise<Result<boolean, Error>> { try { // Try to list buckets as a connectivity check await this.client.listBuckets(); // Check if our bucket exists const exists = await this.client.bucketExists(this.bucket); this.logger.info( { bucket: this.bucket, exists }, 'MinIO connection check successful' ); return Result.ok(exists); } catch (error) { this.logger.error( { error }, 'MinIO connection check failed' ); return Result.err(error instanceof Error ? error : new Error('Connection failed')); } } }

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/drzln/curupira'

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