← Open the runnable labsCOMPLETE FREE CHAPTER · SHRUTI

BROWSER DATA RESCUE / CHAPTER ZERO

The page opened. Where did the notes go?

A working screen, a successful write request and a restored record count answer different questions. Learn to ask for the evidence you actually need.

This chapter uses three original synthetic notes and two runnable labs. You do not need a cloud account or paid library. Run the lab over localhost or HTTPS in a browser with IndexedDB and Web Crypto. Keep its databases separate from your app. These exercises do not retrieve deleted user databases, imitate real disk exhaustion or prove that a browser will retain data forever.

1. Start with a record, not a reassuring label

Imagine a small writing app. A person types a paragraph, the app places it in memory and the save button briefly turns green. After reopening the app the paragraph is absent. Before changing the storage engine, separate the memory update, the database request and the transaction result.

The lab gives you a controlled version of this sequence. Choose Start synthetic lab. The source summary should show three records. Their original digest is e009e31b16d81bddb631a946b011b833062571a7f6b00e667adb16e0d94d51c4. Read the actual titles and bodies as well as the digest. A count of three alone could hide three entirely different notes.

Choose Try an aborted save. The lab changes the first note inside a readwrite transaction. Its put request succeeds, and the event trail records that success. The exercise then deliberately aborts the transaction before completion. The displayed note should remain unchanged after rereading it. The UI must say UNSAVED.

const tx = db.transaction('notes', 'readwrite');
tx.oncomplete = () => showSaved();
tx.onabort = () => showUnsavedDraft();
const request = tx.objectStore('notes').put(draft);
request.onsuccess = () => showRequestProgress();

This fragment illustrates the boundary, not a complete application. The runnable source additionally checks input, handles failed operations and rereads records. A production editor should retain the unsaved draft so the person can copy it, retry it or export it. It should not silently replace that draft with the old saved version.

Now choose Commit synthetic edit. The completion event permits a saved acknowledgment. The first note gets a new revision and a different content digest. Completion answers “did this transaction finish successfully?” It does not answer “will the notes survive every future browser cleanup or abrupt power failure?”

2. A blocked upgrade is a waiting connection

A schema upgrade can appear hung even when the browser is behaving correctly. The old page still has an open connection to the previous database version. The new page requests a higher version, and that request cannot start its versionchange transaction yet. Repeatedly opening more connections makes the diagnosis harder.

  1. Use a new isolated session so the source starts at version 1.
  2. Start the lab and follow Open the old tab.
  3. In that second tab, confirm the synthetic connection and choose Hold old v1 connection.
  4. Return to the first tab and choose Request schema v2.
  5. Read the BLOCKED message. The event trail should contain a blocked event; the second tab should receive versionchange.
  6. In the old tab choose Close old connection, then return to the first tab.

The same pending request should proceed. The lab adds a title index in the upgrade transaction and then rereads the notes. It should report version 2, three records and unchanged content. You have demonstrated connection coordination, not repaired corruption.

connection.onversionchange = () => {
  connection.close();
  // Stop accepting edits through this connection.
  // Tell the person to reopen the updated app.
};
openRequest.onblocked = () => {
  showWaitingForAnotherTab();
};

The old tab in this exercise deliberately refuses the usual close-on-versionchange behavior until you release it. It is the failing example. The main connection uses automatic close handling. Close is different from deleting the database: the notes remain stored.

If you test two pages on different origins, their databases are separate and this exercise will not reproduce the same block. Scheme, hostname and port matter. Use the provided session link, not a copied lab on a different port. After a version-2 exercise, opening version 1 produces a VersionError; start a new session for another blocked-upgrade run.

There is no cancellation method on an IndexedDB open request. Keep the waiting state visible and release the old connection. This proof does not implement a universal timeout/retry manager or solve every service-worker deployment issue.

3. Turn a backup into something you can test

Choose Create backup. The lab reads all notes in one readonly transaction and constructs a strict JSON envelope. It includes the format name, schema version, count, original note fields and a SHA-256 digest of canonical note content. The fields are educational and bounded; they are not a general-purpose database archive format.

