@bobfrankston/mailx-store 0.1.57 → 0.1.58

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/db.d.ts +7 -0
  2. package/db.js +13 -1
  3. package/package.json +1 -1
package/db.d.ts CHANGED
@@ -301,6 +301,13 @@ export declare class MailxDB {
301
301
  * message_folders. Omitted/false for Gmail (label = folder, many per
302
302
  * message). Set true by the IMAP storeMessages path. */
303
303
  exclusive?: boolean;
304
+ /** UIDs the server currently lists for THIS folder, when the caller
305
+ * just enumerated them (the set-diff backfill path). Lets move-detect
306
+ * distinguish a real move (old uid gone) from a DUPLICATE DELIVERY
307
+ * (same Message-ID at two live uids in one folder — e.g. a message
308
+ * addressed to two aliases of the same mailbox). Without this the
309
+ * single row ping-pongs between the two uids every sync cycle. */
310
+ liveServerUids?: Set<number>;
304
311
  }): number;
305
312
  /** Backfill the FTS5 `body_text` column for a message after its body
306
313
  * has been parsed. Capped at ~64 KB of text per row — FTS5 stores the
package/db.js CHANGED
@@ -1828,7 +1828,19 @@ export class MailxDB {
1828
1828
  // surface transient move-dups. Keeping the collapse for now.
1829
1829
  if (msg.messageId) {
1830
1830
  const moved = this.db.prepare("SELECT id, folder_id, uid FROM messages WHERE account_id = ? AND message_id = ? LIMIT 1").get(msg.accountId, msg.messageId);
1831
- if (moved) {
1831
+ // Duplicate delivery, NOT a move: same folder, different uid, and
1832
+ // the caller's server UID list confirms the OLD uid is still in the
1833
+ // mailbox. Rebinding here would ping-pong the row between the two
1834
+ // uids on every sync (each cycle sees the unbound uid as
1835
+ // "server-only", refetches it, and rebinds). Fall through to a
1836
+ // fresh insert instead — both copies get their own row, matching
1837
+ // what the server (and every other client) actually shows, and the
1838
+ // set-diff converges.
1839
+ if (moved && moved.folder_id === msg.folderId && moved.uid !== msg.uid
1840
+ && msg.liveServerUids?.has(moved.uid)) {
1841
+ console.log(` [move-detect] ${msg.accountId} ${msg.messageId}: uid ${moved.uid} still on server — duplicate copy at uid ${msg.uid}, inserting second row`);
1842
+ }
1843
+ else if (moved) {
1832
1844
  console.log(` [move-detect] ${msg.accountId} ${msg.messageId}: rebinding row ${moved.id} (folder ${moved.folder_id}/uid ${moved.uid} → folder ${msg.folderId}/uid ${msg.uid})`);
1833
1845
  this.db.prepare("UPDATE messages SET folder_id = ?, uid = ?, cached_at = ? WHERE id = ?").run(msg.folderId, msg.uid, Date.now(), moved.id);
1834
1846
  this.upsertMessageFolder(moved.id, msg.folderId, msg.uid, msg.exclusive);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bobfrankston/mailx-store",
3
- "version": "0.1.57",
3
+ "version": "0.1.58",
4
4
  "type": "module",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",