aboutsummaryrefslogtreecommitdiffstats
path: root/src/feed-sync.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/feed-sync.js')
-rw-r--r--src/feed-sync.js23
1 files changed, 23 insertions, 0 deletions
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;
+}