fix(import): restore favorite + pinned on import/backup restore
A pinned entry came back unpinned after export→import. Wider than pinned: `favorite` was WRITTEN into the export/backup/sync containers but nothing ever read it back — not parseEntriesFromJSON, not encryptImportEntry, not the server INSERTs. So it was a write-only field, and a restore silently dropped both flags. `pinned` wasn't in any container at all. Wired the full round-trip: - containers: export + auto-backup now carry `pinned` (favorite was there). - parseEntriesFromJSON reads both back (absent → 0, e.g. foreign CSV). - encryptImportEntry passes them through to the body. - server create + bulk-import INSERTs write favorite/pinned (GetValue<Boolean>(..., False) → 0 default). PUT still ignores them, so a sync update can't clobber local flags. Sync stays device-local as decided 2026-07-11: buildSyncSnapshot now OMITS favorite explicitly (it was dead weight before; with the passthrough live, leaving it in would have started propagating it). Commented so the intent isn't re-broken. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -207,7 +207,7 @@ async function runAutoBackupNow(silent) {
|
||||
uuid: e.uuid || '',
|
||||
site: e.site, title: e.title || '', username: e.username,
|
||||
password: plain, folder: e.folder, tags: parseTags(e.tags),
|
||||
favorite: !!e.favorite, totp_secret: plainTotp,
|
||||
favorite: !!e.favorite, pinned: !!e.pinned, totp_secret: plainTotp,
|
||||
kind: e.kind || 'login',
|
||||
template: e.template || '',
|
||||
custom_fields: plainCustom,
|
||||
|
||||
@@ -415,6 +415,10 @@ function parseEntriesFromJSON(text) {
|
||||
attachments: atts,
|
||||
icon_b64: String(e.icon_b64 || '').trim(),
|
||||
icon_custom: e.icon_custom ? 1 : 0,
|
||||
// Flags are part of the vault's state: a restore should give the
|
||||
// list back the way it was. Absent (foreign CSV) → 0.
|
||||
favorite: e.favorite ? 1 : 0,
|
||||
pinned: e.pinned ? 1 : 0,
|
||||
created_at: String(e.created_at || '').trim(),
|
||||
updated_at: String(e.updated_at || '').trim(),
|
||||
});
|
||||
@@ -489,6 +493,11 @@ async function encryptImportEntry(plain) {
|
||||
custom_fields_iv: cfIv,
|
||||
icon_b64: plain.icon_b64 || '',
|
||||
icon_custom: plain.icon_custom ? 1 : 0,
|
||||
// Passthrough: present in the export/backup container (restore keeps
|
||||
// the flags), absent from the sync snapshot (favorite/pinned stay
|
||||
// device-local by design) → undefined there, so the server writes 0.
|
||||
favorite: plain.favorite ? 1 : 0,
|
||||
pinned: plain.pinned ? 1 : 0,
|
||||
template: plain.template || '',
|
||||
// Preserve original timestamps on restore — bulk-import falls back
|
||||
// to now only when these are absent (foreign CSV imports).
|
||||
@@ -907,6 +916,7 @@ async function doExport() {
|
||||
folder: e.folder,
|
||||
tags: parseTags(e.tags),
|
||||
favorite: !!e.favorite,
|
||||
pinned: !!e.pinned,
|
||||
totp_secret: plainTotp,
|
||||
kind: e.kind || 'login',
|
||||
template: e.template || '',
|
||||
|
||||
+4
-1
@@ -252,7 +252,10 @@ async function buildSyncSnapshot() {
|
||||
password: plain === '[ERROR]' ? '' : plain,
|
||||
folder: e.folder || 'All',
|
||||
tags: parseTags(e.tags),
|
||||
favorite: !!e.favorite,
|
||||
// favorite / pinned deliberately OMITTED — device-local by design
|
||||
// (decided 2026-07-11, like the avatar). encryptImportEntry passes
|
||||
// through whatever the container holds, so leaving them out here
|
||||
// is what keeps them from propagating. Adding them back = they sync.
|
||||
totp_secret: plainTotp,
|
||||
kind: e.kind || 'login',
|
||||
template: e.template || '',
|
||||
|
||||
Reference in New Issue
Block a user