Storage
Meloqui provides storage backends for persisting conversation history across sessions.
IStorage
Interface for conversation history storage implementations.
typescript
interface IStorage {
/** Save messages for a conversation */
save(conversationId: string, messages: Message[]): Promise<void>;
/** Load messages for a conversation */
load(conversationId: string): Promise<Message[]>;
/** Delete a conversation and all its messages */
delete(conversationId: string): Promise<void>;
/** List all conversation IDs */
list(): Promise<string[]>;
}InMemoryStorage
In-memory storage using a Map. Messages are not persisted across process restarts.
typescript
import { ChatClient, InMemoryStorage } from 'meloqui';
const storage = new InMemoryStorage();
const client = new ChatClient({
provider: 'openai',
model: 'gpt-4o',
storage,
conversationId: 'my-conversation'
});TIP
InMemoryStorage is the default if no storage is specified. Each ChatClient instance maintains its own isolated storage.
FileStorage
File-based storage using JSON files. Each conversation is stored in a separate file.
typescript
import { ChatClient, FileStorage } from 'meloqui';
const storage = new FileStorage('./conversations');
const client = new ChatClient({
provider: 'openai',
model: 'gpt-4o',
storage,
conversationId: 'my-conversation'
});FileStorageOptions
typescript
interface FileStorageOptions {
/** File format for storage (default: 'json') */
format?: 'json';
}Security
FileStorage includes security measures:
- Path traversal protection: IDs with
..are rejected - Filename sanitization: Only alphanumeric, hyphens, underscores, and dots allowed
- Hidden file prevention: IDs starting with
.are rejected - Directory containment: Resolved paths must stay within the base directory
typescript
// These will throw InvalidConversationIdError
storage.save('../../../etc/passwd', []); // Path traversal
storage.save('.hidden', []); // Hidden file
storage.save('a/b/c', []); // Path separators sanitized to underscorestestStorageImplementation
Test helper to verify custom storage implementations.
typescript
import { testStorageImplementation, IStorage } from 'meloqui';
class MyCustomStorage implements IStorage {
// ... implementation
}
// Run standard test suite
testStorageImplementation(
'MyCustomStorage',
() => new MyCustomStorage()
);This runs a comprehensive test suite covering:
- Save and load roundtrip
- Empty conversation handling
- Delete behavior
- List functionality
- Message isolation between conversations
Custom Storage Implementation
Implement IStorage to create custom backends (Redis, PostgreSQL, etc.):
typescript
import { IStorage, Message } from 'meloqui';
class RedisStorage implements IStorage {
private redis: RedisClient;
constructor(redisUrl: string) {
this.redis = createClient({ url: redisUrl });
}
async save(conversationId: string, messages: Message[]): Promise<void> {
await this.redis.set(
`conv:${conversationId}`,
JSON.stringify(messages)
);
}
async load(conversationId: string): Promise<Message[]> {
const data = await this.redis.get(`conv:${conversationId}`);
return data ? JSON.parse(data) : [];
}
async delete(conversationId: string): Promise<void> {
await this.redis.del(`conv:${conversationId}`);
}
async list(): Promise<string[]> {
const keys = await this.redis.keys('conv:*');
return keys.map(k => k.replace('conv:', ''));
}
}