imapflow 1.0.193 → 1.0.195
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/.github/workflows/test.yml +1 -1
- package/CHANGELOG.md +21 -0
- package/lib/commands/fetch.js +17 -4
- package/lib/handler/imap-stream.js +7 -0
- package/lib/imap-flow.js +336 -265
- package/package.json +8 -8
- package/test/connection-edge-cases-test.js +629 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.0.195](https://github.com/postalsys/imapflow/compare/v1.0.194...v1.0.195) (2025-08-26)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* Add async yielding to compression readNext() to prevent CPU blocking ([18e806d](https://github.com/postalsys/imapflow/commit/18e806d5485defe6d4a0ef3eb502b17f3b2d8c2d))
|
|
9
|
+
* Add async yielding to lock processing loop ([fbf1d9a](https://github.com/postalsys/imapflow/commit/fbf1d9a3aa93b4733a123553d8be0b1785f4135e))
|
|
10
|
+
* Add async yielding to processInput() to prevent CPU blocking ([6b619ce](https://github.com/postalsys/imapflow/commit/6b619ced453c3ee8556e18646ad476ad82a68fbf))
|
|
11
|
+
* Add async yielding to reader() method to prevent CPU blocking ([40574e3](https://github.com/postalsys/imapflow/commit/40574e322be27d8b3cdd1b32416e8395d7e395b5))
|
|
12
|
+
* Add exponential backoff to FETCH retry logic ([fb99e2d](https://github.com/postalsys/imapflow/commit/fb99e2d26c9cb29e69b6d33083ef101264b4b039))
|
|
13
|
+
* Add rate limiting for compression operations ([f54c1d0](https://github.com/postalsys/imapflow/commit/f54c1d0caf1bd8cc41a0779e12c915adbb55f346))
|
|
14
|
+
* Correct log source indicator for client commands ([bb3ea09](https://github.com/postalsys/imapflow/commit/bb3ea09c3135c131fc8bedd733311aa3fe176261))
|
|
15
|
+
|
|
16
|
+
## [1.0.194](https://github.com/postalsys/imapflow/compare/v1.0.193...v1.0.194) (2025-08-13)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
### Bug Fixes
|
|
20
|
+
|
|
21
|
+
* Fixed race condition when opening multiple mailboxes simultaneusly ([1248f84](https://github.com/postalsys/imapflow/commit/1248f8494afe0cc2c9faf31642fa3ea045ec0453))
|
|
22
|
+
* Merge branch 'master' into mustang-im-trycatch ([b024a0a](https://github.com/postalsys/imapflow/commit/b024a0a6375e9e62b8f5a0e1183c34d7e39bd5b7))
|
|
23
|
+
|
|
3
24
|
## [1.0.193](https://github.com/postalsys/imapflow/compare/v1.0.192...v1.0.193) (2025-07-31)
|
|
4
25
|
|
|
5
26
|
|
package/lib/commands/fetch.js
CHANGED
|
@@ -16,7 +16,10 @@ module.exports = async (connection, range, query, options) => {
|
|
|
16
16
|
const commandKey = connection.capabilities.has('BINARY') && options.binary && !connection.disableBinary ? 'BINARY' : 'BODY';
|
|
17
17
|
|
|
18
18
|
let retryCount = 0;
|
|
19
|
-
|
|
19
|
+
const maxRetries = 4;
|
|
20
|
+
const baseDelay = 1000; // Start with 1 second delay
|
|
21
|
+
|
|
22
|
+
while (retryCount < maxRetries) {
|
|
20
23
|
let messages = {
|
|
21
24
|
count: 0,
|
|
22
25
|
list: []
|
|
@@ -189,15 +192,25 @@ module.exports = async (connection, range, query, options) => {
|
|
|
189
192
|
return messages;
|
|
190
193
|
} catch (err) {
|
|
191
194
|
if (err.code === 'ETHROTTLE') {
|
|
192
|
-
//
|
|
195
|
+
// Calculate exponential backoff delay
|
|
196
|
+
const backoffDelay = Math.min(baseDelay * Math.pow(2, retryCount), 30000); // Cap at 30 seconds
|
|
197
|
+
|
|
198
|
+
// Use throttle reset time if provided and longer than backoff
|
|
199
|
+
const delay = err.throttleReset && err.throttleReset > backoffDelay ? err.throttleReset : backoffDelay;
|
|
200
|
+
|
|
193
201
|
connection.log.warn({
|
|
194
|
-
msg: 'Retrying throttled request',
|
|
202
|
+
msg: 'Retrying throttled request with exponential backoff',
|
|
195
203
|
cid: connection.id,
|
|
196
204
|
code: err.code,
|
|
197
205
|
response: err.responseText,
|
|
198
206
|
throttleReset: err.throttleReset,
|
|
199
|
-
retryCount
|
|
207
|
+
retryCount,
|
|
208
|
+
delayMs: delay
|
|
200
209
|
});
|
|
210
|
+
|
|
211
|
+
// Wait before retrying
|
|
212
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
213
|
+
|
|
201
214
|
retryCount++;
|
|
202
215
|
continue;
|
|
203
216
|
}
|
|
@@ -201,10 +201,17 @@ class ImapStream extends Transform {
|
|
|
201
201
|
|
|
202
202
|
async processInput() {
|
|
203
203
|
let data;
|
|
204
|
+
let processedCount = 0;
|
|
204
205
|
while ((data = this.inputQueue.shift())) {
|
|
205
206
|
await this.processInputChunk(data.chunk);
|
|
206
207
|
// mark chunk as processed
|
|
207
208
|
data.next();
|
|
209
|
+
|
|
210
|
+
// Yield to event loop every 10 chunks to prevent CPU blocking
|
|
211
|
+
processedCount++;
|
|
212
|
+
if (processedCount % 10 === 0) {
|
|
213
|
+
await new Promise(resolve => setImmediate(resolve));
|
|
214
|
+
}
|
|
208
215
|
}
|
|
209
216
|
}
|
|
210
217
|
|