From 5d82c98970e3fa7ac4153294e0e27a5cb1a7f480 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Mon, 5 Oct 2026 00:41:16 -0700 Subject: Custom feeds sync across devices: their own sync slot, newest edit wins, deletions remembered Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01YRC6aKhwAud231ot9FPmhi --- src/feed-sync.js | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/feed-sync.js (limited to 'src/feed-sync.js') diff --git a/src/feed-sync.js b/src/feed-sync.js new file mode 100644 index 0000000..55d5845 --- /dev/null +++ b/src/feed-sync.js @@ -0,0 +1,23 @@ +// Custom feeds across devices: per feed, the newest edit (`at`) wins, and a +// deletion is remembered (gone: { id: ms }) so a device still holding the +// feed doesn't hand it back. Commutative, so snapshots apply in any order. +// Returns null when the remote copy changes nothing. +export function mergeFeeds(local, remote) { + const gone = { ...(local.gone || {}) }; + let changed = false; + for (const [id, t] of Object.entries(remote.gone || {})) + if (typeof t === 'number' && (gone[id] || 0) < t) { gone[id] = t; changed = true; } + const feeds = [...(local.feeds || [])]; + const touched = []; + for (const f of Array.isArray(remote.feeds) ? remote.feeds : []) { + if (!f || typeof f.id !== 'string' || (gone[f.id] || 0) >= (f.at || 0)) continue; + const i = feeds.findIndex((x) => x.id === f.id); + if (i < 0) feeds.push(f); + else if ((f.at || 0) > (feeds[i].at || 0)) feeds[i] = f; + else continue; + touched.push(f.id); changed = true; + } + const kept = feeds.filter((f) => (gone[f.id] || 0) < (f.at || 0)); + if (kept.length !== feeds.length) changed = true; + return changed ? { feeds: kept, gone, touched } : null; +} -- cgit v1.2.3