imapflow 1.7.7 → 2.0.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.
Files changed (296) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/README.md +8 -2
  3. package/dist/cjs/charsets.d.ts +1 -0
  4. package/dist/cjs/charsets.js +294 -0
  5. package/dist/cjs/commands/append.d.ts +22 -0
  6. package/dist/cjs/commands/append.js +151 -0
  7. package/dist/cjs/commands/authenticate.d.ts +24 -0
  8. package/dist/cjs/commands/authenticate.js +223 -0
  9. package/dist/cjs/commands/capability.d.ts +8 -0
  10. package/dist/cjs/commands/capability.js +32 -0
  11. package/dist/cjs/commands/close.d.ts +8 -0
  12. package/dist/cjs/commands/close.js +39 -0
  13. package/dist/cjs/commands/compress.d.ts +8 -0
  14. package/dist/cjs/commands/compress.js +56 -0
  15. package/dist/cjs/commands/copy.d.ts +13 -0
  16. package/dist/cjs/commands/copy.js +44 -0
  17. package/dist/cjs/commands/copyuid-parser.d.ts +11 -0
  18. package/dist/cjs/commands/copyuid-parser.js +32 -0
  19. package/dist/cjs/commands/create.d.ts +11 -0
  20. package/dist/cjs/commands/create.js +80 -0
  21. package/dist/cjs/commands/delete.d.ts +11 -0
  22. package/dist/cjs/commands/delete.js +40 -0
  23. package/dist/cjs/commands/enable.d.ts +9 -0
  24. package/dist/cjs/commands/enable.js +61 -0
  25. package/dist/cjs/commands/esearch-parser.d.ts +17 -0
  26. package/dist/cjs/commands/esearch-parser.js +91 -0
  27. package/dist/cjs/commands/expunge.d.ts +12 -0
  28. package/dist/cjs/commands/expunge.js +60 -0
  29. package/dist/cjs/commands/fetch.d.ts +30 -0
  30. package/dist/cjs/commands/fetch.js +241 -0
  31. package/dist/cjs/commands/id.d.ts +10 -0
  32. package/dist/cjs/commands/id.js +80 -0
  33. package/dist/cjs/commands/idle.d.ts +9 -0
  34. package/dist/cjs/commands/idle.js +347 -0
  35. package/dist/cjs/commands/list.d.ts +16 -0
  36. package/dist/cjs/commands/list.js +518 -0
  37. package/dist/cjs/commands/login.d.ts +11 -0
  38. package/dist/cjs/commands/login.js +42 -0
  39. package/dist/cjs/commands/logout.d.ts +8 -0
  40. package/dist/cjs/commands/logout.js +47 -0
  41. package/dist/cjs/commands/move.d.ts +13 -0
  42. package/dist/cjs/commands/move.js +57 -0
  43. package/dist/cjs/commands/namespace.d.ts +25 -0
  44. package/dist/cjs/commands/namespace.js +139 -0
  45. package/dist/cjs/commands/noop.d.ts +8 -0
  46. package/dist/cjs/commands/noop.js +22 -0
  47. package/dist/cjs/commands/quota.d.ts +10 -0
  48. package/dist/cjs/commands/quota.js +119 -0
  49. package/dist/cjs/commands/rename.d.ts +12 -0
  50. package/dist/cjs/commands/rename.js +48 -0
  51. package/dist/cjs/commands/search.d.ts +15 -0
  52. package/dist/cjs/commands/search.js +228 -0
  53. package/dist/cjs/commands/select.d.ts +25 -0
  54. package/dist/cjs/commands/select.js +250 -0
  55. package/dist/cjs/commands/starttls.d.ts +8 -0
  56. package/dist/cjs/commands/starttls.js +30 -0
  57. package/dist/cjs/commands/status-fields.d.ts +14 -0
  58. package/dist/cjs/commands/status-fields.js +61 -0
  59. package/dist/cjs/commands/status.d.ts +12 -0
  60. package/dist/cjs/commands/status.js +108 -0
  61. package/dist/cjs/commands/store.d.ts +19 -0
  62. package/dist/cjs/commands/store.js +93 -0
  63. package/dist/cjs/commands/subscribe.d.ts +9 -0
  64. package/dist/cjs/commands/subscribe.js +31 -0
  65. package/dist/cjs/commands/unsubscribe.d.ts +9 -0
  66. package/dist/cjs/commands/unsubscribe.js +31 -0
  67. package/dist/cjs/connection-deadline.d.ts +49 -0
  68. package/dist/cjs/connection-deadline.js +91 -0
  69. package/dist/cjs/errors.d.ts +83 -0
  70. package/dist/cjs/errors.js +13 -0
  71. package/dist/cjs/handler/imap-compiler.d.ts +24 -0
  72. package/dist/cjs/handler/imap-compiler.js +285 -0
  73. package/dist/cjs/handler/imap-formal-syntax.d.ts +28 -0
  74. package/dist/cjs/handler/imap-formal-syntax.js +121 -0
  75. package/dist/cjs/handler/imap-handler.d.ts +9 -0
  76. package/dist/cjs/handler/imap-handler.js +10 -0
  77. package/dist/cjs/handler/imap-parser.d.ts +16 -0
  78. package/dist/cjs/handler/imap-parser.js +90 -0
  79. package/dist/cjs/handler/imap-stream.d.ts +181 -0
  80. package/dist/cjs/handler/imap-stream.js +446 -0
  81. package/dist/cjs/handler/limits.d.ts +25 -0
  82. package/dist/cjs/handler/limits.js +51 -0
  83. package/dist/cjs/handler/parser-instance.d.ts +68 -0
  84. package/dist/cjs/handler/parser-instance.js +223 -0
  85. package/dist/cjs/handler/token-parser.d.ts +91 -0
  86. package/dist/cjs/handler/token-parser.js +673 -0
  87. package/dist/cjs/handler/types.d.ts +91 -0
  88. package/dist/cjs/handler/types.js +4 -0
  89. package/dist/cjs/imap-commands.d.ts +16 -0
  90. package/dist/cjs/imap-commands.js +74 -0
  91. package/dist/cjs/imap-flow.d.ts +676 -0
  92. package/dist/cjs/imap-flow.js +3949 -0
  93. package/dist/cjs/jp-decoder.d.ts +12 -0
  94. package/dist/cjs/jp-decoder.js +79 -0
  95. package/dist/cjs/limited-passthrough.d.ts +25 -0
  96. package/dist/cjs/limited-passthrough.js +54 -0
  97. package/dist/cjs/logger.d.ts +3 -0
  98. package/dist/cjs/logger.js +11 -0
  99. package/dist/cjs/package-info.d.ts +3 -0
  100. package/dist/cjs/package-info.js +7 -0
  101. package/dist/cjs/package.json +3 -0
  102. package/dist/cjs/proxy-connection.d.ts +33 -0
  103. package/dist/cjs/proxy-connection.js +392 -0
  104. package/dist/cjs/search-compiler.d.ts +34 -0
  105. package/dist/cjs/search-compiler.js +476 -0
  106. package/dist/cjs/special-use.d.ts +22 -0
  107. package/dist/cjs/special-use.js +911 -0
  108. package/dist/cjs/tools.d.ts +427 -0
  109. package/dist/cjs/tools.js +1496 -0
  110. package/{lib/imap-flow.d.ts → dist/cjs/types.d.ts} +386 -516
  111. package/dist/cjs/types.js +5 -0
  112. package/dist/esm/charsets.d.ts +1 -0
  113. package/{lib → dist/esm}/charsets.js +1 -6
  114. package/dist/esm/commands/append.d.ts +22 -0
  115. package/{lib → dist/esm}/commands/append.js +22 -52
  116. package/dist/esm/commands/authenticate.d.ts +24 -0
  117. package/{lib → dist/esm}/commands/authenticate.js +62 -87
  118. package/dist/esm/commands/capability.d.ts +8 -0
  119. package/{lib → dist/esm}/commands/capability.js +6 -9
  120. package/dist/esm/commands/close.d.ts +8 -0
  121. package/{lib → dist/esm}/commands/close.js +6 -10
  122. package/dist/esm/commands/compress.d.ts +8 -0
  123. package/{lib → dist/esm}/commands/compress.js +7 -11
  124. package/dist/esm/commands/copy.d.ts +13 -0
  125. package/{lib → dist/esm}/commands/copy.js +12 -20
  126. package/dist/esm/commands/copyuid-parser.d.ts +11 -0
  127. package/{lib → dist/esm}/commands/copyuid-parser.js +9 -15
  128. package/dist/esm/commands/create.d.ts +11 -0
  129. package/{lib → dist/esm}/commands/create.js +13 -27
  130. package/dist/esm/commands/delete.d.ts +11 -0
  131. package/{lib → dist/esm}/commands/delete.js +9 -14
  132. package/dist/esm/commands/enable.d.ts +9 -0
  133. package/{lib → dist/esm}/commands/enable.js +23 -30
  134. package/dist/esm/commands/esearch-parser.d.ts +17 -0
  135. package/dist/esm/commands/esearch-parser.js +88 -0
  136. package/dist/esm/commands/expunge.d.ts +12 -0
  137. package/{lib → dist/esm}/commands/expunge.js +17 -22
  138. package/dist/esm/commands/fetch.d.ts +30 -0
  139. package/{lib → dist/esm}/commands/fetch.js +32 -64
  140. package/dist/esm/commands/id.d.ts +10 -0
  141. package/{lib → dist/esm}/commands/id.js +17 -23
  142. package/dist/esm/commands/idle.d.ts +9 -0
  143. package/{lib → dist/esm}/commands/idle.js +47 -81
  144. package/dist/esm/commands/list.d.ts +16 -0
  145. package/{lib → dist/esm}/commands/list.js +56 -121
  146. package/dist/esm/commands/login.d.ts +11 -0
  147. package/{lib → dist/esm}/commands/login.js +10 -15
  148. package/dist/esm/commands/logout.d.ts +8 -0
  149. package/{lib → dist/esm}/commands/logout.js +9 -11
  150. package/dist/esm/commands/move.d.ts +13 -0
  151. package/{lib → dist/esm}/commands/move.js +13 -21
  152. package/dist/esm/commands/namespace.d.ts +25 -0
  153. package/{lib → dist/esm}/commands/namespace.js +34 -44
  154. package/dist/esm/commands/noop.d.ts +8 -0
  155. package/{lib → dist/esm}/commands/noop.js +6 -7
  156. package/dist/esm/commands/quota.d.ts +10 -0
  157. package/{lib → dist/esm}/commands/quota.js +18 -36
  158. package/dist/esm/commands/rename.d.ts +12 -0
  159. package/{lib → dist/esm}/commands/rename.js +10 -15
  160. package/dist/esm/commands/search.d.ts +15 -0
  161. package/{lib → dist/esm}/commands/search.js +36 -135
  162. package/dist/esm/commands/select.d.ts +25 -0
  163. package/{lib → dist/esm}/commands/select.js +33 -64
  164. package/dist/esm/commands/starttls.d.ts +8 -0
  165. package/{lib → dist/esm}/commands/starttls.js +6 -8
  166. package/dist/esm/commands/status-fields.d.ts +14 -0
  167. package/{lib → dist/esm}/commands/status-fields.js +5 -16
  168. package/dist/esm/commands/status.d.ts +12 -0
  169. package/{lib → dist/esm}/commands/status.js +18 -29
  170. package/dist/esm/commands/store.d.ts +19 -0
  171. package/{lib → dist/esm}/commands/store.js +24 -37
  172. package/dist/esm/commands/subscribe.d.ts +9 -0
  173. package/{lib → dist/esm}/commands/subscribe.js +8 -12
  174. package/dist/esm/commands/unsubscribe.d.ts +9 -0
  175. package/{lib → dist/esm}/commands/unsubscribe.js +8 -12
  176. package/dist/esm/connection-deadline.d.ts +49 -0
  177. package/{lib → dist/esm}/connection-deadline.js +14 -25
  178. package/dist/esm/errors.d.ts +83 -0
  179. package/dist/esm/errors.js +9 -0
  180. package/dist/esm/handler/imap-compiler.d.ts +24 -0
  181. package/{lib → dist/esm}/handler/imap-compiler.js +22 -80
  182. package/dist/esm/handler/imap-formal-syntax.d.ts +28 -0
  183. package/dist/esm/handler/imap-formal-syntax.js +117 -0
  184. package/dist/esm/handler/imap-handler.d.ts +9 -0
  185. package/dist/esm/handler/imap-handler.js +9 -0
  186. package/dist/esm/handler/imap-parser.d.ts +16 -0
  187. package/{lib → dist/esm}/handler/imap-parser.js +31 -44
  188. package/dist/esm/handler/imap-stream.d.ts +181 -0
  189. package/{lib → dist/esm}/handler/imap-stream.js +29 -121
  190. package/dist/esm/handler/limits.d.ts +25 -0
  191. package/{lib → dist/esm}/handler/limits.js +13 -22
  192. package/dist/esm/handler/parser-instance.d.ts +68 -0
  193. package/{lib → dist/esm}/handler/parser-instance.js +19 -47
  194. package/dist/esm/handler/token-parser.d.ts +91 -0
  195. package/{lib → dist/esm}/handler/token-parser.js +71 -155
  196. package/dist/esm/handler/types.d.ts +91 -0
  197. package/dist/esm/handler/types.js +3 -0
  198. package/dist/esm/imap-commands.d.ts +16 -0
  199. package/dist/esm/imap-commands.js +67 -0
  200. package/dist/esm/imap-flow.d.ts +676 -0
  201. package/{lib → dist/esm}/imap-flow.js +785 -1802
  202. package/dist/esm/jp-decoder.d.ts +12 -0
  203. package/{lib → dist/esm}/jp-decoder.js +6 -21
  204. package/dist/esm/limited-passthrough.d.ts +25 -0
  205. package/{lib → dist/esm}/limited-passthrough.js +7 -20
  206. package/dist/esm/logger.d.ts +3 -0
  207. package/dist/esm/logger.js +4 -0
  208. package/dist/esm/package-info.d.ts +3 -0
  209. package/dist/esm/package-info.js +4 -0
  210. package/dist/esm/package.json +3 -0
  211. package/dist/esm/proxy-connection.d.ts +33 -0
  212. package/{lib → dist/esm}/proxy-connection.js +56 -127
  213. package/dist/esm/search-compiler.d.ts +34 -0
  214. package/{lib → dist/esm}/search-compiler.js +54 -110
  215. package/dist/esm/special-use.d.ts +22 -0
  216. package/dist/esm/special-use.js +907 -0
  217. package/dist/esm/tools.d.ts +427 -0
  218. package/dist/esm/tools.js +1446 -0
  219. package/dist/esm/types.d.ts +828 -0
  220. package/dist/esm/types.js +4 -0
  221. package/package.json +60 -20
  222. package/.gitattributes +0 -1
  223. package/.github/CODE_OF_CONDUCT.md +0 -76
  224. package/.github/FUNDING.yml +0 -4
  225. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -40
  226. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -19
  227. package/.github/contributing.md +0 -17
  228. package/.github/workflows/release.yaml +0 -36
  229. package/.github/workflows/stale.yml +0 -29
  230. package/.github/workflows/test.yml +0 -51
  231. package/.ncurc.js +0 -4
  232. package/.prettierignore +0 -4
  233. package/.prettierrc.js +0 -8
  234. package/.release-please-manifest.json +0 -3
  235. package/CLAUDE.md +0 -104
  236. package/Gruntfile.js +0 -23
  237. package/eslint.config.js +0 -45
  238. package/lib/handler/imap-formal-syntax.js +0 -189
  239. package/lib/handler/imap-handler.js +0 -17
  240. package/lib/imap-commands.js +0 -45
  241. package/lib/logger.js +0 -5
  242. package/lib/special-use.js +0 -923
  243. package/lib/tools.js +0 -1612
  244. package/release-please-config.json +0 -10
  245. package/test/authentication-test.js +0 -101
  246. package/test/auto-idle-test.js +0 -470
  247. package/test/bodystructure-test.js +0 -899
  248. package/test/charsets-test.js +0 -161
  249. package/test/commands-branches-test.js +0 -1095
  250. package/test/commands-integration-test.js +0 -11124
  251. package/test/commands-test.js +0 -73
  252. package/test/connection-edge-cases-test.js +0 -1828
  253. package/test/connection-test.js +0 -162
  254. package/test/copyuid-parser-test.js +0 -173
  255. package/test/fetch-generator-test.js +0 -218
  256. package/test/fixtures/fake-timers.js +0 -115
  257. package/test/fixtures/serialized-mimetorture.js +0 -2738
  258. package/test/fixtures/test-client.js +0 -57
  259. package/test/fixtures/test-tls.js +0 -8
  260. package/test/handler-branches-test.js +0 -310
  261. package/test/idle-polling-test.js +0 -518
  262. package/test/imap-compiler-test.js +0 -809
  263. package/test/imap-flow-compress-test.js +0 -166
  264. package/test/imap-flow-coverage-test.js +0 -612
  265. package/test/imap-flow-fetch-download-test.js +0 -873
  266. package/test/imap-flow-internals-test.js +0 -725
  267. package/test/imap-flow-methods-test.js +0 -889
  268. package/test/imap-flow-proxy-paths-test.js +0 -366
  269. package/test/imap-flow-secure-test.js +0 -573
  270. package/test/imap-flow-server-test.js +0 -1474
  271. package/test/imap-formal-syntax-test.js +0 -293
  272. package/test/imap-parser-test.js +0 -1474
  273. package/test/imap-stream-edge-cases-test.js +0 -666
  274. package/test/imap-stream-test.js +0 -177
  275. package/test/imapflow-test.js +0 -258
  276. package/test/integration/README.md +0 -52
  277. package/test/integration/dovecot-test.conf +0 -27
  278. package/test/integration/rev2-live-test.js +0 -431
  279. package/test/integration/run-rev2-tests.sh +0 -75
  280. package/test/integration-test.js +0 -83
  281. package/test/jp-decoder-test.js +0 -304
  282. package/test/limited-passthrough-test.js +0 -299
  283. package/test/memory-cleanup-test.js +0 -144
  284. package/test/memory-leak-test.js +0 -667
  285. package/test/parser-limits-test.js +0 -292
  286. package/test/proxy-connection-test.js +0 -738
  287. package/test/reliability-improvements-test.js +0 -548
  288. package/test/search-compiler-test.js +0 -1300
  289. package/test/search-test.js +0 -329
  290. package/test/special-use-test.js +0 -418
  291. package/test/starttls-injection-test.js +0 -181
  292. package/test/tag-correlation-test.js +0 -333
  293. package/test/timer-policy-test.js +0 -227
  294. package/test/token-parser-test.js +0 -456
  295. package/test/tools-test.js +0 -2013
  296. package/test/unhandled-rejection-test.js +0 -593
