@bobfrankston/rmfmail 1.2.306 → 1.2.307
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.
- package/.commitmsg +19 -12
- package/npmchanges.md +16 -0
- package/package.json +3 -3
- package/packages/mailx-imap/index.d.ts.map +1 -1
- package/packages/mailx-imap/index.js +22 -15
- package/packages/mailx-imap/index.js.map +1 -1
- package/packages/mailx-imap/index.ts +23 -19
- package/packages/mailx-imap/package-lock.json +2 -2
- package/packages/mailx-imap/package.json +1 -1
- package/packages/mailx-store/db.d.ts +23 -0
- package/packages/mailx-store/db.d.ts.map +1 -1
- package/packages/mailx-store/db.js +47 -0
- package/packages/mailx-store/db.js.map +1 -1
- package/packages/mailx-store/db.ts +52 -0
- package/packages/mailx-store/package.json +1 -1
|
@@ -3445,6 +3445,58 @@ export class MailxDB {
|
|
|
3445
3445
|
this.notifyContactsChanged();
|
|
3446
3446
|
}
|
|
3447
3447
|
|
|
3448
|
+
/** Apply one email entry of a Google People contact.
|
|
3449
|
+
* (Claude Code 2026-09-06, at Bob's direction)
|
|
3450
|
+
*
|
|
3451
|
+
* The `google` row for this address is the one Google owns: its name and
|
|
3452
|
+
* card follow Google on every sync, so a contact renamed in Google
|
|
3453
|
+
* Contacts is renamed here. Discovered rows for the same address are left
|
|
3454
|
+
* alone — they hold the name the correspondent's own mail carried, and
|
|
3455
|
+
* searchContacts folds the two into one line with the google row on top.
|
|
3456
|
+
*
|
|
3457
|
+
* Replaces the pre-2026-09-06 sequence recordSentAddress + a bare
|
|
3458
|
+
* `UPDATE ... WHERE email = ?` in the People sync, which had two defects,
|
|
3459
|
+
* both visible on one contact in Bob's DB: (1) it never wrote `name`, so
|
|
3460
|
+
* a google row kept whatever name it was first created with — Tyler's
|
|
3461
|
+
* Gmail address stayed "T Nichols" after the contact became "tyler K
|
|
3462
|
+
* Nichols" in Google, and typing "Tyler Nichols" in compose found only
|
|
3463
|
+
* his protonmail row; (2) the WHERE-by-email update also tried to turn
|
|
3464
|
+
* the discovered duplicate into a second google row with the same
|
|
3465
|
+
* (source, email, name) and hit the UNIQUE constraint — 4,505
|
|
3466
|
+
* "[contacts] field update failed" lines in one day's log, and none of
|
|
3467
|
+
* those contacts ever received a card update either.
|
|
3468
|
+
*
|
|
3469
|
+
* Returns true when the google row was created. */
|
|
3470
|
+
upsertGoogleContact(googleId: string, name: string, email: string, card: Partial<ContactFields>): boolean {
|
|
3471
|
+
const lower = (email || "").toLowerCase();
|
|
3472
|
+
if (!lower || !/^[^\s<>@]+@[^\s<>@]+\.[^\s<>@]+$/.test(lower)) return false;
|
|
3473
|
+
name = cleanContactName(name);
|
|
3474
|
+
const now = Date.now();
|
|
3475
|
+
const rows = this.db.prepare(
|
|
3476
|
+
"SELECT id FROM contacts WHERE source = 'google' AND lower(email) = ? ORDER BY use_count DESC, id ASC"
|
|
3477
|
+
).all(lower) as { id: number }[];
|
|
3478
|
+
// Older syncs could leave two google rows for one address (the
|
|
3479
|
+
// WHERE-by-email update converted discovered rows). Keep the
|
|
3480
|
+
// most-used one; the rest would collide with the rename below.
|
|
3481
|
+
for (const extra of rows.slice(1)) this.db.prepare("DELETE FROM contacts WHERE id = ?").run(extra.id);
|
|
3482
|
+
const cardVals = CONTACT_FIELD_COLUMNS.map(c => card?.[c] ?? "");
|
|
3483
|
+
if (rows.length) {
|
|
3484
|
+
this.db.prepare(
|
|
3485
|
+
`UPDATE contacts SET name = CASE WHEN ? != '' THEN ? ELSE name END, google_id = ?,
|
|
3486
|
+
${CONTACT_FIELD_COLUMNS.map(c => `${c} = ?`).join(", ")}, updated_at = ?
|
|
3487
|
+
WHERE id = ?`
|
|
3488
|
+
).run(name, name, googleId, ...cardVals, now, rows[0].id);
|
|
3489
|
+
this.notifyContactsChanged();
|
|
3490
|
+
return false;
|
|
3491
|
+
}
|
|
3492
|
+
this.db.prepare(
|
|
3493
|
+
`INSERT INTO contacts (source, google_id, name, email, ${CONTACT_FIELD_COLUMNS.join(", ")}, last_used, use_count, updated_at)
|
|
3494
|
+
VALUES ('google', ?, ?, ?, ${CONTACT_FIELD_COLUMNS.map(() => "?").join(", ")}, 0, 0, ?)`
|
|
3495
|
+
).run(googleId, name, lower, ...cardVals, now);
|
|
3496
|
+
this.notifyContactsChanged();
|
|
3497
|
+
return true;
|
|
3498
|
+
}
|
|
3499
|
+
|
|
3448
3500
|
/** True if `email` (lowercased) appears in the active denylist. Cached
|
|
3449
3501
|
* in-memory; refreshed on contacts.jsonc reload via setContactsDenylist. */
|
|
3450
3502
|
private _denylist: Set<string> = new Set();
|