mcp-memory-libsql
by spences10
Verified
/**
* Service for managing attachment metadata and providing simplified references for AI interactions
*/
export interface AttachmentMetadataInternal {
messageId: string;
filename: string;
originalId: string;
mimeType: string;
size: number;
timestamp: number;
}
export class AttachmentIndexService {
private static instance: AttachmentIndexService;
private index: Map<string, AttachmentMetadataInternal>;
private readonly _maxEntries: number = 256;
private expiryMs: number = 3600000; // 1 hour
/**
* Get the maximum number of entries allowed in the index
*/
get maxEntries(): number {
return this._maxEntries;
}
private constructor() {
this.index = new Map();
}
/**
* Get the singleton instance
*/
public static getInstance(): AttachmentIndexService {
if (!AttachmentIndexService.instance) {
AttachmentIndexService.instance = new AttachmentIndexService();
}
return AttachmentIndexService.instance;
}
/**
* Add or update attachment metadata in the index
*/
addAttachment(messageId: string, attachment: {
id: string;
name: string;
mimeType: string;
size: number;
}): void {
// Clean expired entries if we're near capacity
if (this.index.size >= this._maxEntries) {
this.cleanExpiredEntries();
// If still at capacity after cleaning expired entries,
// remove oldest entries until we have space
if (this.index.size >= this._maxEntries) {
const entries = Array.from(this.index.entries())
.sort(([, a], [, b]) => a.timestamp - b.timestamp);
while (this.index.size >= this._maxEntries && entries.length > 0) {
const [key] = entries.shift()!;
this.index.delete(key);
}
}
}
const key = `${messageId}_${attachment.name}`;
this.index.set(key, {
messageId,
filename: attachment.name,
originalId: attachment.id,
mimeType: attachment.mimeType,
size: attachment.size,
timestamp: Date.now()
});
}
/**
* Retrieve attachment metadata by message ID and filename
*/
getMetadata(messageId: string, filename: string): AttachmentMetadataInternal | undefined {
const key = `${messageId}_${filename}`;
const metadata = this.index.get(key);
if (metadata && this.isExpired(metadata)) {
this.index.delete(key);
return undefined;
}
return metadata;
}
/**
* Remove expired entries from the index
*/
public cleanExpiredEntries(): void {
const now = Date.now();
for (const [key, metadata] of this.index.entries()) {
if (this.isExpired(metadata)) {
this.index.delete(key);
}
}
}
/**
* Check if an entry has expired
*/
private isExpired(metadata: AttachmentMetadataInternal): boolean {
return Date.now() - metadata.timestamp > this.expiryMs;
}
/**
* Get current number of entries in the index
*/
get size(): number {
return this.index.size;
}
}