imapflow 2.0.7 → 2.1.0
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/CHANGELOG.md +29 -0
- package/dist/cjs/commands/append.js +12 -12
- package/dist/cjs/commands/authenticate.d.ts +3 -8
- package/dist/cjs/commands/close.js +2 -1
- package/dist/cjs/commands/copy.js +4 -4
- package/dist/cjs/commands/create.js +2 -3
- package/dist/cjs/commands/delete.js +4 -4
- package/dist/cjs/commands/expunge.js +8 -5
- package/dist/cjs/commands/fetch.js +12 -10
- package/dist/cjs/commands/idle.js +6 -2
- package/dist/cjs/commands/list.js +22 -18
- package/dist/cjs/commands/move.js +11 -6
- package/dist/cjs/commands/namespace.js +1 -1
- package/dist/cjs/commands/quota.js +10 -9
- package/dist/cjs/commands/rename.js +4 -4
- package/dist/cjs/commands/search.js +7 -8
- package/dist/cjs/commands/select.js +12 -9
- package/dist/cjs/commands/status.js +11 -11
- package/dist/cjs/commands/store.js +5 -5
- package/dist/cjs/commands/subscribe.js +2 -17
- package/dist/cjs/commands/subscription.d.ts +10 -0
- package/dist/cjs/commands/subscription.js +29 -0
- package/dist/cjs/commands/unsubscribe.js +2 -17
- package/dist/cjs/download.d.ts +22 -0
- package/dist/cjs/download.js +588 -0
- package/dist/cjs/errors.d.ts +50 -1
- package/dist/cjs/errors.js +53 -1
- package/dist/cjs/handler/imap-compiler.js +1 -1
- package/dist/cjs/handler/imap-stream.d.ts +13 -2
- package/dist/cjs/handler/imap-stream.js +51 -30
- package/dist/cjs/handler/parser-instance.js +2 -2
- package/dist/cjs/handler/token-parser.js +15 -9
- package/dist/cjs/imap-flow.d.ts +30 -84
- package/dist/cjs/imap-flow.js +282 -734
- package/dist/cjs/jp-decoder.js +1 -1
- package/dist/cjs/package-info.d.ts +1 -1
- package/dist/cjs/package-info.js +3 -3
- package/dist/cjs/search-compiler.js +5 -12
- package/dist/cjs/tools.d.ts +52 -11
- package/dist/cjs/tools.js +86 -23
- package/dist/cjs/types.d.ts +30 -16
- package/dist/esm/commands/append.js +13 -13
- package/dist/esm/commands/authenticate.d.ts +3 -8
- package/dist/esm/commands/close.js +2 -1
- package/dist/esm/commands/copy.js +5 -5
- package/dist/esm/commands/create.js +3 -4
- package/dist/esm/commands/delete.js +5 -5
- package/dist/esm/commands/expunge.js +9 -6
- package/dist/esm/commands/fetch.js +13 -11
- package/dist/esm/commands/idle.js +7 -3
- package/dist/esm/commands/list.js +22 -18
- package/dist/esm/commands/move.js +12 -7
- package/dist/esm/commands/namespace.js +2 -2
- package/dist/esm/commands/quota.js +11 -10
- package/dist/esm/commands/rename.js +5 -5
- package/dist/esm/commands/search.js +8 -9
- package/dist/esm/commands/select.js +13 -10
- package/dist/esm/commands/status.js +12 -12
- package/dist/esm/commands/store.js +6 -6
- package/dist/esm/commands/subscribe.js +2 -17
- package/dist/esm/commands/subscription.d.ts +10 -0
- package/dist/esm/commands/subscription.js +26 -0
- package/dist/esm/commands/unsubscribe.js +2 -17
- package/dist/esm/download.d.ts +22 -0
- package/dist/esm/download.js +581 -0
- package/dist/esm/errors.d.ts +50 -1
- package/dist/esm/errors.js +52 -0
- package/dist/esm/handler/imap-compiler.js +1 -1
- package/dist/esm/handler/imap-stream.d.ts +13 -2
- package/dist/esm/handler/imap-stream.js +51 -30
- package/dist/esm/handler/parser-instance.js +2 -2
- package/dist/esm/handler/token-parser.js +15 -9
- package/dist/esm/imap-flow.d.ts +30 -84
- package/dist/esm/imap-flow.js +282 -735
- package/dist/esm/jp-decoder.js +1 -1
- package/dist/esm/package-info.d.ts +1 -1
- package/dist/esm/package-info.js +3 -3
- package/dist/esm/search-compiler.js +5 -12
- package/dist/esm/tools.d.ts +52 -11
- package/dist/esm/tools.js +79 -21
- package/dist/esm/types.d.ts +30 -16
- package/package.json +4 -4
|
@@ -59,7 +59,7 @@ const VALUED_RESPONSE_CODES = Object.assign(Object.create(null), {
|
|
|
59
59
|
* @throws If the SELECT/EXAMINE command fails
|
|
60
60
|
*/
|
|
61
61
|
async function select(connection, pathInput, options) {
|
|
62
|
-
if (!
|
|
62
|
+
if (!(0, tools_js_1.isAuthenticatedState)(connection)) {
|
|
63
63
|
// nothing to do here
|
|
64
64
|
return;
|
|
65
65
|
}
|
|
@@ -95,12 +95,16 @@ async function select(connection, pathInput, options) {
|
|
|
95
95
|
// QRESYNC (RFC 7162): allows efficient mailbox resynchronization by sending
|
|
96
96
|
// the last known UIDVALIDITY and HIGHESTMODSEQ. Server responds with only
|
|
97
97
|
// the changes (new flags, expunged UIDs) since that point.
|
|
98
|
+
// The caller may pass UIDVALIDITY as a bigint, a number or a string. It is parsed once,
|
|
99
|
+
// so the value that is sent is also the one checked against the server's below, and a
|
|
100
|
+
// value that is not a plain decimal skips QRESYNC instead of reaching the server.
|
|
101
|
+
let uidValidity = options.uidValidity !== undefined ? (0, tools_js_1.parseBigIntValue)(String(options.uidValidity)) : false;
|
|
98
102
|
let extraArgs = [];
|
|
99
|
-
if (connection.enabled.has('QRESYNC') && options.changedSince &&
|
|
103
|
+
if (connection.enabled.has('QRESYNC') && options.changedSince && uidValidity) {
|
|
100
104
|
extraArgs.push([
|
|
101
105
|
{ type: 'ATOM', value: 'QRESYNC' },
|
|
102
106
|
[
|
|
103
|
-
{ type: 'ATOM', value:
|
|
107
|
+
{ type: 'ATOM', value: uidValidity.toString() },
|
|
104
108
|
{ type: 'ATOM', value: options.changedSince.toString() }
|
|
105
109
|
]
|
|
106
110
|
]);
|
|
@@ -205,7 +209,7 @@ async function select(connection, pathInput, options) {
|
|
|
205
209
|
// QRESYNC results are only valid if UIDVALIDITY matches, HIGHESTMODSEQ is
|
|
206
210
|
// present, and the mailbox supports mod-sequences. If any condition fails,
|
|
207
211
|
// the client cannot trust the incremental updates and must do a full resync.
|
|
208
|
-
if (map.qresync && (
|
|
212
|
+
if (map.qresync && (uidValidity !== map.uidValidity || !map.highestModseq || map.noModseq)) {
|
|
209
213
|
map.qresync = false;
|
|
210
214
|
}
|
|
211
215
|
// Transition mailbox state: save previous mailbox reference, temporarily
|
|
@@ -215,7 +219,7 @@ async function select(connection, pathInput, options) {
|
|
|
215
219
|
// Emit mailboxClose if we're switching from a different mailbox.
|
|
216
220
|
// Re-selecting the same mailbox (e.g., for resync) does not trigger close/open.
|
|
217
221
|
if (currentMailbox && currentMailbox.path !== path) {
|
|
218
|
-
|
|
222
|
+
(0, tools_js_1.emitSafe)(connection, 'mailboxClose', currentMailbox);
|
|
219
223
|
}
|
|
220
224
|
connection.mailbox = map;
|
|
221
225
|
// Save the SELECT command for potential re-use (e.g., NOOP fallback polling
|
|
@@ -223,13 +227,13 @@ async function select(connection, pathInput, options) {
|
|
|
223
227
|
connection.currentSelectCommand = selectCommand;
|
|
224
228
|
connection.state = connection.states.SELECTED;
|
|
225
229
|
if (!currentMailbox || currentMailbox.path !== path) {
|
|
226
|
-
|
|
230
|
+
(0, tools_js_1.emitSafe)(connection, 'mailboxOpen', connection.mailbox);
|
|
227
231
|
}
|
|
228
232
|
response.next();
|
|
229
233
|
return map;
|
|
230
234
|
}
|
|
231
235
|
catch (err) {
|
|
232
|
-
await (0, tools_js_1.
|
|
236
|
+
await (0, tools_js_1.reportCommandError)(connection, err);
|
|
233
237
|
// If SELECT/EXAMINE fails while a mailbox was already selected, we must
|
|
234
238
|
// reset to AUTHENTICATED state since the server has implicitly deselected
|
|
235
239
|
// the previous mailbox on failure (RFC 3501 Section 6.3.1).
|
|
@@ -239,10 +243,9 @@ async function select(connection, pathInput, options) {
|
|
|
239
243
|
connection.currentSelectCommand = false;
|
|
240
244
|
connection.state = connection.states.AUTHENTICATED;
|
|
241
245
|
if (currentMailbox) {
|
|
242
|
-
|
|
246
|
+
(0, tools_js_1.emitSafe)(connection, 'mailboxClose', currentMailbox);
|
|
243
247
|
}
|
|
244
248
|
}
|
|
245
|
-
connection.log.warn({ err, cid: connection.id });
|
|
246
249
|
throw err;
|
|
247
250
|
}
|
|
248
251
|
}
|
|
@@ -6,19 +6,18 @@ const status_fields_js_1 = require("./status-fields.js");
|
|
|
6
6
|
// STATUS fields that also refresh the live mailbox state when the queried mailbox is the
|
|
7
7
|
// currently selected one. Keyed by the output property name parseStatusList() reports.
|
|
8
8
|
const MAILBOX_UPDATERS = {
|
|
9
|
-
messages: (value, connection, path) => {
|
|
10
|
-
let mailbox = connection.mailbox;
|
|
9
|
+
messages: (value, mailbox, connection, path) => {
|
|
11
10
|
let prevCount = mailbox.exists;
|
|
12
11
|
if (prevCount !== value) {
|
|
13
12
|
mailbox.exists = value;
|
|
14
|
-
|
|
13
|
+
(0, tools_js_1.emitSafe)(connection, 'exists', { path, count: value, prevCount });
|
|
15
14
|
}
|
|
16
15
|
},
|
|
17
|
-
uidNext: (value,
|
|
18
|
-
|
|
16
|
+
uidNext: (value, mailbox) => {
|
|
17
|
+
mailbox.uidNext = value;
|
|
19
18
|
},
|
|
20
|
-
highestModseq: (value,
|
|
21
|
-
|
|
19
|
+
highestModseq: (value, mailbox) => {
|
|
20
|
+
mailbox.highestModseq = value;
|
|
22
21
|
}
|
|
23
22
|
};
|
|
24
23
|
/**
|
|
@@ -31,7 +30,7 @@ const MAILBOX_UPDATERS = {
|
|
|
31
30
|
* @throws {Error} If the mailbox does not exist
|
|
32
31
|
*/
|
|
33
32
|
async function status(connection, path, query) {
|
|
34
|
-
if (!
|
|
33
|
+
if (!(0, tools_js_1.isAuthenticatedState)(connection) || !path) {
|
|
35
34
|
// nothing to do here
|
|
36
35
|
return false;
|
|
37
36
|
}
|
|
@@ -62,7 +61,8 @@ async function status(connection, path, query) {
|
|
|
62
61
|
STATUS: async (untagged) => {
|
|
63
62
|
// If querying the currently selected mailbox, also update the
|
|
64
63
|
// connection's live mailbox state and emit events for changes.
|
|
65
|
-
let
|
|
64
|
+
let selected = (0, tools_js_1.getSelectedMailbox)(connection);
|
|
65
|
+
let currentMailbox = selected && selected.path === path ? selected : false;
|
|
66
66
|
let list = untagged.attributes && Array.isArray(untagged.attributes[1]) ? untagged.attributes[1] : false;
|
|
67
67
|
if (!list) {
|
|
68
68
|
return;
|
|
@@ -70,8 +70,8 @@ async function status(connection, path, query) {
|
|
|
70
70
|
(0, status_fields_js_1.parseStatusList)(list, (key, value) => {
|
|
71
71
|
map[key] = value;
|
|
72
72
|
let updater = MAILBOX_UPDATERS[key];
|
|
73
|
-
if (
|
|
74
|
-
updater(value, connection, path);
|
|
73
|
+
if (currentMailbox && updater) {
|
|
74
|
+
updater(value, currentMailbox, connection, path);
|
|
75
75
|
}
|
|
76
76
|
});
|
|
77
77
|
}
|
|
@@ -12,7 +12,8 @@ const tools_js_1 = require("../tools.js");
|
|
|
12
12
|
* @returns True on success, false on failure or if nothing to do
|
|
13
13
|
*/
|
|
14
14
|
async function store(connection, range, flags, options) {
|
|
15
|
-
|
|
15
|
+
let mailbox = (0, tools_js_1.getSelectedMailbox)(connection);
|
|
16
|
+
if (!mailbox || !range || (options.useLabels && !connection.capabilities.has('X-GM-EXT-1'))) {
|
|
16
17
|
// nothing to do here
|
|
17
18
|
return false;
|
|
18
19
|
}
|
|
@@ -48,7 +49,7 @@ async function store(connection, range, flags, options) {
|
|
|
48
49
|
flags = (Array.isArray(flags) ? flags : [].concat(flags || []))
|
|
49
50
|
.map(flag => {
|
|
50
51
|
let formatted = (0, tools_js_1.formatFlag)(flag);
|
|
51
|
-
if (!(0, tools_js_1.canUseFlag)(
|
|
52
|
+
if (!(0, tools_js_1.canUseFlag)(mailbox, formatted) && options.operation !== 'remove') {
|
|
52
53
|
return false;
|
|
53
54
|
}
|
|
54
55
|
return formatted;
|
|
@@ -65,7 +66,7 @@ async function store(connection, range, flags, options) {
|
|
|
65
66
|
];
|
|
66
67
|
// CONDSTORE (RFC 7162): UNCHANGEDSINCE modifier prevents updating messages whose
|
|
67
68
|
// mod-sequence is higher than the specified value, avoiding overwriting concurrent changes.
|
|
68
|
-
if (options.unchangedSince && connection.enabled.has('CONDSTORE') && !
|
|
69
|
+
if (options.unchangedSince && connection.enabled.has('CONDSTORE') && !mailbox.noModseq) {
|
|
69
70
|
attributes.push([
|
|
70
71
|
{
|
|
71
72
|
type: 'ATOM',
|
|
@@ -84,8 +85,7 @@ async function store(connection, range, flags, options) {
|
|
|
84
85
|
return true;
|
|
85
86
|
}
|
|
86
87
|
catch (err) {
|
|
87
|
-
await (0, tools_js_1.
|
|
88
|
-
connection.log.warn({ err, cid: connection.id });
|
|
88
|
+
await (0, tools_js_1.reportCommandError)(connection, err);
|
|
89
89
|
return false;
|
|
90
90
|
}
|
|
91
91
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.default = subscribe;
|
|
4
|
-
const
|
|
4
|
+
const subscription_js_1 = require("./subscription.js");
|
|
5
5
|
/**
|
|
6
6
|
* Subscribes to a mailbox.
|
|
7
7
|
*
|
|
@@ -10,22 +10,7 @@ const tools_js_1 = require("../tools.js");
|
|
|
10
10
|
* @returns True on success, false on failure, or undefined if preconditions not met
|
|
11
11
|
*/
|
|
12
12
|
async function subscribe(connection, path) {
|
|
13
|
-
|
|
14
|
-
// nothing to do here
|
|
15
|
-
return;
|
|
16
|
-
}
|
|
17
|
-
path = (0, tools_js_1.normalizePath)(connection, path);
|
|
18
|
-
let response;
|
|
19
|
-
try {
|
|
20
|
-
response = await connection.exec('SUBSCRIBE', [{ type: 'ATOM', value: (0, tools_js_1.encodePath)(connection, path) }]);
|
|
21
|
-
response.next();
|
|
22
|
-
return true;
|
|
23
|
-
}
|
|
24
|
-
catch (err) {
|
|
25
|
-
await (0, tools_js_1.enhanceCommandError)(err);
|
|
26
|
-
connection.log.warn({ err, cid: connection.id });
|
|
27
|
-
return false;
|
|
28
|
-
}
|
|
13
|
+
return await (0, subscription_js_1.setSubscription)(connection, 'SUBSCRIBE', path);
|
|
29
14
|
}
|
|
30
15
|
module.exports = exports.default;
|
|
31
16
|
Object.defineProperty(module.exports, 'default', { value: exports.default, enumerable: false, writable: true, configurable: true });
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ImapFlow } from '../imap-flow.js';
|
|
2
|
+
/**
|
|
3
|
+
* Runs SUBSCRIBE or UNSUBSCRIBE for a mailbox, the shared body of the two commands.
|
|
4
|
+
*
|
|
5
|
+
* @param connection - IMAP connection instance
|
|
6
|
+
* @param command - SUBSCRIBE or UNSUBSCRIBE
|
|
7
|
+
* @param path - Mailbox path
|
|
8
|
+
* @returns True on success, false on failure, or undefined if preconditions not met
|
|
9
|
+
*/
|
|
10
|
+
export declare function setSubscription(connection: ImapFlow, command: 'SUBSCRIBE' | 'UNSUBSCRIBE', path: string | string[]): Promise<boolean | undefined>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.setSubscription = setSubscription;
|
|
4
|
+
const tools_js_1 = require("../tools.js");
|
|
5
|
+
/**
|
|
6
|
+
* Runs SUBSCRIBE or UNSUBSCRIBE for a mailbox, the shared body of the two commands.
|
|
7
|
+
*
|
|
8
|
+
* @param connection - IMAP connection instance
|
|
9
|
+
* @param command - SUBSCRIBE or UNSUBSCRIBE
|
|
10
|
+
* @param path - Mailbox path
|
|
11
|
+
* @returns True on success, false on failure, or undefined if preconditions not met
|
|
12
|
+
*/
|
|
13
|
+
async function setSubscription(connection, command, path) {
|
|
14
|
+
if (!(0, tools_js_1.isAuthenticatedState)(connection)) {
|
|
15
|
+
// nothing to do here
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
path = (0, tools_js_1.normalizePath)(connection, path);
|
|
19
|
+
let response;
|
|
20
|
+
try {
|
|
21
|
+
response = await connection.exec(command, [{ type: 'ATOM', value: (0, tools_js_1.encodePath)(connection, path) }]);
|
|
22
|
+
response.next();
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
await (0, tools_js_1.reportCommandError)(connection, err);
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.default = unsubscribe;
|
|
4
|
-
const
|
|
4
|
+
const subscription_js_1 = require("./subscription.js");
|
|
5
5
|
/**
|
|
6
6
|
* Unsubscribes from a mailbox.
|
|
7
7
|
*
|
|
@@ -10,22 +10,7 @@ const tools_js_1 = require("../tools.js");
|
|
|
10
10
|
* @returns True on success, false on failure, or undefined if preconditions not met
|
|
11
11
|
*/
|
|
12
12
|
async function unsubscribe(connection, path) {
|
|
13
|
-
|
|
14
|
-
// nothing to do here
|
|
15
|
-
return;
|
|
16
|
-
}
|
|
17
|
-
path = (0, tools_js_1.normalizePath)(connection, path);
|
|
18
|
-
let response;
|
|
19
|
-
try {
|
|
20
|
-
response = await connection.exec('UNSUBSCRIBE', [{ type: 'ATOM', value: (0, tools_js_1.encodePath)(connection, path) }]);
|
|
21
|
-
response.next();
|
|
22
|
-
return true;
|
|
23
|
-
}
|
|
24
|
-
catch (err) {
|
|
25
|
-
await (0, tools_js_1.enhanceCommandError)(err);
|
|
26
|
-
connection.log.warn({ err, cid: connection.id });
|
|
27
|
-
return false;
|
|
28
|
-
}
|
|
13
|
+
return await (0, subscription_js_1.setSubscription)(connection, 'UNSUBSCRIBE', path);
|
|
29
14
|
}
|
|
30
15
|
module.exports = exports.default;
|
|
31
16
|
Object.defineProperty(module.exports, 'default', { value: exports.default, enumerable: false, writable: true, configurable: true });
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ImapFlow } from './imap-flow.js';
|
|
2
|
+
import type { DownloadManyOptions, DownloadManyResult, DownloadNotFound, DownloadObject, DownloadOptions, SequenceString } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Implements ImapFlow.download(), see its documentation
|
|
5
|
+
*
|
|
6
|
+
* @param client - Connection to download from
|
|
7
|
+
* @param range - UID or sequence number of the message
|
|
8
|
+
* @param part - Body part to download, the whole message when not set
|
|
9
|
+
* @param options - Download options
|
|
10
|
+
* @returns The download, or an empty object when there is nothing to download
|
|
11
|
+
*/
|
|
12
|
+
export declare function downloadMessage(client: ImapFlow, range: SequenceString, part?: string | undefined, options?: DownloadOptions | undefined): Promise<DownloadObject | DownloadNotFound>;
|
|
13
|
+
/**
|
|
14
|
+
* Implements ImapFlow.downloadMany(), see its documentation
|
|
15
|
+
*
|
|
16
|
+
* @param client - Connection to download from
|
|
17
|
+
* @param range - UID or sequence number of the message
|
|
18
|
+
* @param parts - Body parts to download
|
|
19
|
+
* @param options - Download options
|
|
20
|
+
* @returns Downloaded parts keyed by part number
|
|
21
|
+
*/
|
|
22
|
+
export declare function downloadMessageParts(client: ImapFlow, range: SequenceString, parts: string[], options?: DownloadManyOptions | undefined): Promise<DownloadManyResult>;
|