@bobfrankston/mailx-imap 0.1.39 → 0.1.41
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/index.js +39 -8
- package/package.json +3 -3
package/index.js
CHANGED
|
@@ -5,12 +5,11 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { createAutoImapConfig, CompatImapClient } from "@bobfrankston/iflow-direct";
|
|
7
7
|
import { authenticateOAuth } from "@bobfrankston/oauthsupport";
|
|
8
|
-
import { FileMessageStore } from "@bobfrankston/mailx-store";
|
|
8
|
+
import { FileMessageStore, parseSerial } from "@bobfrankston/mailx-store";
|
|
9
9
|
import { loadSettings, getStorePath, getConfigDir, getHistoryDays, getPrefetch } from "@bobfrankston/mailx-settings";
|
|
10
10
|
import { EventEmitter } from "node:events";
|
|
11
11
|
import * as fs from "node:fs";
|
|
12
12
|
import * as path from "node:path";
|
|
13
|
-
import { simpleParser } from "mailparser";
|
|
14
13
|
import { GmailApiProvider } from "./providers/gmail-api.js";
|
|
15
14
|
import { SmtpClient } from "@bobfrankston/smtp-direct";
|
|
16
15
|
import * as os from "node:os";
|
|
@@ -99,7 +98,7 @@ function decodeEntities(text) {
|
|
|
99
98
|
/** Extract a plain-text preview from message source */
|
|
100
99
|
async function extractPreview(source) {
|
|
101
100
|
try {
|
|
102
|
-
const parsed = await
|
|
101
|
+
const parsed = await parseSerial(source);
|
|
103
102
|
const bodyText = parsed.text || "";
|
|
104
103
|
const bodyHtml = parsed.html || "";
|
|
105
104
|
// Use text part; fall back to stripping HTML tags if text is empty
|
|
@@ -861,9 +860,30 @@ export class ImapManager extends EventEmitter {
|
|
|
861
860
|
}
|
|
862
861
|
/** Store a batch of messages to DB immediately — used by onChunk for incremental sync */
|
|
863
862
|
async storeMessages(accountId, folderId, folder, msgs, highestUid) {
|
|
863
|
+
// Chunked transactions: better-sqlite3 is synchronous and an open
|
|
864
|
+
// transaction blocks every other query on the same DB. A 1881-row
|
|
865
|
+
// INBOX sync inside ONE transaction locked the connection for ~1.5 s
|
|
866
|
+
// of straight upserts; any concurrent `getMessage` IPC had to wait
|
|
867
|
+
// out the whole loop before its own DB read could run. Bob 2026-05-13:
|
|
868
|
+
// "long long loading again." Solution: commit every BATCH_SIZE rows,
|
|
869
|
+
// yield the event loop with `setImmediate`, then begin a new
|
|
870
|
+
// transaction. User clicks land in those gaps with a single-row
|
|
871
|
+
// worth of latency instead of the full loop's worth.
|
|
872
|
+
const BATCH_SIZE = 50;
|
|
864
873
|
let stored = 0;
|
|
865
|
-
|
|
874
|
+
let inTxn = false;
|
|
875
|
+
const startTxn = () => { this.db.beginTransaction(); inTxn = true; };
|
|
876
|
+
const commitTxn = () => { if (inTxn) {
|
|
877
|
+
this.db.commitTransaction();
|
|
878
|
+
inTxn = false;
|
|
879
|
+
} };
|
|
880
|
+
const rollbackTxn = () => { if (inTxn) {
|
|
881
|
+
this.db.rollbackTransaction();
|
|
882
|
+
inTxn = false;
|
|
883
|
+
} };
|
|
866
884
|
try {
|
|
885
|
+
startTxn();
|
|
886
|
+
let batchCount = 0;
|
|
867
887
|
for (const msg of msgs) {
|
|
868
888
|
// Debug: log subjects with non-ASCII to trace encoding issues
|
|
869
889
|
if (msg.subject && /[^\x00-\x7F]/.test(msg.subject)) {
|
|
@@ -919,11 +939,23 @@ export class ImapManager extends EventEmitter {
|
|
|
919
939
|
flags, size: msg.size || 0, hasAttachments, preview, bodyPath
|
|
920
940
|
});
|
|
921
941
|
stored++;
|
|
942
|
+
batchCount++;
|
|
943
|
+
if (batchCount >= BATCH_SIZE) {
|
|
944
|
+
commitTxn();
|
|
945
|
+
// Hand the event loop to any waiting IPC (user clicks,
|
|
946
|
+
// outbox drains, alarm polls). setImmediate runs AFTER
|
|
947
|
+
// pending I/O callbacks, so a stack of getMessage IPCs
|
|
948
|
+
// that arrived during the previous chunk gets serviced
|
|
949
|
+
// before we start the next batch.
|
|
950
|
+
await new Promise(r => setImmediate(r));
|
|
951
|
+
batchCount = 0;
|
|
952
|
+
startTxn();
|
|
953
|
+
}
|
|
922
954
|
}
|
|
923
|
-
|
|
955
|
+
commitTxn();
|
|
924
956
|
}
|
|
925
957
|
catch (e) {
|
|
926
|
-
|
|
958
|
+
rollbackTxn();
|
|
927
959
|
console.error(` storeMessages error: ${e.message}`);
|
|
928
960
|
}
|
|
929
961
|
return stored;
|
|
@@ -939,8 +971,7 @@ export class ImapManager extends EventEmitter {
|
|
|
939
971
|
*
|
|
940
972
|
* Fires the same emits as a normal sync so the UI updates. */
|
|
941
973
|
async insertLocalRowFromSource(accountId, folder, uid, source, flags) {
|
|
942
|
-
const
|
|
943
|
-
const parsed = await simpleParser(source);
|
|
974
|
+
const parsed = await parseSerial(source);
|
|
944
975
|
// Coerce mailparser AddressObject(s) into the flat `{name, address}[]`
|
|
945
976
|
// shape storeMessages's downstream toEmailAddresses expects.
|
|
946
977
|
// RFC 2047 encoded-word decoding (incl. inside quoted-strings) is
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bobfrankston/mailx-imap",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.41",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@bobfrankston/mailx-types": "^0.1.11",
|
|
13
13
|
"@bobfrankston/mailx-settings": "^0.1.16",
|
|
14
|
-
"@bobfrankston/mailx-store": "^0.1.
|
|
14
|
+
"@bobfrankston/mailx-store": "^0.1.21",
|
|
15
15
|
"@bobfrankston/iflow-direct": "^0.1.41",
|
|
16
16
|
"@bobfrankston/tcp-transport": "^0.1.6",
|
|
17
17
|
"@bobfrankston/smtp-direct": "^0.1.8",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@bobfrankston/mailx-types": "^0.1.11",
|
|
41
41
|
"@bobfrankston/mailx-settings": "^0.1.16",
|
|
42
|
-
"@bobfrankston/mailx-store": "^0.1.
|
|
42
|
+
"@bobfrankston/mailx-store": "^0.1.21",
|
|
43
43
|
"@bobfrankston/iflow-direct": "^0.1.41",
|
|
44
44
|
"@bobfrankston/tcp-transport": "^0.1.6",
|
|
45
45
|
"@bobfrankston/smtp-direct": "^0.1.8",
|