MCPcopy
hub / github.com/opentrace/opentrace / IDBChatHistoryStore

Class IDBChatHistoryStore

ui/src/chat/chatHistory.ts:77–330  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

75 * Stores conversations entirely in the user's browser.
76 */
77export class IDBChatHistoryStore implements ChatHistoryStore {
78 private dbPromise: Promise<IDBPDatabase> | null = null;
79
80 private getDB(): Promise<IDBPDatabase> {
81 if (!this.dbPromise) {
82 this.dbPromise = openDB(DB_NAME, DB_VERSION, {
83 upgrade(db, oldVersion, _newVersion, transaction) {
84 if (!db.objectStoreNames.contains(STORE_NAME)) {
85 const store = db.createObjectStore(STORE_NAME, { keyPath: 'id' });
86 store.createIndex('updatedAt', 'updatedAt');
87 store.createIndex('projectKey', 'projectKey');
88 } else if (oldVersion < 2) {
89 const store = transaction.objectStore(STORE_NAME);
90 if (!store.indexNames.contains('projectKey')) {
91 store.createIndex('projectKey', 'projectKey');
92 }
93 }
94 // v3: separate blob store for image attachments
95 if (oldVersion < 3) {
96 if (!db.objectStoreNames.contains(BLOB_STORE)) {
97 const blobStore = db.createObjectStore(BLOB_STORE, {
98 keyPath: 'id',
99 });
100 blobStore.createIndex('conversationId', 'conversationId');
101 }
102 // Note: we intentionally skip migrating existing inline images here.
103 // Using async operations (.then/.getAll) inside the upgrade callback
104 // can cause TransactionInactiveError. Inline images from before v3
105 // will continue to work as-is; new images use the blob store.
106 }
107 },
108 }).catch((err) => {
109 this.dbPromise = null;
110 throw err;
111 });
112 }
113 return this.dbPromise;
114 }
115
116 /**
117 * Extract blobs from messages and return stripped messages + blobs.
118 */
119 private stripBlobs(
120 convId: string,
121 messages: ChatMessage[],
122 ): { stripped: ChatMessage[]; blobs: StoredBlob[] } {
123 const blobs: StoredBlob[] = [];
124 const stripped = messages.map((m) => {
125 if (m.role !== 'user') return m;
126 let result = m;
127
128 // Strip legacy image blobs
129 if (m.images?.length) {
130 result = {
131 ...result,
132 images: m.images.map((img) => {
133 if (img.dataUrl) {
134 blobs.push({

Callers

nothing calls this directly

Calls

no outgoing calls

Tested by

no test coverage detected