imapflow 2.0.8 → 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 +20 -0
- package/dist/cjs/commands/list.js +20 -16
- package/dist/cjs/commands/select.js +7 -3
- package/dist/cjs/errors.d.ts +48 -1
- package/dist/cjs/errors.js +53 -1
- package/dist/cjs/handler/imap-stream.d.ts +13 -2
- package/dist/cjs/handler/imap-stream.js +47 -26
- package/dist/cjs/handler/token-parser.js +14 -8
- package/dist/cjs/imap-flow.d.ts +14 -77
- package/dist/cjs/imap-flow.js +35 -4
- package/dist/cjs/package-info.d.ts +1 -1
- package/dist/cjs/package-info.js +1 -1
- package/dist/cjs/tools.d.ts +1 -1
- package/dist/cjs/tools.js +9 -8
- package/dist/esm/commands/list.js +20 -16
- package/dist/esm/commands/select.js +7 -3
- package/dist/esm/errors.d.ts +48 -1
- package/dist/esm/errors.js +52 -0
- package/dist/esm/handler/imap-stream.d.ts +13 -2
- package/dist/esm/handler/imap-stream.js +47 -26
- package/dist/esm/handler/token-parser.js +14 -8
- package/dist/esm/imap-flow.d.ts +14 -77
- package/dist/esm/imap-flow.js +34 -4
- package/dist/esm/package-info.d.ts +1 -1
- package/dist/esm/package-info.js +1 -1
- package/dist/esm/tools.d.ts +1 -1
- package/dist/esm/tools.js +7 -6
- package/package.json +2 -2
package/dist/esm/imap-flow.js
CHANGED
|
@@ -17,7 +17,7 @@ import { downloadMessage, downloadMessageParts } from './download.js';
|
|
|
17
17
|
import { AuthenticationFailure } from './errors.js';
|
|
18
18
|
import imapCommands from './imap-commands.js';
|
|
19
19
|
import { comparePaths, updateCapabilities, getFolderTree, formatMessageResponse, packMessageRange, normalizePath, expandRange, getColorFlags, hasCapability, isRev2Active, logConnectionError, unrefTimer, clearTimer, parseUintValue, getStringList, getTextValues, emitSafe, buildConnectionError, guardedPromise, guardedReject, MAX_UINT32_DIGITS } from './tools.js';
|
|
20
|
-
export { AuthenticationFailure } from './errors.js';
|
|
20
|
+
export { AuthenticationFailure, ImapFlowErrorCode } from './errors.js';
|
|
21
21
|
const GREETING_TIMEOUT = 16 * 1000;
|
|
22
22
|
const UPGRADE_TIMEOUT = 10 * 1000;
|
|
23
23
|
const SOCKET_TIMEOUT = 5 * 60 * 1000;
|
|
@@ -1561,6 +1561,7 @@ export class ImapFlow extends EventEmitter {
|
|
|
1561
1561
|
/** @internal */
|
|
1562
1562
|
beginSession(onUnhandledError) {
|
|
1563
1563
|
clearTimer(this.greetingTimeout);
|
|
1564
|
+
this.greetingReceived = true;
|
|
1564
1565
|
this.untaggedHandlers.OK = null;
|
|
1565
1566
|
this.untaggedHandlers.PREAUTH = null;
|
|
1566
1567
|
if (this.isClosed) {
|
|
@@ -1620,6 +1621,12 @@ export class ImapFlow extends EventEmitter {
|
|
|
1620
1621
|
this.byeReason = reason || 'Server closed connection';
|
|
1621
1622
|
this.untaggedHandlers.BYE = null;
|
|
1622
1623
|
this.state = this.states.LOGOUT;
|
|
1624
|
+
// A BYE greeting rejects the connection outright. Do not wait for the server to close
|
|
1625
|
+
// the socket: one that keeps it open would leave connect() pending until the greeting
|
|
1626
|
+
// timeout.
|
|
1627
|
+
if (!this.greetingReceived) {
|
|
1628
|
+
this.closeAfter();
|
|
1629
|
+
}
|
|
1623
1630
|
}
|
|
1624
1631
|
// Drops every capability-derived field together - the counterpart of
|
|
1625
1632
|
// updateCapabilitiesFromRaw() below, which sets them together. rawCapabilities is
|
|
@@ -1852,7 +1859,7 @@ export class ImapFlow extends EventEmitter {
|
|
|
1852
1859
|
/** @internal */
|
|
1853
1860
|
autoidle() {
|
|
1854
1861
|
clearTimer(this.idleStartTimer);
|
|
1855
|
-
if (this.options.disableAutoIdle || this.state !== this.states.SELECTED) {
|
|
1862
|
+
if (this.options.disableAutoIdle || !this.usable || this.state !== this.states.SELECTED) {
|
|
1856
1863
|
return;
|
|
1857
1864
|
}
|
|
1858
1865
|
if (this.connectionBusy()) {
|
|
@@ -1864,7 +1871,7 @@ export class ImapFlow extends EventEmitter {
|
|
|
1864
1871
|
// missed clearTimeout would inject IDLE between a caller's own commands. Declining
|
|
1865
1872
|
// postpones rather than cancels: whatever made the connection busy calls autoidle()
|
|
1866
1873
|
// again when it finishes.
|
|
1867
|
-
if (this.state !== this.states.SELECTED || this.connectionBusy()) {
|
|
1874
|
+
if (!this.usable || this.state !== this.states.SELECTED || this.connectionBusy()) {
|
|
1868
1875
|
return;
|
|
1869
1876
|
}
|
|
1870
1877
|
this.idle().catch(err => logConnectionError(this, 'Auto-IDLE failed', err));
|
|
@@ -3349,7 +3356,8 @@ export class ImapFlow extends EventEmitter {
|
|
|
3349
3356
|
}
|
|
3350
3357
|
/**
|
|
3351
3358
|
* Detaches sockets from the IMAP pipeline. Useful for upgrading the connection
|
|
3352
|
-
* (e.g., STARTTLS) or transferring socket ownership.
|
|
3359
|
+
* (e.g., STARTTLS) or transferring socket ownership. Call it while the connection is not
|
|
3360
|
+
* idling: an IDLE in progress is not broken first, so the server still expects `DONE`.
|
|
3353
3361
|
*
|
|
3354
3362
|
* @returns Socket objects: `readSocket` is the read socket (inflated socket if compression is enabled, raw socket otherwise),
|
|
3355
3363
|
* `writeSocket` the write socket and `socket` the raw underlying socket (same as readSocket/writeSocket when compression is disabled)
|
|
@@ -3364,6 +3372,11 @@ export class ImapFlow extends EventEmitter {
|
|
|
3364
3372
|
// compression is active, the PassThrough writeSocket - so the connection
|
|
3365
3373
|
// is fully released to the caller.
|
|
3366
3374
|
this.clearSocketHandlers();
|
|
3375
|
+
// The socket now belongs to the caller. Marking the client unusable keeps
|
|
3376
|
+
// auto-IDLE (armed now, or re-armed by a lock release or a finished download)
|
|
3377
|
+
// and a later dispose from writing IDLE or LOGOUT onto it.
|
|
3378
|
+
this.usable = false;
|
|
3379
|
+
clearTimer(this.idleStartTimer);
|
|
3367
3380
|
const readSocket = this._inflate || socket;
|
|
3368
3381
|
const writeSocket = this.writeSocket || socket;
|
|
3369
3382
|
// Defense-in-depth: when compression is active the raw socket is orphaned
|
|
@@ -3461,6 +3474,23 @@ export class ImapFlow extends EventEmitter {
|
|
|
3461
3474
|
* console.log(`${entry.cid} ${entry.msg}`);
|
|
3462
3475
|
* });
|
|
3463
3476
|
*/
|
|
3477
|
+
// Installed outside the class body: a computed `[Symbol.asyncDispose]` key would turn into a
|
|
3478
|
+
// method named "undefined" on Node.js 20.0-20.3, which predate the symbol
|
|
3479
|
+
if (typeof Symbol.asyncDispose === 'symbol') {
|
|
3480
|
+
ImapFlow.prototype[Symbol.asyncDispose] = async function () {
|
|
3481
|
+
if (this.usable) {
|
|
3482
|
+
try {
|
|
3483
|
+
await this.logout();
|
|
3484
|
+
}
|
|
3485
|
+
catch (err) {
|
|
3486
|
+
logConnectionError(this, 'LOGOUT failed while disposing', err);
|
|
3487
|
+
}
|
|
3488
|
+
}
|
|
3489
|
+
// logout() already closes the connection; close() is idempotent and covers a client
|
|
3490
|
+
// that never connected or whose logout was skipped
|
|
3491
|
+
this.close();
|
|
3492
|
+
};
|
|
3493
|
+
}
|
|
3464
3494
|
// Both `import { ImapFlow } from 'imapflow'` and `import imapflow from 'imapflow'` work, the
|
|
3465
3495
|
// latter matching the shape `require('imapflow')` has always had
|
|
3466
3496
|
const imapflow = { ImapFlow, AuthenticationFailure };
|
package/dist/esm/package-info.js
CHANGED
package/dist/esm/tools.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Transform } from 'node:stream';
|
|
2
2
|
import type { ImapFlow } from './imap-flow.js';
|
|
3
|
-
import type
|
|
3
|
+
import { type ConnectionErrorSite, type ImapFlowError } from './errors.js';
|
|
4
4
|
import type { ImapAttributeList, ImapAttributeNode, ImapResponse } from './handler/types.js';
|
|
5
5
|
import type { FetchMessageObject, ListResponse, ListTreeResponse, MailboxObject, MessageEnvelopeObject, MessageStructureObject, ImapFlowEvents, StatusQuery } from './types.js';
|
|
6
6
|
export { AuthenticationFailure } from './errors.js';
|
package/dist/esm/tools.js
CHANGED
|
@@ -5,10 +5,11 @@ import { compiler } from './handler/imap-handler.js';
|
|
|
5
5
|
import { createHash } from 'node:crypto';
|
|
6
6
|
import { JPDecoder } from './jp-decoder.js';
|
|
7
7
|
import iconv from 'iconv-lite';
|
|
8
|
+
import { ImapFlowErrorCode } from './errors.js';
|
|
8
9
|
export { AuthenticationFailure } from './errors.js';
|
|
9
10
|
const FLAG_COLORS = ['red', 'orange', 'yellow', 'green', 'blue', 'purple', 'grey'];
|
|
10
11
|
// Error codes that only mean the connection is no longer usable. See logConnectionError().
|
|
11
|
-
const CONNECTION_GONE_CODES = new Set([
|
|
12
|
+
const CONNECTION_GONE_CODES = new Set([ImapFlowErrorCode.NoConnection, ImapFlowErrorCode.EConnectionClosed, ImapFlowErrorCode.StateLogout]);
|
|
12
13
|
// Upper bound for expanding server-supplied sequence ranges (see expandRange). 2^24
|
|
13
14
|
// entries in total is far beyond any legitimate mailbox while keeping the worst-case
|
|
14
15
|
// expansion of a hostile range set bounded.
|
|
@@ -1092,7 +1093,7 @@ export function parseBodystructure(entry) {
|
|
|
1092
1093
|
curNode.type = 'multipart/' + ((node[i++] || {}).value || '').toString().toLowerCase();
|
|
1093
1094
|
// extension data (not available for BODY requests)
|
|
1094
1095
|
// body parameter parenthesized list
|
|
1095
|
-
if (i < node.length
|
|
1096
|
+
if (i < node.length) {
|
|
1096
1097
|
if (node[i]) {
|
|
1097
1098
|
curNode.parameters = getStructuredParams(node[i]);
|
|
1098
1099
|
}
|
|
@@ -1174,7 +1175,7 @@ export function parseBodystructure(entry) {
|
|
|
1174
1175
|
}
|
|
1175
1176
|
// extension data (not available for BODY requests)
|
|
1176
1177
|
// md5
|
|
1177
|
-
if (i < node.length
|
|
1178
|
+
if (i < node.length) {
|
|
1178
1179
|
if (node[i]) {
|
|
1179
1180
|
curNode.md5 = (node[i].value || '').toString().toLowerCase();
|
|
1180
1181
|
}
|
|
@@ -1184,7 +1185,7 @@ export function parseBodystructure(entry) {
|
|
|
1184
1185
|
// the following are shared extension values (for both multipart and non-multipart parts)
|
|
1185
1186
|
// not available for BODY requests
|
|
1186
1187
|
// body disposition
|
|
1187
|
-
if (i < node.length
|
|
1188
|
+
if (i < node.length) {
|
|
1188
1189
|
let disposition = node[i];
|
|
1189
1190
|
if (Array.isArray(disposition) && disposition.length) {
|
|
1190
1191
|
curNode.disposition = ((disposition[0] && disposition[0].value) || '').toString().toLowerCase();
|
|
@@ -1195,7 +1196,7 @@ export function parseBodystructure(entry) {
|
|
|
1195
1196
|
i++;
|
|
1196
1197
|
}
|
|
1197
1198
|
// body language
|
|
1198
|
-
if (i < node.length
|
|
1199
|
+
if (i < node.length) {
|
|
1199
1200
|
if (node[i]) {
|
|
1200
1201
|
/* c8 ignore next */ // node[i] is truthy inside this guard, so the [] fallback is unreachable
|
|
1201
1202
|
curNode.language = [].concat(node[i] || []).map(val => ((val && val.value) || '').toString().toLowerCase());
|
|
@@ -1205,7 +1206,7 @@ export function parseBodystructure(entry) {
|
|
|
1205
1206
|
// body location
|
|
1206
1207
|
// NB! defined as a "string list" in RFC3501 but replaced in errata document with "string"
|
|
1207
1208
|
// Errata: http://www.rfc-editor.org/errata_search.php?rfc=3501
|
|
1208
|
-
if (i < node.length
|
|
1209
|
+
if (i < node.length) {
|
|
1209
1210
|
if (node[i]) {
|
|
1210
1211
|
curNode.location = (node[i].value || '').toString();
|
|
1211
1212
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "imapflow",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "IMAP Client for Node",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/cjs/imap-flow.js",
|
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
"types-node-legacy": "npm:@types/node@20.0.0",
|
|
79
79
|
"typescript": "6.0.3",
|
|
80
80
|
"typescript-eslint": "8.70.1",
|
|
81
|
-
"wrangler": "4.
|
|
81
|
+
"wrangler": "4.142.0"
|
|
82
82
|
},
|
|
83
83
|
"dependencies": {
|
|
84
84
|
"@zone-eu/mailsplit": "5.4.17",
|