imapflow 2.5.8 → 2.6.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 +26 -0
- package/README.md +9 -0
- package/dist/cjs/commands/append.js +6 -3
- package/dist/cjs/commands/fetch.d.ts +2 -1
- package/dist/cjs/commands/fetch.js +8 -2
- package/dist/cjs/commands/idle.js +7 -0
- package/dist/cjs/commands/select.js +17 -6
- package/dist/cjs/commands/status.js +19 -5
- package/dist/cjs/download.js +3 -3
- package/dist/cjs/errors.d.ts +3 -1
- package/dist/cjs/errors.js +4 -1
- package/dist/cjs/handler/imap-parser.js +38 -6
- package/dist/cjs/handler/limits.d.ts +1 -0
- package/dist/cjs/handler/limits.js +8 -1
- package/dist/cjs/handler/token-parser.d.ts +8 -2
- package/dist/cjs/handler/token-parser.js +55 -16
- package/dist/cjs/handler/types.d.ts +5 -2
- package/dist/cjs/imap-flow.d.ts +38 -2
- package/dist/cjs/imap-flow.js +99 -15
- package/dist/cjs/package-info.d.ts +1 -1
- package/dist/cjs/package-info.js +1 -1
- package/dist/cjs/types.d.ts +51 -7
- package/dist/esm/commands/append.js +6 -3
- package/dist/esm/commands/fetch.d.ts +2 -1
- package/dist/esm/commands/fetch.js +8 -2
- package/dist/esm/commands/idle.js +7 -0
- package/dist/esm/commands/select.js +17 -6
- package/dist/esm/commands/status.js +19 -5
- package/dist/esm/download.js +3 -3
- package/dist/esm/errors.d.ts +3 -1
- package/dist/esm/errors.js +4 -1
- package/dist/esm/handler/imap-parser.js +38 -6
- package/dist/esm/handler/limits.d.ts +1 -0
- package/dist/esm/handler/limits.js +7 -0
- package/dist/esm/handler/token-parser.d.ts +8 -2
- package/dist/esm/handler/token-parser.js +56 -17
- package/dist/esm/handler/types.d.ts +5 -2
- package/dist/esm/imap-flow.d.ts +38 -2
- package/dist/esm/imap-flow.js +99 -15
- package/dist/esm/package-info.d.ts +1 -1
- package/dist/esm/package-info.js +1 -1
- package/dist/esm/types.d.ts +51 -7
- package/package.json +3 -3
package/dist/esm/imap-flow.js
CHANGED
|
@@ -168,6 +168,18 @@ export class ImapFlow extends EventEmitter {
|
|
|
168
168
|
* Current module version as a static class property
|
|
169
169
|
*/
|
|
170
170
|
static { this.version = packageInfo.version; }
|
|
171
|
+
/**
|
|
172
|
+
* The mailboxes a `verifyOnly` connection with `includeMailboxes` listed before it logged out,
|
|
173
|
+
* `undefined` otherwise
|
|
174
|
+
*
|
|
175
|
+
* @example
|
|
176
|
+
* let client = new ImapFlow({ ..., verifyOnly: true, includeMailboxes: true });
|
|
177
|
+
* await client.connect();
|
|
178
|
+
* console.log(client.mailboxList.map(mailbox => mailbox.path));
|
|
179
|
+
*/
|
|
180
|
+
get mailboxList() {
|
|
181
|
+
return this._mailboxList;
|
|
182
|
+
}
|
|
171
183
|
/**
|
|
172
184
|
* Creates a client for one IMAP connection. Nothing is sent before `connect()` is called
|
|
173
185
|
*/
|
|
@@ -219,6 +231,7 @@ export class ImapFlow extends EventEmitter {
|
|
|
219
231
|
this._throttleWaits = new Set();
|
|
220
232
|
this._upgradeReject = null;
|
|
221
233
|
this.isClosed = false;
|
|
234
|
+
this._errorReported = false;
|
|
222
235
|
this.states = states;
|
|
223
236
|
this.state = this.states.NOT_AUTHENTICATED;
|
|
224
237
|
this.lockCounter = 0;
|
|
@@ -243,6 +256,9 @@ export class ImapFlow extends EventEmitter {
|
|
|
243
256
|
this.mailbox = false;
|
|
244
257
|
this.currentSelectCommand = false;
|
|
245
258
|
this.idling = false;
|
|
259
|
+
this.context = this.options.context;
|
|
260
|
+
this.connectedAt = null;
|
|
261
|
+
this.lastClientWrite = null;
|
|
246
262
|
this.emitLogs = !!this.options.emitLogs;
|
|
247
263
|
this.lo = 0;
|
|
248
264
|
this.untaggedHandlers = {};
|
|
@@ -288,6 +304,15 @@ export class ImapFlow extends EventEmitter {
|
|
|
288
304
|
return;
|
|
289
305
|
}
|
|
290
306
|
err._connId = err._connId || this.id;
|
|
307
|
+
// One error per connection: emitError() closes the connection, and until the deferred
|
|
308
|
+
// close() runs a second socket, deflate or parser error may still arrive. Emitting it as
|
|
309
|
+
// well would reach a consumer that removed its listener after the first one, or one that
|
|
310
|
+
// only awaited connect(), as an unhandled 'error' that throws.
|
|
311
|
+
if (this._errorReported) {
|
|
312
|
+
this.log.debug({ msg: 'Suppressed error after the connection already reported one', err, cid: this.id });
|
|
313
|
+
this.closeAfter();
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
291
316
|
// During a STARTTLS handshake the upgrade owns the single error path (its settle()
|
|
292
317
|
// helper). Route the error there so a streamer-originated failure is surfaced with its
|
|
293
318
|
// real code (instead of a generic ClosedAfterConnect*) and cannot hang a verifyOnly
|
|
@@ -298,6 +323,7 @@ export class ImapFlow extends EventEmitter {
|
|
|
298
323
|
this._upgradeReject = null;
|
|
299
324
|
if (typeof reject === 'function') {
|
|
300
325
|
// settle() clears the upgrade timer and flags, and closes the connection
|
|
326
|
+
this._errorReported = true;
|
|
301
327
|
reject(err);
|
|
302
328
|
return;
|
|
303
329
|
}
|
|
@@ -312,10 +338,12 @@ export class ImapFlow extends EventEmitter {
|
|
|
312
338
|
let reject = this.initialReject;
|
|
313
339
|
this.initialResolve = false;
|
|
314
340
|
this.initialReject = false;
|
|
341
|
+
this._errorReported = true;
|
|
315
342
|
this.closeAfter();
|
|
316
343
|
reject(err);
|
|
317
344
|
return;
|
|
318
345
|
}
|
|
346
|
+
this._errorReported = true;
|
|
319
347
|
this.closeAfter();
|
|
320
348
|
this.emit('error', err);
|
|
321
349
|
}
|
|
@@ -369,6 +397,7 @@ export class ImapFlow extends EventEmitter {
|
|
|
369
397
|
else {
|
|
370
398
|
return false;
|
|
371
399
|
}
|
|
400
|
+
this.lastClientWrite = Date.now();
|
|
372
401
|
for (let data of frames) {
|
|
373
402
|
if (this.logRaw) {
|
|
374
403
|
// Client frames of an authentication exchange carry credentials: the LOGIN
|
|
@@ -827,9 +856,17 @@ export class ImapFlow extends EventEmitter {
|
|
|
827
856
|
async handleResponse(data) {
|
|
828
857
|
let parsed;
|
|
829
858
|
try {
|
|
830
|
-
parsed = await parser(data.payload, { literals: data.literals });
|
|
859
|
+
parsed = await parser(data.payload, { literals: data.literals, maxResponseTokens: this.options.maxResponseTokens });
|
|
831
860
|
}
|
|
832
861
|
catch (err) {
|
|
862
|
+
if (err.code === 'TooManyTokens') {
|
|
863
|
+
// A size limit, so as terminal as the ones ImapStream enforces: the server is
|
|
864
|
+
// flooding responses, and skipping the line would only invite the next one
|
|
865
|
+
this.log.error({ msg: 'Response exceeded the token limit', payloadBytes: data.payload.length, err, cid: this.id });
|
|
866
|
+
this.rejectCurrentRequest(err);
|
|
867
|
+
this.failProtocol(err);
|
|
868
|
+
return false;
|
|
869
|
+
}
|
|
833
870
|
// can not make sense of this. The payload can be up to the configured line
|
|
834
871
|
// cap (1GB by default), so log only a bounded prefix: a server looping
|
|
835
872
|
// unparseable garbage would otherwise turn this error log into a disk filler.
|
|
@@ -1251,7 +1288,9 @@ export class ImapFlow extends EventEmitter {
|
|
|
1251
1288
|
}
|
|
1252
1289
|
});
|
|
1253
1290
|
const socket = this.socket;
|
|
1254
|
-
|
|
1291
|
+
// on(), not once(): with compression the deflate and writeSocket errors are forwarded
|
|
1292
|
+
// onto this socket, and a second one before close() must not find it without a listener
|
|
1293
|
+
socket.on('error', this._socketError);
|
|
1255
1294
|
socket.once('close', this._socketClose);
|
|
1256
1295
|
socket.once('end', this._socketEnd);
|
|
1257
1296
|
socket.on('tlsClientError', this._socketError);
|
|
@@ -2230,6 +2269,7 @@ export class ImapFlow extends EventEmitter {
|
|
|
2230
2269
|
}
|
|
2231
2270
|
try {
|
|
2232
2271
|
clearTimer(this.connectTimeout);
|
|
2272
|
+
this.connectedAt = Date.now();
|
|
2233
2273
|
// ImapFlow now owns the socket; drop the proxy's early error handler
|
|
2234
2274
|
// (its "before connection setup" message no longer applies).
|
|
2235
2275
|
detachEarlyErrorHandler(socket);
|
|
@@ -2355,6 +2395,15 @@ export class ImapFlow extends EventEmitter {
|
|
|
2355
2395
|
}
|
|
2356
2396
|
return error;
|
|
2357
2397
|
}
|
|
2398
|
+
// What a message command called without a selected mailbox rejects with: NoMailboxSelected,
|
|
2399
|
+
// or NoConnection once the connection is gone, as that is why the mailbox is missing then
|
|
2400
|
+
/** @internal */
|
|
2401
|
+
createNoMailboxError(command) {
|
|
2402
|
+
if (!this.usable) {
|
|
2403
|
+
return this.createNoConnectionError(this.byeReason, { rejectedFrom: 'noMailbox', command });
|
|
2404
|
+
}
|
|
2405
|
+
return createImapError('No mailbox is selected', 'NoMailboxSelected', { command });
|
|
2406
|
+
}
|
|
2358
2407
|
/**
|
|
2359
2408
|
* Closes TCP connection without notifying the server.
|
|
2360
2409
|
*
|
|
@@ -2795,8 +2844,14 @@ export class ImapFlow extends EventEmitter {
|
|
|
2795
2844
|
// LIST. This sets mailboxMissing on the error so the caller can distinguish
|
|
2796
2845
|
// "doesn't exist" from other failures, for getMailboxLock() callers as well.
|
|
2797
2846
|
try {
|
|
2798
|
-
let
|
|
2799
|
-
|
|
2847
|
+
let normalized = normalizePath(this, path);
|
|
2848
|
+
let folders = await this.run('LIST', '', normalized, { listOnly: true });
|
|
2849
|
+
// The path is the LIST pattern, so a % or * in a name also matches other
|
|
2850
|
+
// mailboxes, and an entry marked \NonExistent (RFC 5258) does not exist either
|
|
2851
|
+
let exists = Array.isArray(folders) &&
|
|
2852
|
+
folders.some(entry => comparePaths(this, entry.path, normalized) &&
|
|
2853
|
+
![...(entry.flags || [])].some(flag => typeof flag === 'string' && flag.toUpperCase() === '\\NONEXISTENT'));
|
|
2854
|
+
if (!exists) {
|
|
2800
2855
|
err.mailboxMissing = true;
|
|
2801
2856
|
}
|
|
2802
2857
|
}
|
|
@@ -2839,6 +2894,9 @@ export class ImapFlow extends EventEmitter {
|
|
|
2839
2894
|
* otherwise IDLE is started by default on connection inactivity. NB! If `idle()` is called manually then it does not
|
|
2840
2895
|
* return until IDLE is finished which means you would have to call some other command out of scope.
|
|
2841
2896
|
*
|
|
2897
|
+
* Unlike auto-IDLE, a direct call does not wait for the connection to be free: a mailbox lock
|
|
2898
|
+
* holder may idle inside its own lock, and idle() can not tell it from another caller.
|
|
2899
|
+
*
|
|
2842
2900
|
* @returns `false` if IDLE failed, `undefined` otherwise
|
|
2843
2901
|
*
|
|
2844
2902
|
* @example
|
|
@@ -3092,6 +3150,9 @@ export class ImapFlow extends EventEmitter {
|
|
|
3092
3150
|
* @param query Fetch query
|
|
3093
3151
|
* @param options Fetch options
|
|
3094
3152
|
* @yields Message data object
|
|
3153
|
+
* @throws An error with the code `NoMailboxSelected` when no mailbox is selected (for example
|
|
3154
|
+
* after `mailboxClose()` or a failed `mailboxOpen()`), or `NoConnection` once the connection
|
|
3155
|
+
* is gone. Earlier releases yielded nothing in that case, as for an empty mailbox
|
|
3095
3156
|
*
|
|
3096
3157
|
* @example
|
|
3097
3158
|
* let mailbox = await client.mailboxOpen('INBOX');
|
|
@@ -3105,8 +3166,8 @@ export class ImapFlow extends EventEmitter {
|
|
|
3105
3166
|
async *fetch(range, query, options) {
|
|
3106
3167
|
options = options || {};
|
|
3107
3168
|
if (!this.mailbox) {
|
|
3108
|
-
//
|
|
3109
|
-
|
|
3169
|
+
// an empty result would look like an empty mailbox, for example right after close()
|
|
3170
|
+
throw this.createNoMailboxError('FETCH');
|
|
3110
3171
|
}
|
|
3111
3172
|
let resolved = await this.resolveRange(range, options);
|
|
3112
3173
|
if (!resolved) {
|
|
@@ -3216,6 +3277,7 @@ export class ImapFlow extends EventEmitter {
|
|
|
3216
3277
|
* @param query Fetch query
|
|
3217
3278
|
* @param options Fetch options
|
|
3218
3279
|
* @returns Array of Message data object
|
|
3280
|
+
* @throws An error with the code `NoMailboxSelected` when no mailbox is selected, see fetch()
|
|
3219
3281
|
*
|
|
3220
3282
|
* @example
|
|
3221
3283
|
* let mailbox = await client.mailboxOpen('INBOX');
|
|
@@ -3239,7 +3301,9 @@ export class ImapFlow extends EventEmitter {
|
|
|
3239
3301
|
* @param seq Single UID or sequence number of the message to fetch for
|
|
3240
3302
|
* @param query Fetch query
|
|
3241
3303
|
* @param options Fetch options
|
|
3242
|
-
* @returns Message data object
|
|
3304
|
+
* @returns Message data object, `false` when the message was not found
|
|
3305
|
+
* @throws An error with the code `NoMailboxSelected` when no mailbox is selected, see fetch().
|
|
3306
|
+
* Earlier releases resolved `undefined` then
|
|
3243
3307
|
*
|
|
3244
3308
|
* @example
|
|
3245
3309
|
* let mailbox = await client.mailboxOpen('INBOX');
|
|
@@ -3249,8 +3313,9 @@ export class ImapFlow extends EventEmitter {
|
|
|
3249
3313
|
*/
|
|
3250
3314
|
async fetchOne(seq, query, options) {
|
|
3251
3315
|
if (!this.mailbox) {
|
|
3252
|
-
//
|
|
3253
|
-
|
|
3316
|
+
// undefined used to be returned here, indistinguishable from a missing message for a
|
|
3317
|
+
// caller that only tests the result
|
|
3318
|
+
throw this.createNoMailboxError('FETCH');
|
|
3254
3319
|
}
|
|
3255
3320
|
if (seq === '*') {
|
|
3256
3321
|
if (!this.mailbox.exists) {
|
|
@@ -3428,6 +3493,9 @@ export class ImapFlow extends EventEmitter {
|
|
|
3428
3493
|
return;
|
|
3429
3494
|
}
|
|
3430
3495
|
this.processingLock = true;
|
|
3496
|
+
// The lock taken off the queue and not settled yet. A pass that throws out of its loop
|
|
3497
|
+
// rejects it, its caller would wait forever otherwise: it is in the queue no longer.
|
|
3498
|
+
let unsettled = null;
|
|
3431
3499
|
try {
|
|
3432
3500
|
// Process all locks in queue until empty
|
|
3433
3501
|
let processedCount = 0;
|
|
@@ -3444,6 +3512,7 @@ export class ImapFlow extends EventEmitter {
|
|
|
3444
3512
|
await new Promise(resolve => setImmediate(resolve));
|
|
3445
3513
|
}
|
|
3446
3514
|
const lock = this.locks.shift();
|
|
3515
|
+
unsettled = lock;
|
|
3447
3516
|
const { resolve, reject, path, options, lockId } = lock;
|
|
3448
3517
|
// From here on the grant/reject path owns the outcome; the acquire
|
|
3449
3518
|
// timer must not race with resolution.
|
|
@@ -3509,6 +3578,7 @@ export class ImapFlow extends EventEmitter {
|
|
|
3509
3578
|
};
|
|
3510
3579
|
if (!this.usable || !this.socket || this.socket.destroyed) {
|
|
3511
3580
|
this.log.trace({ msg: 'Failed to acquire mailbox lock', path, lockId, idling: this.idling });
|
|
3581
|
+
unsettled = null;
|
|
3512
3582
|
reject(this.createNoConnectionError(false, { rejectedFrom: 'mailboxLock', path }));
|
|
3513
3583
|
continue; // Process next lock in queue
|
|
3514
3584
|
}
|
|
@@ -3521,6 +3591,7 @@ export class ImapFlow extends EventEmitter {
|
|
|
3521
3591
|
this.currentLock = lock;
|
|
3522
3592
|
armHeldTimer();
|
|
3523
3593
|
this.autoidle();
|
|
3594
|
+
unsettled = null;
|
|
3524
3595
|
resolve({ path, release });
|
|
3525
3596
|
};
|
|
3526
3597
|
if (this.mailbox && this.mailbox.path === path && !!this.mailbox.readOnly === !!options.readOnly) {
|
|
@@ -3563,23 +3634,35 @@ export class ImapFlow extends EventEmitter {
|
|
|
3563
3634
|
...(options.description && { description: options.description }),
|
|
3564
3635
|
err
|
|
3565
3636
|
});
|
|
3637
|
+
unsettled = null;
|
|
3566
3638
|
reject(err);
|
|
3567
3639
|
// Continue to next lock in queue
|
|
3568
3640
|
}
|
|
3569
3641
|
}
|
|
3570
3642
|
}
|
|
3643
|
+
catch (err) {
|
|
3644
|
+
if (unsettled) {
|
|
3645
|
+
let lock = unsettled;
|
|
3646
|
+
unsettled = null;
|
|
3647
|
+
// granted but not handed out (the grant itself failed): nobody can release it
|
|
3648
|
+
if (this.currentLock === lock) {
|
|
3649
|
+
clearTimer(lock.heldWarnTimer);
|
|
3650
|
+
lock.heldWarnTimer = null;
|
|
3651
|
+
this.currentLock = false;
|
|
3652
|
+
}
|
|
3653
|
+
lock.reject(err);
|
|
3654
|
+
}
|
|
3655
|
+
throw err;
|
|
3656
|
+
}
|
|
3571
3657
|
finally {
|
|
3572
3658
|
this.processingLock = false;
|
|
3573
|
-
//
|
|
3574
|
-
//
|
|
3575
|
-
// arrived before we finished). Schedule another run if needed.
|
|
3576
|
-
/* c8 ignore start */ // requires a lock to be enqueued during an in-flight processLocks pass; not reproducible deterministically
|
|
3659
|
+
// A pass that ended with locks queued and none held (it threw out of its loop) would
|
|
3660
|
+
// leave them waiting with nothing to start another pass. Schedule one.
|
|
3577
3661
|
if (this.locks.length && !this.currentLock) {
|
|
3578
3662
|
setImmediate(() => {
|
|
3579
3663
|
this.processLocks().catch(err => this.log.error({ err, cid: this.id }));
|
|
3580
3664
|
});
|
|
3581
3665
|
}
|
|
3582
|
-
/* c8 ignore stop */
|
|
3583
3666
|
}
|
|
3584
3667
|
}
|
|
3585
3668
|
/**
|
|
@@ -3773,7 +3856,8 @@ export class ImapFlow extends EventEmitter {
|
|
|
3773
3856
|
*/
|
|
3774
3857
|
/**
|
|
3775
3858
|
* Error event. In most cases getting an error event also means that connection is closed
|
|
3776
|
-
* and pending operations should return with a failure.
|
|
3859
|
+
* and pending operations should return with a failure. Emitted at most once per connection,
|
|
3860
|
+
* later errors while the connection is closing are only logged.
|
|
3777
3861
|
*
|
|
3778
3862
|
* @event ImapFlow#error
|
|
3779
3863
|
* @example
|
package/dist/esm/package-info.js
CHANGED
package/dist/esm/types.d.ts
CHANGED
|
@@ -76,8 +76,13 @@ export interface ImapFlowOptions {
|
|
|
76
76
|
emitLogs?: boolean | undefined;
|
|
77
77
|
/** If true, then logs out automatically after successful authentication */
|
|
78
78
|
verifyOnly?: boolean | undefined;
|
|
79
|
-
/** If true and verifyOnly is set, lists mailboxes */
|
|
79
|
+
/** If true and verifyOnly is set, lists mailboxes. The listing is in `client.mailboxList` once `connect()` resolved */
|
|
80
80
|
includeMailboxes?: boolean | undefined;
|
|
81
|
+
/**
|
|
82
|
+
* Data of the application's own to keep with the client, such as the account the connection
|
|
83
|
+
* belongs to. ImapFlow never reads it, it is the initial value of `client.context`
|
|
84
|
+
*/
|
|
85
|
+
context?: unknown;
|
|
81
86
|
/**
|
|
82
87
|
* Proxy URL. Supports HTTP CONNECT (http:, https:) and SOCKS (socks:, socks4:, socks4a:,
|
|
83
88
|
* socks5:) proxies. IPv6 proxy endpoints are given in URL form, e.g. `socks5://[2001:db8::1]:1080`.
|
|
@@ -133,8 +138,9 @@ export interface ImapFlowOptions {
|
|
|
133
138
|
* whatever is left of `maxResponseSize`, so lowering that also bounds line buffering.
|
|
134
139
|
* Exceeding it is terminal: the connection fails with error code `LineTooLarge` and
|
|
135
140
|
* no further input is parsed. The limit bounds the bytes of a line, not the memory its parse
|
|
136
|
-
* takes, which is several times the line size for a line of many small tokens
|
|
137
|
-
* answer of plain numbers is read into an array of about the
|
|
141
|
+
* takes, which is several times the line size for a line of many small tokens, see
|
|
142
|
+
* `maxResponseTokens`. A SEARCH answer of plain numbers is read into an array of about the
|
|
143
|
+
* size of the line.
|
|
138
144
|
*/
|
|
139
145
|
maxLineLength?: number | undefined;
|
|
140
146
|
/**
|
|
@@ -159,6 +165,16 @@ export interface ImapFlowOptions {
|
|
|
159
165
|
* no further input is parsed.
|
|
160
166
|
*/
|
|
161
167
|
maxResponseSize?: number | undefined;
|
|
168
|
+
/**
|
|
169
|
+
* Maximum number of tokens (atoms, strings, literals, lists and other parse tree nodes) in a
|
|
170
|
+
* single IMAP response. The byte limits bound what a server sends, this bounds what parsing it
|
|
171
|
+
* costs: each token takes around a hundred bytes of heap while the response is parsed, so a
|
|
172
|
+
* response of many small tokens costs about fifty times its size. Defaults to 1000000, far
|
|
173
|
+
* above any legitimate response (a SEARCH answer of plain numbers is not tokenized and does
|
|
174
|
+
* not count). Lower it in a memory-limited runtime. `Infinity` disables the limit. Exceeding it
|
|
175
|
+
* is terminal: the connection fails with error code `TooManyTokens`.
|
|
176
|
+
*/
|
|
177
|
+
maxResponseTokens?: number | undefined;
|
|
162
178
|
/**
|
|
163
179
|
* Threshold in milliseconds for warning that a mailbox lock has been held
|
|
164
180
|
* for a long time (diagnostic for forgotten release() calls). Defaults to
|
|
@@ -681,9 +697,12 @@ export type DownloadManyResult = {
|
|
|
681
697
|
export interface AppendResponseObject {
|
|
682
698
|
/** Full mailbox path where the message was uploaded to */
|
|
683
699
|
destination: string;
|
|
684
|
-
/** Mailbox UIDVALIDITY if server has UIDPLUS extension enabled */
|
|
700
|
+
/** Mailbox UIDVALIDITY if server has UIDPLUS extension enabled, only set together with the `uid` it reported */
|
|
685
701
|
uidValidity?: bigint | undefined;
|
|
686
|
-
/**
|
|
702
|
+
/**
|
|
703
|
+
* UID of the uploaded message if server has UIDPLUS extension enabled. Without a usable APPENDUID,
|
|
704
|
+
* an append to the selected mailbox looks it up by sequence number instead, and `uidValidity` is not set
|
|
705
|
+
*/
|
|
687
706
|
uid?: number | undefined;
|
|
688
707
|
/** Sequence number of the uploaded message if path is currently selected mailbox */
|
|
689
708
|
seq?: number | undefined;
|
|
@@ -775,6 +794,22 @@ export interface ExistsEvent {
|
|
|
775
794
|
/** Message count before this update */
|
|
776
795
|
prevCount: number;
|
|
777
796
|
}
|
|
797
|
+
/**
|
|
798
|
+
* Payload of the `highestModseq` event: the HIGHESTMODSEQ of the selected mailbox changed (RFC
|
|
799
|
+
* 7162), so flags or other message metadata changed on the server. Emitted when a poll on a
|
|
800
|
+
* server without IDLE (`missingIdleCommand` STATUS or SELECT) or a STATUS or re-SELECT of the
|
|
801
|
+
* open mailbox reports a new value, which is when the changes themselves are not delivered as
|
|
802
|
+
* `flags` events. A consumer resynchronizes with `fetch(range, { flags: true }, { changedSince:
|
|
803
|
+
* prevHighestModseq })`.
|
|
804
|
+
*/
|
|
805
|
+
export interface HighestModseqEvent {
|
|
806
|
+
/** Mailbox path */
|
|
807
|
+
path: string;
|
|
808
|
+
/** The new HIGHESTMODSEQ value */
|
|
809
|
+
highestModseq: bigint;
|
|
810
|
+
/** The value before this update, undefined when none was known */
|
|
811
|
+
prevHighestModseq?: bigint | undefined;
|
|
812
|
+
}
|
|
778
813
|
export interface FlagsEvent {
|
|
779
814
|
/** Mailbox path */
|
|
780
815
|
path: string;
|
|
@@ -874,7 +909,10 @@ export interface TlsInfo extends CipherNameAndProtocol {
|
|
|
874
909
|
export interface ImapFlowEvents {
|
|
875
910
|
/** Connection close event */
|
|
876
911
|
close: [];
|
|
877
|
-
/**
|
|
912
|
+
/**
|
|
913
|
+
* Error event. Emitted at most once per connection, the connection closes after it. An error
|
|
914
|
+
* while `connect()` is pending rejects `connect()` instead and is not emitted
|
|
915
|
+
*/
|
|
878
916
|
error: [error: Error];
|
|
879
917
|
/** Message count in currently opened mailbox changed */
|
|
880
918
|
exists: [data: ExistsEvent];
|
|
@@ -882,7 +920,13 @@ export interface ImapFlowEvents {
|
|
|
882
920
|
expunge: [data: ExpungeEvent];
|
|
883
921
|
/** Flags were updated for a message */
|
|
884
922
|
flags: [data: FlagsEvent];
|
|
885
|
-
/**
|
|
923
|
+
/** The HIGHESTMODSEQ of the selected mailbox changed without the changes being reported, see {@link HighestModseqEvent} */
|
|
924
|
+
highestModseq: [data: HighestModseqEvent];
|
|
925
|
+
/**
|
|
926
|
+
* Mailbox was opened. Also emitted, after `mailboxClose` for the old mailbox object, when the
|
|
927
|
+
* open mailbox turned out to have a new UIDVALIDITY (a re-SELECT, or a STATUS poll on a server
|
|
928
|
+
* without IDLE, which then selects the mailbox again): every cached UID of it is invalid
|
|
929
|
+
*/
|
|
886
930
|
mailboxOpen: [mailbox: MailboxObject];
|
|
887
931
|
/** Mailbox was closed, either explicitly or because the connection went away while a mailbox was still selected */
|
|
888
932
|
mailboxClose: [mailbox: MailboxObject];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "imapflow",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.0",
|
|
4
4
|
"description": "IMAP Client for Node",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/cjs/imap-flow.js",
|
|
@@ -93,8 +93,8 @@
|
|
|
93
93
|
"tsx": "4.23.15",
|
|
94
94
|
"types-node-legacy": "npm:@types/node@20.0.0",
|
|
95
95
|
"typescript": "6.0.3",
|
|
96
|
-
"typescript-eslint": "8.
|
|
97
|
-
"wrangler": "4.151.
|
|
96
|
+
"typescript-eslint": "8.72.0",
|
|
97
|
+
"wrangler": "4.151.3"
|
|
98
98
|
},
|
|
99
99
|
"dependencies": {
|
|
100
100
|
"@zone-eu/mailsplit": "5.4.27",
|