Storage API
IStorage abstracts persistence for conversations and messages.
Interface
export interface IStorage {
saveMessage(message: Message): Promise<void>;
getMessage(id: string): Promise<Message | undefined>;
getMessages(query: MessageQuery): Promise<CursorPage<Message>>;
updateMessage(id: string, update: Partial<Message>): Promise<void>;
deleteMessage(id: string): Promise<void>;
saveConversation(conversation: Conversation): Promise<void>;
getConversation(id: string): Promise<Conversation | undefined>;
getConversations(query?: ConversationQuery): Promise<CursorPage<Conversation>>;
updateConversation(id: string, update: Partial<Conversation>): Promise<void>;
deleteConversation(id: string): Promise<void>;
clear(): Promise<void>;
}LocalStorage Adapter (Browser)
import type {
Conversation,
ConversationQuery,
CursorPage,
IStorage,
Message,
MessageQuery,
} from '@kaira/chat-core';
const MESSAGE_KEY = 'kaira:messages';
const CONVERSATION_KEY = 'kaira:conversations';
export class LocalStorageAdapter implements IStorage {
async saveMessage(message: Message): Promise<void> {
const messages = this.readMessages();
messages[message.id] = message;
this.write(MESSAGE_KEY, messages);
}
async getMessage(id: string): Promise<Message | undefined> {
return this.readMessages()[id];
}
async getMessages(query: MessageQuery): Promise<CursorPage<Message>> {
const items = Object.values(this.readMessages()).filter(
(message) => message.conversationId === query.conversationId,
);
return { items, hasMore: false };
}
async updateMessage(id: string, update: Partial<Message>): Promise<void> {
const messages = this.readMessages();
const current = messages[id];
if (!current) return;
messages[id] = { ...current, ...update };
this.write(MESSAGE_KEY, messages);
}
async deleteMessage(id: string): Promise<void> {
const messages = this.readMessages();
delete messages[id];
this.write(MESSAGE_KEY, messages);
}
async saveConversation(conversation: Conversation): Promise<void> {
const conversations = this.readConversations();
conversations[conversation.id] = conversation;
this.write(CONVERSATION_KEY, conversations);
}
async getConversation(id: string): Promise<Conversation | undefined> {
return this.readConversations()[id];
}
async getConversations(_query?: ConversationQuery): Promise<CursorPage<Conversation>> {
return { items: Object.values(this.readConversations()), hasMore: false };
}
async updateConversation(id: string, update: Partial<Conversation>): Promise<void> {
const conversations = this.readConversations();
const current = conversations[id];
if (!current) return;
conversations[id] = { ...current, ...update };
this.write(CONVERSATION_KEY, conversations);
}
async deleteConversation(id: string): Promise<void> {
const conversations = this.readConversations();
delete conversations[id];
this.write(CONVERSATION_KEY, conversations);
}
async clear(): Promise<void> {
localStorage.removeItem(MESSAGE_KEY);
localStorage.removeItem(CONVERSATION_KEY);
}
private readMessages(): Record<string, Message> {
return this.read<Record<string, Message>>(MESSAGE_KEY);
}
private readConversations(): Record<string, Conversation> {
return this.read<Record<string, Conversation>>(CONVERSATION_KEY);
}
private read<T>(key: string): T {
const raw = localStorage.getItem(key);
if (!raw) return {} as T;
return JSON.parse(raw) as T;
}
private write<T>(key: string, value: T): void {
localStorage.setItem(key, JSON.stringify(value));
}
}Database Adapter Pattern
// Implement IStorage by translating methods to your backend API or ORM.
// Keep conversion logic isolated in this adapter layer.