Choose Download backup JSON and check that a file was actually saved outside browser-managed origin storage. A download button click alone is not proof. You can also copy the visible JSON into a file yourself. Store a production backup somewhere that remains available when the app's origin storage is lost; saving a second copy in the same database misses the point.

Choose Validate backup. This step checks schema, exact fields, count, unique identifiers, bounded text, revisions and checksum without writing a database. The lab rejects backups larger than 128 KiB, more than 100 records or unsupported schema versions. It does not accept arbitrary HTML or execute content from a backup.

Changing a note body without updating the checksum must fail. Editing the input after validation disables restoration until you validate again. A checksum is an integrity check, not a signature: an attacker can edit the records and recalculate it. Do not import untrusted production archives merely because a hash matches.

4. Restore beside the source, then compare

Choose Restore to fresh staging database. The restore creates a new, explicitly named lab database. It writes all validated notes transactionally, waits for completion, reads them back and compares the count and canonical content digest with the backup. The original source is not overwritten.

The lab should say VERIFIED and show the restored titles, bodies and revisions. VERIFIED means that this bounded copy matched this backup at this time. It does not certify that the backup was current, that its author is trustworthy or that all future writes will succeed.

For the failure exercise, select Inject a staging transaction abort and restore again. The lab deliberately aborts after a put succeeds. The new staging database should contain zero records, and the source should be unchanged. An empty staging database can remain after the aborted write; the proof does not claim that schema creation and the later data transaction are one atomic operation.

5. Practice loss without touching your real data

The optional drill empties only this session's synthetic notes store. First make a current backup. If you changed the source since export, the lab refuses to empty it until you export again. A retained copy provides Undo from retained backup while the page remains open.

After confirming the drill, empty the store. Its summary should show zero notes. Restore to staging and verify the original three notes there. Undo returns the retained copy to the original store, unless doing so would overwrite newer notes. That is the normal recovery path for this reversible exercise.

For a stronger outside-origin proof, download the backup, empty the synthetic store and reload the page. Start the existing session again. It should stay empty: existing empty databases must not be silently reseeded. Select the downloaded JSON file, validate it and restore into fresh staging. The restored digest should match the downloaded backup. In-page undo is unavailable after reload because its copy lived only in memory.

This is an actual empty-record-store/reimport exercise. It is not database deletion, storage eviction, a private-session test or a simulated operating-system crash. Do not clear site data, delete databases or run unfamiliar browser-profile recovery scripts to complete this chapter.

6. Try to falsify the reassuring result

Export the observation receipt if you want to keep the visible event sequence with your exercise notes. It includes the browser user agent, lab session and origin. It is a local log, not independent certification. Test traffic and personal practice are not customer acquisition evidence.

7. Use the stronger free tool when you need it

MDN provides authoritative explanations of blocked upgrades and transaction completion. Those free examples can already demonstrate the key browser behavior. Dexie export/import provides established export/import tooling including transaction support and facilities beyond this small lab.

This proof adds an original paired teaching sequence, sample records, visible event trail, failure injections and checked recovery expectations. It is not a faster or more capable database engine. If the documentation and Dexie solve your task, use them. No measured time-saving advantage, purchase intent or exclusivity claim has been established.

The planned casebook would add six substantial cases: failed-save recovery, invalid backup preflight, stale-tab conflict, a cached screen with missing records, retention decisions and deployment recovery. They need their own implementation and evidence. The full book and its EPUB/PDF editions are not yet finished or offered for sale. No paid API, subscription or consulting is required for this free proof.

Reader checklist

  1. Identify the exact operation and transaction outcome before saying saved.
  2. Inspect the blocked connection before opening more requests.
  3. Keep an external backup and validate it without mutation.
  4. Restore into a separate target, reread and compare exact contents.
  5. Write down what the exercise did not test.

Original chapter and examples by Shruti. Version 0.1.0 proof, 8 October 2026. HTTP/HTTPS browser coverage and package evidence are recorded separately; no Safari, private mode or indefinite-retention guarantee.

Return to the working labs →

This site uses Cloudflare Web Analytics for aggregate visit and performance measurement. Read the visitor privacy notice.