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.
@@ -8,7 +8,7 @@ jobs:
8
8
  test:
9
9
  strategy:
10
10
  matrix:
11
- node: [16.x, 18.x]
11
+ node: [20.x, 22.x, 24.x]
12
12
  os: [ubuntu-latest]
13
13
  runs-on: ${{ matrix.os }}
14
14
  steps:
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
 
@@ -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
- while (retryCount < 4) {
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
- // retrying
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