@@ -1,9 +1,5 @@
1
- 'use strict';
2
-
3
- const { guardedPromise, hasCapability, logConnectionError, restampConnectionError, unrefTimer } = require('../tools.js');
4
-
1
+ import { guardedPromise, hasCapability, logConnectionError, restampConnectionError, unrefTimer, clearTimer } from '../tools.js';
5
2
  const NOOP_INTERVAL = 2 * 60 * 1000;
6
-
7
3
  /**
8
4
  * Marks the connection as idling on behalf of one session and returns a release function.
9
5
  *
@@ -11,14 +7,13 @@ const NOOP_INTERVAL = 2 * 60 * 1000;
11
7
  * finishes late (a poll that completes after cancellation, an IDLE that unwinds after a restart)
12
8
  * cannot clear the flag of the session that has since taken over.
13
9
  *
14
- * @param {Object} connection - IMAP connection instance
15
- * @returns {Function} Release function, safe to call more than once
10
+ * @param connection - IMAP connection instance
11
+ * @returns Release function, safe to call more than once
16
12
  */
17
13
  function claimIdling(connection) {
18
14
  let token = {};
19
15
  connection._idleSession = token;
20
16
  connection.idling = true;
21
-
22
17
  return () => {
23
18
  if (connection._idleSession === token) {
24
19
  connection._idleSession = null;
@@ -26,25 +21,21 @@ function claimIdling(connection) {
26
21
  }
27
22
  };
28
23
  }
29
-
30
24
  /**
31
25
  * Runs a single IDLE session on the connection.
32
26
  *
33
- * @param {Object} connection - IMAP connection instance
34
- * @returns {Promise<void|boolean>} Void on success, false on failure
27
+ * @param connection - IMAP connection instance
28
+ * @returns Void on success, false on failure
35
29
  */
36
30
  async function runIdle(connection) {
37
31
  let response;
38
-
39
32
  // Queue of promises waiting for IDLE to break. When another command needs to run,
40
33
  // it calls connection.preCheck() which queues a promise here and sends DONE to break IDLE.
41
34
  let preCheckWaitQueue = [];
42
-
43
35
  // The preCheck function this session owns. Only this session may clear it from the
44
36
  // connection, so a newer IDLE session that already installed its own is left alone.
45
37
  let ownPreCheck = null;
46
38
  let releaseIdling = claimIdling(connection);
47
-
48
39
  try {
49
40
  // State flags for the IDLE lifecycle:
50
41
  // - doneRequested: someone wants to break IDLE (e.g., to run another command)
@@ -53,7 +44,6 @@ async function runIdle(connection) {
53
44
  let doneRequested = false;
54
45
  let doneSent = false;
55
46
  let canEnd = false;
56
-
57
47
  // preCheck sends DONE to break out of IDLE. Called when another command
58
48
  // needs to run on this connection (e.g., a FETCH or STORE from user code).
59
49
  let preCheck = async () => {
@@ -63,25 +53,22 @@ async function runIdle(connection) {
63
53
  src: 'c',
64
54
  msg: `DONE`,
65
55
  comment: `breaking IDLE`,
66
- lockId: connection.currentLock?.lockId,
56
+ lockId: connection.currentLock ? connection.currentLock.lockId : undefined,
67
57
  path: connection.mailbox && connection.mailbox.path,
68
58
  cid: connection.id
69
59
  });
70
60
  connection.write('DONE');
71
61
  doneSent = true;
72
-
73
62
  releaseIdling();
74
63
  if (connection.preCheck === ownPreCheck) {
75
64
  connection.preCheck = false; // unset itself
76
65
  }
77
-
78
66
  while (preCheckWaitQueue.length) {
79
67
  let { resolve } = preCheckWaitQueue.shift();
80
68
  resolve();
81
69
  }
82
70
  }
83
71
  };
84
-
85
72
  // Public interface for breaking IDLE. Returns a promise that resolves when
86
73
  // IDLE is actually broken and the connection is free for other commands.
87
74
  let connectionPreCheck = () => {
@@ -90,10 +77,9 @@ async function runIdle(connection) {
90
77
  let handler = guardedPromise((resolve, reject) => {
91
78
  preCheckWaitQueue.push({ resolve, reject });
92
79
  });
93
-
94
80
  connection.log.trace({
95
81
  msg: 'Requesting IDLE break',
96
- lockId: connection.currentLock?.lockId,
82
+ lockId: connection.currentLock ? connection.currentLock.lockId : undefined,
97
83
  path: connection.mailbox && connection.mailbox.path,
98
84
  queued: preCheckWaitQueue.length,
99
85
  doneRequested,
@@ -101,16 +87,12 @@ async function runIdle(connection) {
101
87
  doneSent,
102
88
  cid: connection.id
103
89
  });
104
-
105
- preCheck().catch(err => logConnectionError(connection, 'Failed to break IDLE', err));
106
-
90
+ preCheck().catch((err) => logConnectionError(connection, 'Failed to break IDLE', err));
107
91
  return handler;
108
92
  };
109
-
110
93
  // Register preCheck on the connection so other code (e.g., getMailboxLock) can break IDLE
111
94
  ownPreCheck = connectionPreCheck;
112
95
  connection.preCheck = connectionPreCheck;
113
-
114
96
  response = await connection.exec('IDLE', false, {
115
97
  // Server responds with "+" continuation to acknowledge IDLE mode.
116
98
  // After this, the server will push untagged responses for mailbox changes.
@@ -118,7 +100,7 @@ async function runIdle(connection) {
118
100
  onPlusTag: async () => {
119
101
  connection.log.debug({
120
102
  msg: `Initiated IDLE, waiting for server input`,
121
- lockId: connection.currentLock?.lockId,
103
+ lockId: connection.currentLock ? connection.currentLock.lockId : undefined,
122
104
  doneRequested,
123
105
  cid: connection.id
124
106
  });
@@ -126,17 +108,18 @@ async function runIdle(connection) {
126
108
  if (doneRequested) {
127
109
  try {
128
110
  await preCheck();
129
- } catch (err) {
111
+ }
112
+ catch (err) {
130
113
  logConnectionError(connection, 'Failed to break IDLE', err);
131
114
  }
132
115
  }
133
116
  },
134
- onSend: () => {}
117
+ onSend: () => { }
135
118
  });
136
-
137
119
  response.next();
138
120
  return;
139
- } catch (err) {
121
+ }
122
+ catch (err) {
140
123
  logConnectionError(connection, 'IDLE session failed', err);
141
124
  if (preCheckWaitQueue.length) {
142
125
  // One error for the whole queue: every waiter failed at the same site, for the same
@@ -149,7 +132,8 @@ async function runIdle(connection) {
149
132
  }
150
133
  }
151
134
  return false;
152
- } finally {
135
+ }
136
+ finally {
153
137
  // Single ownership cleanup for every outcome: explicit break, tagged completion
154
138
  // (including a server-terminated IDLE, where preCheck never ran), rejected command,
155
139
  // parser failure and connection close. `idling` drives socket-timeout handling, so it
@@ -164,7 +148,6 @@ async function runIdle(connection) {
164
148
  }
165
149
  }
166
150
  }
167
-
168
151
  /**
169
152
  * Runs one fallback poll. The real SELECT and STATUS commands are reused instead of replaying the
170
153
  * saved wire arguments, so a poll applies exactly the same mailbox state transitions, events and
@@ -172,19 +155,16 @@ async function runIdle(connection) {
172
155
  * than connection.run(), because run() awaits preCheck() - and the preCheck it would await is the
173
156
  * one this very polling session installed, so the session would cancel itself.
174
157
  *
175
- * @param {Object} connection - IMAP connection instance
176
- * @param {Object} session - Polling session state
177
- * @returns {Promise<void>}
158
+ * @param connection - IMAP connection instance
159
+ * @param session - Polling session state
178
160
  */
179
161
  async function pollOnce(connection, session) {
180
162
  let path = connection.mailbox && connection.mailbox.path;
181
-
182
163
  switch (connection.missingIdleCommand) {
183
164
  case 'SELECT':
184
165
  connection.log.debug({ msg: `Running SELECT to detect changes in folder`, cid: connection.id });
185
166
  await connection.runInternal('SELECT', path, { readOnly: session.selectCommand.command === 'EXAMINE' });
186
167
  break;
187
-
188
168
  case 'STATUS': {
189
169
  connection.log.debug({ msg: `Running STATUS to detect changes in folder`, cid: connection.id });
190
170
  // HIGHESTMODSEQ is filtered out again unless the server advertises CONDSTORE, so a
@@ -204,7 +184,6 @@ async function pollOnce(connection, session) {
204
184
  }
205
185
  break;
206
186
  }
207
-
208
187
  case 'NOOP':
209
188
  default: {
210
189
  let response = await connection.exec('NOOP', false, { comment: 'IDLE not supported' });
@@ -213,7 +192,6 @@ async function pollOnce(connection, session) {
213
192
  }
214
193
  }
215
194
  }
216
-
217
195
  /**
218
196
  * Polls the selected mailbox at a fixed interval, for servers without IDLE support.
219
197
  *
@@ -221,25 +199,21 @@ async function pollOnce(connection, session) {
221
199
  * a poll starts and again before the next timer is scheduled, and a poll that completes after
222
200
  * cancellation can neither run again nor take ownership away from a newer IDLE session.
223
201
  *
224
- * @param {Object} connection - IMAP connection instance
225
- * @param {number} [maxIdleTime] - Upper bound for the polling interval
226
- * @returns {Promise<void>}
202
+ * @param connection - IMAP connection instance
203
+ * @param maxIdleTime - Upper bound for the polling interval
227
204
  */
228
205
  async function runPollingFallback(connection, maxIdleTime) {
229
206
  if (!connection.currentSelectCommand) {
230
207
  return;
231
208
  }
232
-
233
209
  let session = {
234
210
  cancelled: false,
235
211
  timer: null,
236
212
  preCheck: null,
237
213
  selectCommand: connection.currentSelectCommand
238
214
  };
239
-
240
215
  let interval = maxIdleTime ? Math.min(NOOP_INTERVAL, maxIdleTime) : NOOP_INTERVAL;
241
216
  let releaseIdling = claimIdling(connection);
242
-
243
217
  try {
244
218
  await new Promise(resolve => {
245
219
  // Idempotent cancellation. Never keyed off connection.preCheck, because a newer IDLE
@@ -249,54 +223,47 @@ async function runPollingFallback(connection, maxIdleTime) {
249
223
  return;
250
224
  }
251
225
  session.cancelled = true;
252
- clearTimeout(session.timer);
226
+ clearTimer(session.timer);
253
227
  session.timer = null;
254
228
  resolve();
255
229
  };
256
-
257
230
  session.preCheck = async () => {
258
231
  connection.log.debug({ msg: `Breaking NOOP loop`, cid: connection.id });
259
232
  cancel();
260
233
  };
261
234
  connection.preCheck = session.preCheck;
262
-
263
235
  const runPoll = () => {
264
236
  if (session.cancelled) {
265
237
  return;
266
238
  }
267
-
268
239
  // The transport or the mailbox may be gone by the time the timer fires
269
240
  if (!connection.socket || connection.socket.destroyed || connection.state !== connection.states.SELECTED || !connection.mailbox) {
270
241
  return cancel();
271
242
  }
272
-
273
243
  pollOnce(connection, session)
274
244
  .then(() => {
275
- // Stamped only after a poll actually completed: a failed poll must not
276
- // satisfy the resumed schedule below, or the next session would defer
277
- // its first poll a full interval past an attempt that checked nothing.
278
- connection._lastPollAt = Date.now();
279
- // Cancellation is re-checked here: the session may have been broken while
280
- // this poll was in flight, and an orphaned poller must not schedule again.
281
- if (session.cancelled) {
282
- return;
283
- }
284
- scheduleNextPoll(interval);
285
- })
286
- .catch(err => {
287
- logConnectionError(connection, 'Failed to poll for mailbox changes', err);
288
- cancel();
289
- });
245
+ // Stamped only after a poll actually completed: a failed poll must not
246
+ // satisfy the resumed schedule below, or the next session would defer
247
+ // its first poll a full interval past an attempt that checked nothing.
248
+ connection._lastPollAt = Date.now();
249
+ // Cancellation is re-checked here: the session may have been broken while
250
+ // this poll was in flight, and an orphaned poller must not schedule again.
251
+ if (session.cancelled) {
252
+ return;
253
+ }
254
+ scheduleNextPoll(interval);
255
+ })
256
+ .catch((err) => {
257
+ logConnectionError(connection, 'Failed to poll for mailbox changes', err);
258
+ cancel();
259
+ });
290
260
  };
291
-
292
261
  function scheduleNextPoll(delay) {
293
262
  session.timer = setTimeout(runPoll, delay);
294
263
  // Background polling must not keep the process alive
295
264
  unrefTimer(session.timer);
296
265
  }
297
-
298
266
  connection.log.debug({ msg: `Initiated NOOP loop`, cid: connection.id });
299
-
300
267
  // Every auto-IDLE restart begins a fresh polling session, so an unconditional first
301
268
  // poll would tie the poll rate to how often the caller runs commands rather than to
302
269
  // `interval`: with a short autoIdleDelay, a command every few seconds turns into a
@@ -308,13 +275,15 @@ async function runPollingFallback(connection, maxIdleTime) {
308
275
  let sinceLastPoll = Math.max(0, Date.now() - (connection._lastPollAt || 0));
309
276
  if (sinceLastPoll >= interval) {
310
277
  runPoll();
311
- } else {
278
+ }
279
+ else {
312
280
  scheduleNextPoll(interval - sinceLastPoll);
313
281
  }
314
282
  });
315
- } finally {
283
+ }
284
+ finally {
316
285
  session.cancelled = true;
317
- clearTimeout(session.timer);
286
+ clearTimer(session.timer);
318
287
  session.timer = null;
319
288
  releaseIdling();
320
289
  if (connection.preCheck === session.preCheck) {
@@ -322,20 +291,18 @@ async function runPollingFallback(connection, maxIdleTime) {
322
291
  }
323
292
  }
324
293
  }
325
-
326
294
  /**
327
295
  * Listens for changes in the selected mailbox using IDLE or NOOP polling fallback.
328
296
  *
329
- * @param {Object} connection - IMAP connection instance
330
- * @param {number} [maxIdleTime] - Maximum time in milliseconds to stay in IDLE before restarting
331
- * @returns {Promise<void|boolean|undefined>} Void on success, false on failure, or undefined if not in SELECTED state
297
+ * @param connection - IMAP connection instance
298
+ * @param maxIdleTime - Maximum time in milliseconds to stay in IDLE before restarting
299
+ * @returns Void on success, false on failure, or undefined if not in SELECTED state
332
300
  */
333
- module.exports = async (connection, maxIdleTime) => {
301
+ export default async function idle(connection, maxIdleTime) {
334
302
  if (connection.state !== connection.states.SELECTED) {
335
303
  // nothing to do here
336
304
  return;
337
305
  }
338
-
339
306
  // If server supports IDLE (RFC 2177, folded into base IMAP4rev2), use it for
340
307
  // real-time push notifications. Otherwise, fall back to periodic polling with
341
308
  // NOOP/STATUS/SELECT.
@@ -354,7 +321,7 @@ module.exports = async (connection, maxIdleTime) => {
354
321
  stillIdling = true;
355
322
  // request IDLE break if IDLE has been running for allowed time
356
323
  connection.log.trace({ msg: 'Max allowed IDLE time reached', cid: connection.id });
357
- connection.preCheck().catch(err => logConnectionError(connection, 'Failed to break IDLE for restart', err));
324
+ connection.preCheck().catch((err) => logConnectionError(connection, 'Failed to break IDLE for restart', err));
358
325
  }
359
326
  }
360
327
  }, maxIdleTime);
@@ -369,8 +336,7 @@ module.exports = async (connection, maxIdleTime) => {
369
336
  stillIdling = false;
370
337
  }
371
338
  }
372
-
373
339
  // Fallback for servers without IDLE support: poll at regular intervals using
374
340
  // NOOP (default), STATUS, or SELECT depending on missingIdleCommand config.
375
341
  return runPollingFallback(connection, maxIdleTime);
376
- };
342
+ }
@@ -0,0 +1,16 @@
1
+ import type { ImapFlow } from '../imap-flow.js';
2
+ import type { ListOptions, ListResponse } from '../types.js';
3
+ /**
4
+ * Lists mailboxes from the server, including subscription status and special-use flags.
5
+ *
6
+ * @param connection - IMAP connection instance
7
+ * @param reference - Reference name (namespace prefix)
8
+ * @param mailbox - Mailbox name pattern with possible wildcards
9
+ * @param options - List options
10
+ * @param options.listOnly - If true, return entries after LIST without LSUB or status queries
11
+ * @param options.statusQuery - Status data items to query for each listed mailbox
12
+ * @param options.specialUseHints - Hints mapping mailbox paths to special-use types (sent, junk, trash, drafts, archive)
13
+ * @returns Array of mailbox entries sorted by special-use flags and name
14
+ * @throws If the LIST command fails
15
+ */
16
+ export default function list(connection: ImapFlow, reference: string | undefined, mailbox: string | undefined, options?: ListOptions | undefined): Promise<ListResponse[]>;