imapflow 2.7.0 → 2.8.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 +7 -0
- package/dist/cjs/imap-flow.d.ts +5 -3
- package/dist/cjs/imap-flow.js +28 -2
- package/dist/cjs/package-info.d.ts +1 -1
- package/dist/cjs/package-info.js +1 -1
- package/dist/cjs/types.d.ts +10 -0
- package/dist/esm/imap-flow.d.ts +5 -3
- package/dist/esm/imap-flow.js +28 -2
- package/dist/esm/package-info.d.ts +1 -1
- package/dist/esm/package-info.js +1 -1
- package/dist/esm/types.d.ts +10 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [2.8.0](https://github.com/postalsys/imapflow/compare/v2.7.0...v2.8.0) (2026-10-21)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* idle({ whenFree: true }) waits for the connection to be free before starting IDLE ([791c24c](https://github.com/postalsys/imapflow/commit/791c24ca607b60585ef619269abb0aa1f400f525))
|
|
9
|
+
|
|
3
10
|
## [2.7.0](https://github.com/postalsys/imapflow/compare/v2.6.0...v2.7.0) (2026-10-21)
|
|
4
11
|
|
|
5
12
|
|
package/dist/cjs/imap-flow.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { EventEmitter } from 'node:events';
|
|
5
5
|
import { PassThrough, type Readable } from 'node:stream';
|
|
6
6
|
import { AuthenticationFailure } from './errors.js';
|
|
7
|
-
import type { AppendResponseObject, CopyResponseObject, DownloadManyOptions, DownloadManyResult, DownloadObject, DownloadNotFound, DownloadOptions, ESearchResult, FetchMessageObject, FetchOptions, FetchQueryObject, IdInfoObject, ImapFlowEvents, ImapFlowOptions, InternalLogger, ListOptions, ListResponse, ListTreeResponse, MailboxCreateResponse, MailboxDeleteResponse, MailboxLockObject, MailboxLockOptions, MailboxObject, MailboxOpenOptions, MailboxRenameResponse, MessageRange, MessageRangeOptions, NamespaceObject, NamespacesObject, QuotaResponse, SearchObject, SearchOptions, SearchReturnOption, SequenceString, StatusObject, StatusQuery, StoreOptions, TlsInfo, ImapTransportSocket } from './types.js';
|
|
7
|
+
import type { AppendResponseObject, CopyResponseObject, DownloadManyOptions, DownloadManyResult, DownloadObject, DownloadNotFound, DownloadOptions, ESearchResult, FetchMessageObject, FetchOptions, FetchQueryObject, IdInfoObject, ImapFlowEvents, ImapFlowOptions, InternalLogger, ListOptions, ListResponse, ListTreeResponse, MailboxCreateResponse, MailboxDeleteResponse, MailboxLockObject, MailboxLockOptions, IdleOptions, MailboxObject, MailboxOpenOptions, MailboxRenameResponse, MessageRange, MessageRangeOptions, NamespaceObject, NamespacesObject, QuotaResponse, SearchObject, SearchOptions, SearchReturnOption, SequenceString, StatusObject, StatusQuery, StoreOptions, TlsInfo, ImapTransportSocket } from './types.js';
|
|
8
8
|
export type * from './types.js';
|
|
9
9
|
export type { ImapFlowError } from './errors.js';
|
|
10
10
|
export { AuthenticationFailure, ImapFlowErrorCode } from './errors.js';
|
|
@@ -378,8 +378,10 @@ export declare class ImapFlow extends EventEmitter {
|
|
|
378
378
|
* return until IDLE is finished which means you would have to call some other command out of scope.
|
|
379
379
|
*
|
|
380
380
|
* Unlike auto-IDLE, a direct call does not wait for the connection to be free: a mailbox lock
|
|
381
|
-
* holder may idle inside its own lock, and idle() can not tell it from another caller.
|
|
381
|
+
* holder may idle inside its own lock, and idle() can not tell it from another caller. Code that
|
|
382
|
+
* holds no lock passes `{ whenFree: true }` to wait for the connection to be free first.
|
|
382
383
|
*
|
|
384
|
+
* @param options IDLE options
|
|
383
385
|
* @returns `false` if IDLE failed, `undefined` otherwise
|
|
384
386
|
*
|
|
385
387
|
* @example
|
|
@@ -387,7 +389,7 @@ export declare class ImapFlow extends EventEmitter {
|
|
|
387
389
|
*
|
|
388
390
|
* await client.idle();
|
|
389
391
|
*/
|
|
390
|
-
idle(): Promise<boolean | undefined>;
|
|
392
|
+
idle(options?: IdleOptions | undefined): Promise<boolean | undefined>;
|
|
391
393
|
/**
|
|
392
394
|
* Sets flags for a message or message range
|
|
393
395
|
*
|
package/dist/cjs/imap-flow.js
CHANGED
|
@@ -302,6 +302,7 @@ class ImapFlow extends node_events_1.EventEmitter {
|
|
|
302
302
|
this.context = this.options.context;
|
|
303
303
|
this.connectedAt = null;
|
|
304
304
|
this.lastClientWrite = null;
|
|
305
|
+
this._idleWaiters = [];
|
|
305
306
|
this.idlingAtClose = false;
|
|
306
307
|
this.emitLogs = !!this.options.emitLogs;
|
|
307
308
|
this.lo = 0;
|
|
@@ -2187,6 +2188,14 @@ class ImapFlow extends node_events_1.EventEmitter {
|
|
|
2187
2188
|
connectionBusy() {
|
|
2188
2189
|
return !!(this.currentLock || this.locks.length || this.currentRequest || this.requestQueue.length || this._openDownloads);
|
|
2189
2190
|
}
|
|
2191
|
+
/** @internal */
|
|
2192
|
+
wakeIdleWaiters() {
|
|
2193
|
+
if (this._idleWaiters.length) {
|
|
2194
|
+
for (let { resolve } of this._idleWaiters.splice(0)) {
|
|
2195
|
+
resolve();
|
|
2196
|
+
}
|
|
2197
|
+
}
|
|
2198
|
+
}
|
|
2190
2199
|
// Timer process-liveness policy: connection establishment and greeting deadlines keep the
|
|
2191
2200
|
// process alive, because a caller is waiting on connect() to settle. Background timers
|
|
2192
2201
|
// (auto-IDLE, IDLE restart, fallback polling, throttle back-off, the held-lock diagnostic) are
|
|
@@ -2194,6 +2203,9 @@ class ImapFlow extends node_events_1.EventEmitter {
|
|
|
2194
2203
|
// explicitly on close().
|
|
2195
2204
|
/** @internal */
|
|
2196
2205
|
autoidle() {
|
|
2206
|
+
// every place the connection may have become free calls this, so it is where waiting
|
|
2207
|
+
// idle({ whenFree: true }) calls re-check it, also with auto-IDLE turned off
|
|
2208
|
+
this.wakeIdleWaiters();
|
|
2197
2209
|
(0, tools_js_1.clearTimer)(this.idleStartTimer);
|
|
2198
2210
|
if (this.options.disableAutoIdle || !this.usable || this.state !== this.states.SELECTED) {
|
|
2199
2211
|
return;
|
|
@@ -2501,6 +2513,12 @@ class ImapFlow extends node_events_1.EventEmitter {
|
|
|
2501
2513
|
}
|
|
2502
2514
|
this.closeRequests();
|
|
2503
2515
|
this.closeLocks();
|
|
2516
|
+
if (this._idleWaiters.length) {
|
|
2517
|
+
let waiterError = this.createNoConnectionError(this.byeReason, { rejectedFrom: 'idleWait', command: 'IDLE' });
|
|
2518
|
+
for (let { reject } of this._idleWaiters.splice(0)) {
|
|
2519
|
+
reject(waiterError);
|
|
2520
|
+
}
|
|
2521
|
+
}
|
|
2504
2522
|
this.closeStreams();
|
|
2505
2523
|
// clear socket handlers
|
|
2506
2524
|
this.clearSocketHandlers();
|
|
@@ -2941,8 +2959,10 @@ class ImapFlow extends node_events_1.EventEmitter {
|
|
|
2941
2959
|
* return until IDLE is finished which means you would have to call some other command out of scope.
|
|
2942
2960
|
*
|
|
2943
2961
|
* Unlike auto-IDLE, a direct call does not wait for the connection to be free: a mailbox lock
|
|
2944
|
-
* holder may idle inside its own lock, and idle() can not tell it from another caller.
|
|
2962
|
+
* holder may idle inside its own lock, and idle() can not tell it from another caller. Code that
|
|
2963
|
+
* holds no lock passes `{ whenFree: true }` to wait for the connection to be free first.
|
|
2945
2964
|
*
|
|
2965
|
+
* @param options IDLE options
|
|
2946
2966
|
* @returns `false` if IDLE failed, `undefined` otherwise
|
|
2947
2967
|
*
|
|
2948
2968
|
* @example
|
|
@@ -2950,7 +2970,13 @@ class ImapFlow extends node_events_1.EventEmitter {
|
|
|
2950
2970
|
*
|
|
2951
2971
|
* await client.idle();
|
|
2952
2972
|
*/
|
|
2953
|
-
async idle() {
|
|
2973
|
+
async idle(options) {
|
|
2974
|
+
// Re-checked on every wake, as another IDLE may have started meanwhile
|
|
2975
|
+
while (options?.whenFree && !this.idling && this.usable && this.connectionBusy()) {
|
|
2976
|
+
await new Promise((resolve, reject) => {
|
|
2977
|
+
this._idleWaiters.push({ resolve, reject });
|
|
2978
|
+
});
|
|
2979
|
+
}
|
|
2954
2980
|
if (!this.idling) {
|
|
2955
2981
|
return await this.run('IDLE', this.maxIdleTime);
|
|
2956
2982
|
}
|
package/dist/cjs/package-info.js
CHANGED
package/dist/cjs/types.d.ts
CHANGED
|
@@ -745,6 +745,16 @@ export interface MailboxOpenOptions {
|
|
|
745
745
|
/** QRESYNC (RFC 7162): the UIDVALIDITY known from the previous session, required with `changedSince` */
|
|
746
746
|
uidValidity?: bigint | number | string | undefined;
|
|
747
747
|
}
|
|
748
|
+
export interface IdleOptions {
|
|
749
|
+
/**
|
|
750
|
+
* Wait until the connection is free before starting IDLE: no mailbox lock held or queued, no
|
|
751
|
+
* command running or queued, no download open. Use it from code that does not hold a mailbox
|
|
752
|
+
* lock, so IDLE does not land between another caller's commands. A lock holder must not set it,
|
|
753
|
+
* it would wait for its own release. The returned promise rejects with `NoConnection` when the
|
|
754
|
+
* connection closes while waiting.
|
|
755
|
+
*/
|
|
756
|
+
whenFree?: boolean | undefined;
|
|
757
|
+
}
|
|
748
758
|
export interface MailboxLockOptions extends MailboxOpenOptions {
|
|
749
759
|
/**
|
|
750
760
|
* Optional timeout in milliseconds to wait for the lock to be granted.
|
package/dist/esm/imap-flow.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { EventEmitter } from 'node:events';
|
|
5
5
|
import { PassThrough, type Readable } from 'node:stream';
|
|
6
6
|
import { AuthenticationFailure } from './errors.js';
|
|
7
|
-
import type { AppendResponseObject, CopyResponseObject, DownloadManyOptions, DownloadManyResult, DownloadObject, DownloadNotFound, DownloadOptions, ESearchResult, FetchMessageObject, FetchOptions, FetchQueryObject, IdInfoObject, ImapFlowEvents, ImapFlowOptions, InternalLogger, ListOptions, ListResponse, ListTreeResponse, MailboxCreateResponse, MailboxDeleteResponse, MailboxLockObject, MailboxLockOptions, MailboxObject, MailboxOpenOptions, MailboxRenameResponse, MessageRange, MessageRangeOptions, NamespaceObject, NamespacesObject, QuotaResponse, SearchObject, SearchOptions, SearchReturnOption, SequenceString, StatusObject, StatusQuery, StoreOptions, TlsInfo, ImapTransportSocket } from './types.js';
|
|
7
|
+
import type { AppendResponseObject, CopyResponseObject, DownloadManyOptions, DownloadManyResult, DownloadObject, DownloadNotFound, DownloadOptions, ESearchResult, FetchMessageObject, FetchOptions, FetchQueryObject, IdInfoObject, ImapFlowEvents, ImapFlowOptions, InternalLogger, ListOptions, ListResponse, ListTreeResponse, MailboxCreateResponse, MailboxDeleteResponse, MailboxLockObject, MailboxLockOptions, IdleOptions, MailboxObject, MailboxOpenOptions, MailboxRenameResponse, MessageRange, MessageRangeOptions, NamespaceObject, NamespacesObject, QuotaResponse, SearchObject, SearchOptions, SearchReturnOption, SequenceString, StatusObject, StatusQuery, StoreOptions, TlsInfo, ImapTransportSocket } from './types.js';
|
|
8
8
|
export type * from './types.js';
|
|
9
9
|
export type { ImapFlowError } from './errors.js';
|
|
10
10
|
export { AuthenticationFailure, ImapFlowErrorCode } from './errors.js';
|
|
@@ -378,8 +378,10 @@ export declare class ImapFlow extends EventEmitter {
|
|
|
378
378
|
* return until IDLE is finished which means you would have to call some other command out of scope.
|
|
379
379
|
*
|
|
380
380
|
* Unlike auto-IDLE, a direct call does not wait for the connection to be free: a mailbox lock
|
|
381
|
-
* holder may idle inside its own lock, and idle() can not tell it from another caller.
|
|
381
|
+
* holder may idle inside its own lock, and idle() can not tell it from another caller. Code that
|
|
382
|
+
* holds no lock passes `{ whenFree: true }` to wait for the connection to be free first.
|
|
382
383
|
*
|
|
384
|
+
* @param options IDLE options
|
|
383
385
|
* @returns `false` if IDLE failed, `undefined` otherwise
|
|
384
386
|
*
|
|
385
387
|
* @example
|
|
@@ -387,7 +389,7 @@ export declare class ImapFlow extends EventEmitter {
|
|
|
387
389
|
*
|
|
388
390
|
* await client.idle();
|
|
389
391
|
*/
|
|
390
|
-
idle(): Promise<boolean | undefined>;
|
|
392
|
+
idle(options?: IdleOptions | undefined): Promise<boolean | undefined>;
|
|
391
393
|
/**
|
|
392
394
|
* Sets flags for a message or message range
|
|
393
395
|
*
|
package/dist/esm/imap-flow.js
CHANGED
|
@@ -259,6 +259,7 @@ export class ImapFlow extends EventEmitter {
|
|
|
259
259
|
this.context = this.options.context;
|
|
260
260
|
this.connectedAt = null;
|
|
261
261
|
this.lastClientWrite = null;
|
|
262
|
+
this._idleWaiters = [];
|
|
262
263
|
this.idlingAtClose = false;
|
|
263
264
|
this.emitLogs = !!this.options.emitLogs;
|
|
264
265
|
this.lo = 0;
|
|
@@ -2144,6 +2145,14 @@ export class ImapFlow extends EventEmitter {
|
|
|
2144
2145
|
connectionBusy() {
|
|
2145
2146
|
return !!(this.currentLock || this.locks.length || this.currentRequest || this.requestQueue.length || this._openDownloads);
|
|
2146
2147
|
}
|
|
2148
|
+
/** @internal */
|
|
2149
|
+
wakeIdleWaiters() {
|
|
2150
|
+
if (this._idleWaiters.length) {
|
|
2151
|
+
for (let { resolve } of this._idleWaiters.splice(0)) {
|
|
2152
|
+
resolve();
|
|
2153
|
+
}
|
|
2154
|
+
}
|
|
2155
|
+
}
|
|
2147
2156
|
// Timer process-liveness policy: connection establishment and greeting deadlines keep the
|
|
2148
2157
|
// process alive, because a caller is waiting on connect() to settle. Background timers
|
|
2149
2158
|
// (auto-IDLE, IDLE restart, fallback polling, throttle back-off, the held-lock diagnostic) are
|
|
@@ -2151,6 +2160,9 @@ export class ImapFlow extends EventEmitter {
|
|
|
2151
2160
|
// explicitly on close().
|
|
2152
2161
|
/** @internal */
|
|
2153
2162
|
autoidle() {
|
|
2163
|
+
// every place the connection may have become free calls this, so it is where waiting
|
|
2164
|
+
// idle({ whenFree: true }) calls re-check it, also with auto-IDLE turned off
|
|
2165
|
+
this.wakeIdleWaiters();
|
|
2154
2166
|
clearTimer(this.idleStartTimer);
|
|
2155
2167
|
if (this.options.disableAutoIdle || !this.usable || this.state !== this.states.SELECTED) {
|
|
2156
2168
|
return;
|
|
@@ -2458,6 +2470,12 @@ export class ImapFlow extends EventEmitter {
|
|
|
2458
2470
|
}
|
|
2459
2471
|
this.closeRequests();
|
|
2460
2472
|
this.closeLocks();
|
|
2473
|
+
if (this._idleWaiters.length) {
|
|
2474
|
+
let waiterError = this.createNoConnectionError(this.byeReason, { rejectedFrom: 'idleWait', command: 'IDLE' });
|
|
2475
|
+
for (let { reject } of this._idleWaiters.splice(0)) {
|
|
2476
|
+
reject(waiterError);
|
|
2477
|
+
}
|
|
2478
|
+
}
|
|
2461
2479
|
this.closeStreams();
|
|
2462
2480
|
// clear socket handlers
|
|
2463
2481
|
this.clearSocketHandlers();
|
|
@@ -2898,8 +2916,10 @@ export class ImapFlow extends EventEmitter {
|
|
|
2898
2916
|
* return until IDLE is finished which means you would have to call some other command out of scope.
|
|
2899
2917
|
*
|
|
2900
2918
|
* Unlike auto-IDLE, a direct call does not wait for the connection to be free: a mailbox lock
|
|
2901
|
-
* holder may idle inside its own lock, and idle() can not tell it from another caller.
|
|
2919
|
+
* holder may idle inside its own lock, and idle() can not tell it from another caller. Code that
|
|
2920
|
+
* holds no lock passes `{ whenFree: true }` to wait for the connection to be free first.
|
|
2902
2921
|
*
|
|
2922
|
+
* @param options IDLE options
|
|
2903
2923
|
* @returns `false` if IDLE failed, `undefined` otherwise
|
|
2904
2924
|
*
|
|
2905
2925
|
* @example
|
|
@@ -2907,7 +2927,13 @@ export class ImapFlow extends EventEmitter {
|
|
|
2907
2927
|
*
|
|
2908
2928
|
* await client.idle();
|
|
2909
2929
|
*/
|
|
2910
|
-
async idle() {
|
|
2930
|
+
async idle(options) {
|
|
2931
|
+
// Re-checked on every wake, as another IDLE may have started meanwhile
|
|
2932
|
+
while (options?.whenFree && !this.idling && this.usable && this.connectionBusy()) {
|
|
2933
|
+
await new Promise((resolve, reject) => {
|
|
2934
|
+
this._idleWaiters.push({ resolve, reject });
|
|
2935
|
+
});
|
|
2936
|
+
}
|
|
2911
2937
|
if (!this.idling) {
|
|
2912
2938
|
return await this.run('IDLE', this.maxIdleTime);
|
|
2913
2939
|
}
|
package/dist/esm/package-info.js
CHANGED
package/dist/esm/types.d.ts
CHANGED
|
@@ -745,6 +745,16 @@ export interface MailboxOpenOptions {
|
|
|
745
745
|
/** QRESYNC (RFC 7162): the UIDVALIDITY known from the previous session, required with `changedSince` */
|
|
746
746
|
uidValidity?: bigint | number | string | undefined;
|
|
747
747
|
}
|
|
748
|
+
export interface IdleOptions {
|
|
749
|
+
/**
|
|
750
|
+
* Wait until the connection is free before starting IDLE: no mailbox lock held or queued, no
|
|
751
|
+
* command running or queued, no download open. Use it from code that does not hold a mailbox
|
|
752
|
+
* lock, so IDLE does not land between another caller's commands. A lock holder must not set it,
|
|
753
|
+
* it would wait for its own release. The returned promise rejects with `NoConnection` when the
|
|
754
|
+
* connection closes while waiting.
|
|
755
|
+
*/
|
|
756
|
+
whenFree?: boolean | undefined;
|
|
757
|
+
}
|
|
748
758
|
export interface MailboxLockOptions extends MailboxOpenOptions {
|
|
749
759
|
/**
|
|
750
760
|
* Optional timeout in milliseconds to wait for the lock to be granted.
|