feat(backup): export any backup version as JSON - #643
Open
dmnyc wants to merge 8 commits into
Open
Conversation
dmnyc
force-pushed
the
feat/backup-json-export
branch
from
August 20, 2026 04:41
c652fc5 to
d5282c1
Compare
dmnyc
force-pushed
the
feat/backup-json-export
branch
from
August 20, 2026 04:44
d5282c1 to
4919bc6
Compare
dmnyc
force-pushed
the
feat/backup-json-export
branch
from
August 20, 2026 04:45
4919bc6 to
77c03e3
Compare
dmnyc
force-pushed
the
feat/backup-json-export
branch
from
August 20, 2026 04:54
77c03e3 to
93539f3
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Backups are NIP-78 events only the user can decrypt. That's right for privacy and wrong for portability: the data could only ever be read back by this app, and only for as long as the account's signer still works. There was no way to get a copy out.
The change
"Export JSON" on every backup row — Follows, Mute List, Profile — downloading the latest backup's contents as a file.
The expandable Versions list gets a per-version JSON button too, next to its existing Restore. That's arguably the more useful one: when several versions exist, "export this one" is the thing you actually want.
listFollowsBackups()and friends already decrypt eagerly, so the payload is in hand — export costs no extra signer round-trip and no network call.File contents
The payload is wrapped in a little provenance so the file is still intelligible months later, out of context:
{ "source": "zap.cooking", "exportedAt": "2026-08-20T…", "pubkey": "…", "type": "follows", "kind": "kind:3", "backedUpAt": "2026-08-14T…", "data": { … } }Filename is
zapcooking-<type>-<backup date>.json— dated by when the backup was taken, not when it was exported, so several exports of different versions don't collide.Buttons are disabled when a row has no decrypted backup to export.
Verification
pnpm check— 1 error / 152 warnings, identical tomain(pre-existingdelete-operator error)pnpm test— 1267 passedNot verified: an actual download with real backup data, which needs a signed-in account with backups. The download path is the standard blob/anchor approach, but the resulting file is worth eyeballing once.
Worth deciding separately
There's no import counterpart. Export alone is still worth having — it gets data out, which is the part that's currently impossible — but "restore from a JSON file" is the obvious follow-up if you want these files to be more than an archive.