Storage API
PolyglotDatabase Class
Dexie-based IndexedDB database implementation.
Schema Definition
this.version(1).stores({
chats: '++id, title, createdAt, updatedAt, lastModified, model, provider, currentModel, isArchived',
meta: 'id, lastSync, version'
});
Tables
chats Table
Primary Key:
id
(auto-increment string)Indexes:
title
,createdAt
,updatedAt
,lastModified
,model
,provider
,currentModel
,isArchived
Type:
Table<Chat, string>
meta Table
Primary Key:
id
(string)Indexes:
lastSync
,version
Type:
Table<AppMeta, string>
Data Models
Chat Interface
interface Chat {
id?: string; // Auto-generated UUID if not provided
title: string; // Chat display name
messages: Message[]; // Array of chat messages
createdAt: Date; // Chat creation timestamp
updatedAt: Date; // Last update timestamp
lastModified: Date; // Last modification (used for sync)
model?: string; // AI model used
provider?: string; // AI provider (openai, anthropic, etc)
currentModel?: string; // Currently active model
isArchived?: boolean; // Archive status (default: false)
}
Message Interface
interface Message {
id: string; // Unique message ID
role: 'user' | 'assistant'; // Message sender role
content: string; // Message text content
timestamp: Date; // Message timestamp
}
AppMeta Interface
interface AppMeta {
id: string; // Metadata record ID
lastSync?: Date; // Last synchronization timestamp
version?: string; // Application version
[key: string]: any; // Additional metadata fields
}
Internal Storage Operations
Date Conversion
convertDatesToObjects(chat: any): Chat
Converts stored date strings back to Date objects.
private convertDatesToObjects(chat: any): Chat {
return {
...chat,
createdAt: new Date(chat.createdAt),
updatedAt: new Date(chat.updatedAt),
lastModified: new Date(chat.lastModified || chat.updatedAt || Date.now()),
isArchived: chat.isArchived || false,
currentModel: chat.currentModel || chat.model,
messages: (chat.messages || []).map((msg: any) => ({
...msg,
timestamp: new Date(msg.timestamp)
}))
};
}
prepareChatForStorage(chat: Chat): Chat
Prepares chat object for IndexedDB storage with proper defaults.
private prepareChatForStorage(chat: Chat): Chat {
const now = new Date();
return {
...chat,
id: chat.id || crypto.randomUUID(),
createdAt: chat.createdAt || now,
updatedAt: now,
lastModified: now,
isArchived: chat.isArchived || false,
currentModel: chat.currentModel || chat.model || 'unknown',
messages: (chat.messages || []).map(msg => ({
...msg,
id: msg.id || crypto.randomUUID(),
timestamp: msg.timestamp || now
}))
};
}
Database Management
initialize(): Promise
Initialize database with schema validation and error recovery.
await this.db.open();
// Verify expected tables exist
const tableNames = this.db.tables.map(table => table.name);
const expectedTables = ['chats', 'meta'];
for (const expectedTable of expectedTables) {
if (!tableNames.includes(expectedTable)) {
throw new Error(`Missing expected table: ${expectedTable}`);
}
}
resetDatabase(): Promise
Delete and recreate database (used for error recovery).
await this.db.delete();
this.db = new PolyglotDatabase();
await this.db.open();
Query Operations
Conversation Queries
// Get all conversations ordered by lastModified (newest first)
const chats = await this.db.chats.orderBy('lastModified').reverse().toArray();
// Get specific conversation
const chat = await this.db.chats.get(id);
// Save/update conversation
const chatId = await this.db.chats.put(preparedChat);
// Delete conversation
await this.db.chats.delete(id);
Metadata Queries
// Get metadata record
const meta = await this.db.meta.get(id);
// Save metadata
await this.db.meta.put(meta);
Filtering Operations
Archive Filtering
// Filter archived conversations
if (showArchived) {
return convertedChats;
} else {
return convertedChats.filter(chat => !chat.isArchived);
}
Error Recovery
Schema Version Errors
if (error.name === 'VersionError' || error.name === 'NotFoundError') {
console.log('Schema mismatch detected, recreating database...');
await this.resetDatabase();
}
Storage Quota Handling
Graceful degradation when quota exceeded
Automatic cleanup of oldest conversations
User notification of storage limitations
Network Errors
All operations work offline
Sync failures don't affect local operations
Automatic retry mechanisms for sync operations
Performance Characteristics
Query Performance
Primary key lookups: O(log n)
Index scans: O(log n + m) where m = result set size
Full table scans: O(n) - avoided where possible
Storage Efficiency
JSON serialization: Compact representation
Index overhead: ~10-15% storage overhead
Date storage: ISO strings for cross-browser compatibility
Memory Usage
Lazy loading: Conversations loaded on demand
Result caching: Dexie provides automatic result caching
Memory cleanup: Automatic garbage collection of unused objects
Browser Storage Limits
Typical Limits
Chrome: ~60% of available disk space
Firefox: Up to 2GB per origin
Safari: 1GB per origin
Edge: Similar to Chrome
Quota Management
// Check current usage
navigator.storage.estimate().then(estimate => {
console.log(`Used: ${estimate.usage}, Quota: ${estimate.quota}`);
});
// Request persistent storage
navigator.storage.persist().then(granted => {
if (granted) {
console.log('Persistent storage granted');
}
});
Last updated