diff --git a/sync/bme-sync.js b/sync/bme-sync.js index fc048f8..ff915cf 100644 --- a/sync/bme-sync.js +++ b/sync/bme-sync.js @@ -1105,6 +1105,35 @@ function buildManualBackupSnapshot(snapshot = {}, chatId = "") { }; } +function markManualBackupHistoryForLocalRebind(snapshot = {}, chatId = "") { + const normalizedSnapshot = normalizeSyncSnapshot(snapshot, chatId); + const meta = toSerializableData(normalizedSnapshot.meta, {}); + const historyState = normalizeRuntimeHistoryMeta( + meta[RUNTIME_HISTORY_META_KEY], + chatId, + ); + const lastProcessedAssistantFloor = Number( + historyState.lastProcessedAssistantFloor, + ); + + historyState.processedMessageHashes = {}; + historyState.processedMessageHashesNeedRefresh = + Number.isFinite(lastProcessedAssistantFloor) && + lastProcessedAssistantFloor >= 0; + meta[RUNTIME_HISTORY_META_KEY] = historyState; + + return { + meta, + nodes: toSerializableData(normalizedSnapshot.nodes, []), + edges: toSerializableData(normalizedSnapshot.edges, []), + tombstones: toSerializableData(normalizedSnapshot.tombstones, []), + state: toSerializableData(normalizedSnapshot.state, { + lastProcessedFloor: -1, + extractionCount: 0, + }), + }; +} + function mergeRuntimeHistoryMeta(localMeta = {}, remoteMeta = {}, options = {}) { const localHistory = normalizeRuntimeHistoryMeta(localMeta, options.chatId); const remoteHistory = normalizeRuntimeHistoryMeta(remoteMeta, options.chatId); @@ -2024,7 +2053,10 @@ export async function restoreFromServer(chatId, options = {}) { }; } - const snapshot = normalizeSyncSnapshot(envelope.snapshot, normalizedChatId); + const snapshot = markManualBackupHistoryForLocalRebind( + envelope.snapshot, + normalizedChatId, + ); if (normalizeChatId(snapshot.meta?.chatId) !== normalizedChatId) { return { restored: false, diff --git a/tests/indexeddb-sync.mjs b/tests/indexeddb-sync.mjs index 1ac5374..dc36c20 100644 --- a/tests/indexeddb-sync.mjs +++ b/tests/indexeddb-sync.mjs @@ -623,6 +623,15 @@ async function testManualBackupAndRestoreFlow() { chatId: "chat-backup-flow", lastProcessedAssistantFloor: 4, extractionCount: 2, + processedMessageHashVersion: 2, + processedMessageHashes: { + 0: "hash-0", + 1: "hash-1", + 2: "hash-2", + 3: "hash-3", + 4: "hash-4", + }, + processedMessageHashesNeedRefresh: false, }, runtimeBatchJournal: [ { id: "journal-1", processedRange: [0, 0], createdAt: 11 }, @@ -677,6 +686,20 @@ async function testManualBackupAndRestoreFlow() { retainedCount: 4, }, ); + assert.deepEqual( + backupPayload.snapshot.meta.runtimeHistoryState.processedMessageHashes, + { + 0: "hash-0", + 1: "hash-1", + 2: "hash-2", + 3: "hash-3", + 4: "hash-4", + }, + ); + assert.equal( + backupPayload.snapshot.meta.runtimeHistoryState.processedMessageHashesNeedRefresh, + false, + ); const backupUploadLog = logs.uploadedPayloads.find( (entry) => entry.name === backupResult.filename, ); @@ -725,6 +748,15 @@ async function testManualBackupAndRestoreFlow() { retainedCount: 4, }, ); + assert.deepEqual(db.snapshot.meta.runtimeHistoryState.processedMessageHashes, {}); + assert.equal( + db.snapshot.meta.runtimeHistoryState.processedMessageHashesNeedRefresh, + true, + ); + assert.equal( + db.snapshot.meta.runtimeHistoryState.lastProcessedAssistantFloor, + 4, + ); assert.ok(Number(db.meta.get("lastBackupRestoredAt")) > 0); const safetyStatus = await getRestoreSafetySnapshotStatus( "chat-backup-flow",