@bobfrankston/rmfmail 1.0.697 → 1.0.698
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/client/app.bundle.js +16 -3
- package/client/app.bundle.js.map +2 -2
- package/client/components/message-viewer.js +32 -3
- package/client/components/message-viewer.js.map +1 -1
- package/client/components/message-viewer.ts +29 -3
- package/package.json +1 -1
- package/packages/mailx-imap/index.d.ts.map +1 -1
- package/packages/mailx-imap/index.js +6 -2
- package/packages/mailx-imap/index.js.map +1 -1
- package/packages/mailx-imap/index.ts +6 -2
- package/packages/mailx-imap/package-lock.json +2 -2
- package/packages/mailx-imap/package.json +1 -1
- package/packages/mailx-store/package.json +1 -1
- package/packages/mailx-store/parse-serial.d.ts +4 -3
- package/packages/mailx-store/parse-serial.d.ts.map +1 -1
- package/packages/mailx-store/parse-serial.js +37 -7
- package/packages/mailx-store/parse-serial.js.map +1 -1
- package/packages/mailx-store/parse-serial.ts +48 -7
- package/packages/mailx-imap/node_modules.npmglobalize-stash-43676/.package-lock.json +0 -116
|
@@ -166,7 +166,7 @@ function decodeEntities(text: string): string {
|
|
|
166
166
|
/** Extract a plain-text preview from message source */
|
|
167
167
|
async function extractPreview(source: string): Promise<{ bodyHtml: string; bodyText: string; preview: string; hasAttachments: boolean }> {
|
|
168
168
|
try {
|
|
169
|
-
const parsed = await parseSerial(source);
|
|
169
|
+
const parsed = await parseSerial(source, "background");
|
|
170
170
|
const bodyText = parsed.text || "";
|
|
171
171
|
const bodyHtml = parsed.html || "";
|
|
172
172
|
// Use text part; fall back to stripping HTML tags if text is empty
|
|
@@ -1007,7 +1007,11 @@ export class ImapManager extends EventEmitter {
|
|
|
1007
1007
|
source: string,
|
|
1008
1008
|
flags: string[],
|
|
1009
1009
|
): Promise<void> {
|
|
1010
|
-
|
|
1010
|
+
// insertLocalRowFromSource runs right after sendMessage — that's a
|
|
1011
|
+
// user-initiated path but the parse cost is on the post-send
|
|
1012
|
+
// background work, not the click-through. Tag as background so a
|
|
1013
|
+
// concurrent user-click foreground parse jumps ahead.
|
|
1014
|
+
const parsed = await parseSerial(source, "background");
|
|
1011
1015
|
// Coerce mailparser AddressObject(s) into the flat `{name, address}[]`
|
|
1012
1016
|
// shape storeMessages's downstream toEmailAddresses expects.
|
|
1013
1017
|
// RFC 2047 encoded-word decoding (incl. inside quoted-strings) is
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bobfrankston/mailx-imap",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.42",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@bobfrankston/mailx-imap",
|
|
9
|
-
"version": "0.1.
|
|
9
|
+
"version": "0.1.42",
|
|
10
10
|
"license": "ISC",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@bobfrankston/iflow-direct": "^0.1.27",
|
|
@@ -27,7 +27,8 @@
|
|
|
27
27
|
* pool is built.
|
|
28
28
|
*/
|
|
29
29
|
import { type ParsedMail, type Source } from "mailparser";
|
|
30
|
-
/** Serialized wrapper around `mailparser.simpleParser`.
|
|
31
|
-
*
|
|
32
|
-
|
|
30
|
+
/** Serialized wrapper around `mailparser.simpleParser`. `priority` defaults
|
|
31
|
+
* to "foreground" — only sync/background callers should pass "background"
|
|
32
|
+
* so user clicks aren't stuck behind a back-fill. */
|
|
33
|
+
export declare function parseSerial(source: Source, priority?: "foreground" | "background"): Promise<ParsedMail>;
|
|
33
34
|
//# sourceMappingURL=parse-serial.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parse-serial.d.ts","sourceRoot":"","sources":["parse-serial.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,EAAgB,KAAK,UAAU,EAAE,KAAK,MAAM,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"parse-serial.d.ts","sourceRoot":"","sources":["parse-serial.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,EAAgB,KAAK,UAAU,EAAE,KAAK,MAAM,EAAE,MAAM,YAAY,CAAC;AAsCxE;;sDAEsD;AACtD,wBAAsB,WAAW,CAC7B,MAAM,EAAE,MAAM,EACd,QAAQ,GAAE,YAAY,GAAG,YAA2B,GACrD,OAAO,CAAC,UAAU,CAAC,CAOrB"}
|
|
@@ -27,12 +27,42 @@
|
|
|
27
27
|
* pool is built.
|
|
28
28
|
*/
|
|
29
29
|
import { simpleParser } from "mailparser";
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
30
|
+
const _head = []; // UI / foreground — drained first
|
|
31
|
+
const _tail = []; // sync / background
|
|
32
|
+
let _pumping = false;
|
|
33
|
+
async function pump() {
|
|
34
|
+
if (_pumping)
|
|
35
|
+
return;
|
|
36
|
+
_pumping = true;
|
|
37
|
+
try {
|
|
38
|
+
for (;;) {
|
|
39
|
+
const next = _head.shift() ?? _tail.shift();
|
|
40
|
+
if (!next)
|
|
41
|
+
break;
|
|
42
|
+
try {
|
|
43
|
+
const parsed = await simpleParser(next.source);
|
|
44
|
+
next.resolve(parsed);
|
|
45
|
+
}
|
|
46
|
+
catch (e) {
|
|
47
|
+
next.reject(e);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
finally {
|
|
52
|
+
_pumping = false;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/** Serialized wrapper around `mailparser.simpleParser`. `priority` defaults
|
|
56
|
+
* to "foreground" — only sync/background callers should pass "background"
|
|
57
|
+
* so user clicks aren't stuck behind a back-fill. */
|
|
58
|
+
export async function parseSerial(source, priority = "foreground") {
|
|
59
|
+
return new Promise((resolve, reject) => {
|
|
60
|
+
const entry = { source, resolve, reject };
|
|
61
|
+
if (priority === "foreground")
|
|
62
|
+
_head.push(entry);
|
|
63
|
+
else
|
|
64
|
+
_tail.push(entry);
|
|
65
|
+
pump();
|
|
66
|
+
});
|
|
37
67
|
}
|
|
38
68
|
//# sourceMappingURL=parse-serial.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parse-serial.js","sourceRoot":"","sources":["parse-serial.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,EAAE,YAAY,EAAgC,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"parse-serial.js","sourceRoot":"","sources":["parse-serial.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,EAAE,YAAY,EAAgC,MAAM,YAAY,CAAC;AAexE,MAAM,KAAK,GAAc,EAAE,CAAC,CAAE,kCAAkC;AAChE,MAAM,KAAK,GAAc,EAAE,CAAC,CAAE,oBAAoB;AAClD,IAAI,QAAQ,GAAG,KAAK,CAAC;AAErB,KAAK,UAAU,IAAI;IACf,IAAI,QAAQ;QAAE,OAAO;IACrB,QAAQ,GAAG,IAAI,CAAC;IAChB,IAAI,CAAC;QACD,SAAS,CAAC;YACN,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,EAAE,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;YAC5C,IAAI,CAAC,IAAI;gBAAE,MAAM;YACjB,IAAI,CAAC;gBACD,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBAC/C,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YACzB,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACT,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YACnB,CAAC;QACL,CAAC;IACL,CAAC;YAAS,CAAC;QACP,QAAQ,GAAG,KAAK,CAAC;IACrB,CAAC;AACL,CAAC;AAED;;sDAEsD;AACtD,MAAM,CAAC,KAAK,UAAU,WAAW,CAC7B,MAAc,EACd,WAAwC,YAAY;IAEpD,OAAO,IAAI,OAAO,CAAa,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC/C,MAAM,KAAK,GAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;QACnD,IAAI,QAAQ,KAAK,YAAY;YAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;;YAC5C,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACvB,IAAI,EAAE,CAAC;IACX,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -29,12 +29,53 @@
|
|
|
29
29
|
|
|
30
30
|
import { simpleParser, type ParsedMail, type Source } from "mailparser";
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
/**
|
|
33
|
+
* Priority queue. A background pump runs the next pending parse; UI calls
|
|
34
|
+
* insert at the head of the line, sync calls go to the tail. Without this,
|
|
35
|
+
* a first-sync of 96 folders × thousands of messages each can queue
|
|
36
|
+
* thousands of `extractPreview` parses ahead of a single user click — the
|
|
37
|
+
* preview pane sits on "Loading body…" for minutes while the back-fill
|
|
38
|
+
* grinds through. Same parses, different order.
|
|
39
|
+
*/
|
|
40
|
+
type Pending = {
|
|
41
|
+
source: Source;
|
|
42
|
+
resolve: (m: ParsedMail) => void;
|
|
43
|
+
reject: (e: unknown) => void;
|
|
44
|
+
};
|
|
45
|
+
const _head: Pending[] = []; // UI / foreground — drained first
|
|
46
|
+
const _tail: Pending[] = []; // sync / background
|
|
47
|
+
let _pumping = false;
|
|
48
|
+
|
|
49
|
+
async function pump(): Promise<void> {
|
|
50
|
+
if (_pumping) return;
|
|
51
|
+
_pumping = true;
|
|
52
|
+
try {
|
|
53
|
+
for (;;) {
|
|
54
|
+
const next = _head.shift() ?? _tail.shift();
|
|
55
|
+
if (!next) break;
|
|
56
|
+
try {
|
|
57
|
+
const parsed = await simpleParser(next.source);
|
|
58
|
+
next.resolve(parsed);
|
|
59
|
+
} catch (e) {
|
|
60
|
+
next.reject(e);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
} finally {
|
|
64
|
+
_pumping = false;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
33
67
|
|
|
34
|
-
/** Serialized wrapper around `mailparser.simpleParser`.
|
|
35
|
-
*
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
68
|
+
/** Serialized wrapper around `mailparser.simpleParser`. `priority` defaults
|
|
69
|
+
* to "foreground" — only sync/background callers should pass "background"
|
|
70
|
+
* so user clicks aren't stuck behind a back-fill. */
|
|
71
|
+
export async function parseSerial(
|
|
72
|
+
source: Source,
|
|
73
|
+
priority: "foreground" | "background" = "foreground",
|
|
74
|
+
): Promise<ParsedMail> {
|
|
75
|
+
return new Promise<ParsedMail>((resolve, reject) => {
|
|
76
|
+
const entry: Pending = { source, resolve, reject };
|
|
77
|
+
if (priority === "foreground") _head.push(entry);
|
|
78
|
+
else _tail.push(entry);
|
|
79
|
+
pump();
|
|
80
|
+
});
|
|
40
81
|
}
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@bobfrankston/mailx-imap",
|
|
3
|
-
"version": "0.1.12",
|
|
4
|
-
"lockfileVersion": 3,
|
|
5
|
-
"requires": true,
|
|
6
|
-
"packages": {
|
|
7
|
-
"../../../../projects/oauth/oauthsupport": {
|
|
8
|
-
"name": "@bobfrankston/oauthsupport",
|
|
9
|
-
"version": "1.0.25",
|
|
10
|
-
"license": "MIT",
|
|
11
|
-
"devDependencies": {
|
|
12
|
-
"@types/node": "^25.2.1"
|
|
13
|
-
},
|
|
14
|
-
"engines": {
|
|
15
|
-
"node": ">=18.0.0"
|
|
16
|
-
}
|
|
17
|
-
},
|
|
18
|
-
"../../../MailApps/iflow-direct": {
|
|
19
|
-
"name": "@bobfrankston/iflow-direct",
|
|
20
|
-
"version": "0.1.27",
|
|
21
|
-
"license": "ISC",
|
|
22
|
-
"dependencies": {
|
|
23
|
-
"@bobfrankston/tcp-transport": "file:../tcp-transport"
|
|
24
|
-
},
|
|
25
|
-
"devDependencies": {
|
|
26
|
-
"@types/node": "^25.6.0"
|
|
27
|
-
}
|
|
28
|
-
},
|
|
29
|
-
"../../../MailApps/mailx-sync": {
|
|
30
|
-
"name": "@bobfrankston/mailx-sync",
|
|
31
|
-
"version": "0.1.10",
|
|
32
|
-
"license": "ISC",
|
|
33
|
-
"dependencies": {
|
|
34
|
-
"@bobfrankston/iflow-direct": "file:../iflow-direct",
|
|
35
|
-
"@bobfrankston/tcp-transport": "file:../tcp-transport"
|
|
36
|
-
},
|
|
37
|
-
"devDependencies": {
|
|
38
|
-
"@types/node": "^25.6.0"
|
|
39
|
-
}
|
|
40
|
-
},
|
|
41
|
-
"../../../MailApps/smtp-direct": {
|
|
42
|
-
"name": "@bobfrankston/smtp-direct",
|
|
43
|
-
"version": "0.1.5",
|
|
44
|
-
"license": "ISC",
|
|
45
|
-
"dependencies": {
|
|
46
|
-
"@bobfrankston/tcp-transport": "file:../tcp-transport"
|
|
47
|
-
},
|
|
48
|
-
"devDependencies": {
|
|
49
|
-
"@types/node": "^25.6.0"
|
|
50
|
-
}
|
|
51
|
-
},
|
|
52
|
-
"../../../MailApps/tcp-transport": {
|
|
53
|
-
"name": "@bobfrankston/tcp-transport",
|
|
54
|
-
"version": "0.1.5",
|
|
55
|
-
"license": "ISC",
|
|
56
|
-
"devDependencies": {
|
|
57
|
-
"@types/node": "^25.6.0"
|
|
58
|
-
}
|
|
59
|
-
},
|
|
60
|
-
"../../app/packages/mailx-settings": {
|
|
61
|
-
"name": "@bobfrankston/mailx-settings",
|
|
62
|
-
"version": "0.1.6",
|
|
63
|
-
"license": "ISC",
|
|
64
|
-
"dependencies": {
|
|
65
|
-
"@bobfrankston/mailx-types": "file:../mailx-types",
|
|
66
|
-
"jsonc-parser": "^3.3.1"
|
|
67
|
-
}
|
|
68
|
-
},
|
|
69
|
-
"../../app/packages/mailx-store": {
|
|
70
|
-
"name": "@bobfrankston/mailx-store",
|
|
71
|
-
"version": "0.1.5",
|
|
72
|
-
"license": "ISC",
|
|
73
|
-
"dependencies": {
|
|
74
|
-
"@bobfrankston/mailx-settings": "file:../mailx-settings",
|
|
75
|
-
"@bobfrankston/mailx-types": "file:../mailx-types"
|
|
76
|
-
}
|
|
77
|
-
},
|
|
78
|
-
"../../app/packages/mailx-types": {
|
|
79
|
-
"name": "@bobfrankston/mailx-types",
|
|
80
|
-
"version": "0.1.5",
|
|
81
|
-
"license": "ISC"
|
|
82
|
-
},
|
|
83
|
-
"node_modules/@bobfrankston/iflow-direct": {
|
|
84
|
-
"resolved": "../../../MailApps/iflow-direct",
|
|
85
|
-
"link": true
|
|
86
|
-
},
|
|
87
|
-
"node_modules/@bobfrankston/mailx-settings": {
|
|
88
|
-
"resolved": "../../app/packages/mailx-settings",
|
|
89
|
-
"link": true
|
|
90
|
-
},
|
|
91
|
-
"node_modules/@bobfrankston/mailx-store": {
|
|
92
|
-
"resolved": "../../app/packages/mailx-store",
|
|
93
|
-
"link": true
|
|
94
|
-
},
|
|
95
|
-
"node_modules/@bobfrankston/mailx-sync": {
|
|
96
|
-
"resolved": "../../../MailApps/mailx-sync",
|
|
97
|
-
"link": true
|
|
98
|
-
},
|
|
99
|
-
"node_modules/@bobfrankston/mailx-types": {
|
|
100
|
-
"resolved": "../../app/packages/mailx-types",
|
|
101
|
-
"link": true
|
|
102
|
-
},
|
|
103
|
-
"node_modules/@bobfrankston/oauthsupport": {
|
|
104
|
-
"resolved": "../../../../projects/oauth/oauthsupport",
|
|
105
|
-
"link": true
|
|
106
|
-
},
|
|
107
|
-
"node_modules/@bobfrankston/smtp-direct": {
|
|
108
|
-
"resolved": "../../../MailApps/smtp-direct",
|
|
109
|
-
"link": true
|
|
110
|
-
},
|
|
111
|
-
"node_modules/@bobfrankston/tcp-transport": {
|
|
112
|
-
"resolved": "../../../MailApps/tcp-transport",
|
|
113
|
-
"link": true
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|