imapflow 1.7.8 → 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 +20 -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 +761 -1789
  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 -101
  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 -909
  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 -661
@@ -0,0 +1,30 @@
1
+ import type { ImapFlow } from '../imap-flow.js';
2
+ import type { FetchMessageObject, FetchOptions, FetchQueryObject } from '../types.js';
3
+ /**
4
+ * Options for the FETCH command
5
+ */
6
+ export interface FetchCommandOptions extends Omit<FetchOptions, 'changedSince'> {
7
+ /** Only fetch messages changed since this modseq value */
8
+ changedSince?: bigint | number | string | undefined;
9
+ /** Callback for processing each fetched message individually. Call `next()` to release the next message */
10
+ onUntaggedFetch?: ((message: FetchMessageObject, next: (err?: Error | null | undefined) => void) => void) | undefined;
11
+ }
12
+ /**
13
+ * Result of the FETCH command
14
+ */
15
+ export interface FetchCommandResult {
16
+ /** Number of untagged FETCH responses received */
17
+ count: number;
18
+ /** Formatted messages, empty when `onUntaggedFetch` consumed them */
19
+ list: FetchMessageObject[];
20
+ }
21
+ /**
22
+ * Fetches emails from the server.
23
+ *
24
+ * @param connection - IMAP connection instance
25
+ * @param range - Message sequence number or UID range
26
+ * @param query - Fetch query specifying which data to retrieve (e.g., flags, envelope, bodyStructure, headers, source, bodyParts)
27
+ * @param options - Fetch options
28
+ * @returns Object with message count and list, or undefined if not in SELECTED state
29
+ */
30
+ export default function fetch(connection: ImapFlow, range: string, query: FetchQueryObject, options?: FetchCommandOptions | undefined): Promise<FetchCommandResult | undefined>;
@@ -1,88 +1,67 @@
1
- 'use strict';
2
-
3
- const { formatMessageResponse, isRev2Active } = require('../tools');
4
-
1
+ import { formatMessageResponse, isRev2Active } from '../tools.js';
5
2
  /**
6
3
  * Fetches emails from the server.
7
4
  *
8
- * @param {Object} connection - IMAP connection instance
9
- * @param {string} range - Message sequence number or UID range
10
- * @param {Object} query - Fetch query specifying which data to retrieve (e.g., flags, envelope, bodyStructure, headers, source, bodyParts)
11
- * @param {Object} [options] - Fetch options
12
- * @param {boolean} [options.uid] - If true, use UID FETCH instead of FETCH
13
- * @param {boolean} [options.binary] - If true, use BINARY fetch when available
14
- * @param {string} [options.changedSince] - Only fetch messages changed since this modseq value
15
- * @param {Function} [options.onUntaggedFetch] - Callback for processing each fetched message individually
16
- * @returns {Promise<{count: number, list: Object[]}|undefined>} Object with message count and list, or undefined if not in SELECTED state
5
+ * @param connection - IMAP connection instance
6
+ * @param range - Message sequence number or UID range
7
+ * @param query - Fetch query specifying which data to retrieve (e.g., flags, envelope, bodyStructure, headers, source, bodyParts)
8
+ * @param options - Fetch options
9
+ * @returns Object with message count and list, or undefined if not in SELECTED state
17
10
  */
18
- module.exports = async (connection, range, query, options) => {
11
+ export default async function fetch(connection, range, query, options) {
19
12
  if (connection.state !== connection.states.SELECTED || !range) {
20
13
  // nothing to do here
21
14
  return;
22
15
  }
23
-
24
16
  options = options || {};
25
-
26
17
  let mailbox = connection.mailbox;
27
-
28
18
  // Use BINARY extension for fetching if supported and requested, otherwise fall back to BODY.
29
19
  // RFC 9051 folds the FETCH side of the BINARY extension into base IMAP4rev2, so an active
30
20
  // rev2 session can use it even without the BINARY capability token (the APPEND side is NOT
31
- // folded in and stays gated on the token in append.js)
21
+ // folded in and stays gated on the token in append.ts)
32
22
  const canUseBinary = connection.capabilities.has('BINARY') || isRev2Active(connection);
33
23
  const commandKey = canUseBinary && options.binary && !connection.disableBinary ? 'BINARY' : 'BODY';
34
-
35
24
  // Retry logic for ETHROTTLE errors (server rate limiting) with exponential backoff
36
25
  let retryCount = 0;
37
26
  const maxRetries = 4;
38
27
  const baseDelay = 1000; // Start with 1 second delay
39
-
40
28
  while (retryCount < maxRetries) {
41
29
  let messages = {
42
30
  count: 0,
43
31
  list: []
44
32
  };
45
-
46
33
  let response;
47
34
  try {
48
35
  /* c8 ignore next */ // range is guaranteed truthy by the early-return guard above, so the '*' fallback is unreachable
49
36
  let attributes = [{ type: 'SEQUENCE', value: (range || '*').toString() }];
50
-
51
37
  let queryStructure = [];
52
-
53
38
  // Helper to build BODY.PEEK[section]<partial> or BINARY.PEEK[section]<partial> atoms.
54
39
  // PEEK avoids marking messages as \Seen. Section identifies what to fetch (HEADER, specific part, etc.)
55
40
  // Partial is an optional byte range [start, maxLength].
56
41
  let setBodyPeek = (attributes, partial) => {
57
42
  let section = [].concat(attributes || []);
58
-
59
43
  // BINARY may only address the empty section or a numeric part specifier
60
44
  // (RFC 3516 / RFC 9051 section-binary) - HEADER, HEADER.FIELDS, TEXT and
61
45
  // n.MIME are invalid after BINARY and must stay BODY fetches
62
- let binaryAddressable =
63
- !section.length || (section.length === 1 && typeof section[0].value === 'string' && /^\d+(\.\d+)*$/.test(section[0].value));
64
-
46
+ let first = section[0];
47
+ let binaryAddressable = !section.length || (section.length === 1 && typeof first.value === 'string' && /^\d+(\.\d+)*$/.test(first.value));
65
48
  let bodyPeek = {
66
49
  type: 'ATOM',
67
50
  value: `${binaryAddressable ? commandKey : 'BODY'}.PEEK`,
68
- section,
51
+ section: section,
69
52
  partial
70
53
  };
71
-
72
54
  queryStructure.push(bodyPeek);
73
55
  };
74
-
75
56
  // IMAP fetch macros (ALL, FAST, FULL) and standard data items map directly to IMAP atoms
76
57
  ['all', 'fast', 'full', 'uid', 'flags', 'bodyStructure', 'envelope', 'internalDate'].forEach(key => {
77
58
  if (query[key]) {
78
59
  queryStructure.push({ type: 'ATOM', value: key.toUpperCase() });
79
60
  }
80
61
  });
81
-
82
62
  if (query.size) {
83
63
  queryStructure.push({ type: 'ATOM', value: 'RFC822.SIZE' });
84
64
  }
85
-
86
65
  // Fetch full message source, optionally with byte range (start/maxLength)
87
66
  if (query.source) {
88
67
  let partial;
@@ -94,51 +73,47 @@ module.exports = async (connection, range, query, options) => {
94
73
  }
95
74
  setBodyPeek(null, partial);
96
75
  }
97
-
98
76
  // Always request a unique email ID for message deduplication.
99
77
  // Prefer OBJECTID (RFC 8474) over Gmail's X-GM-MSGID extension.
100
78
  if (connection.capabilities.has('OBJECTID')) {
101
79
  queryStructure.push({ type: 'ATOM', value: 'EMAILID' });
102
- } else if (connection.capabilities.has('X-GM-EXT-1')) {
80
+ }
81
+ else if (connection.capabilities.has('X-GM-EXT-1')) {
103
82
  queryStructure.push({ type: 'ATOM', value: 'X-GM-MSGID' });
104
83
  }
105
-
106
84
  // Thread ID: OBJECTID's THREADID or Gmail's X-GM-THRID
107
85
  if (query.threadId) {
108
86
  if (connection.capabilities.has('OBJECTID')) {
109
87
  queryStructure.push({ type: 'ATOM', value: 'THREADID' });
110
- } else if (connection.capabilities.has('X-GM-EXT-1')) {
88
+ }
89
+ else if (connection.capabilities.has('X-GM-EXT-1')) {
111
90
  queryStructure.push({ type: 'ATOM', value: 'X-GM-THRID' });
112
91
  }
113
92
  }
114
-
115
93
  // Gmail labels are only available with X-GM-EXT-1 extension
116
94
  if (query.labels) {
117
95
  if (connection.capabilities.has('X-GM-EXT-1')) {
118
96
  queryStructure.push({ type: 'ATOM', value: 'X-GM-LABELS' });
119
97
  }
120
98
  }
121
-
122
99
  // always ask for modseq if possible
123
100
  if (connection.enabled.has('CONDSTORE') && !mailbox.noModseq) {
124
101
  queryStructure.push({ type: 'ATOM', value: 'MODSEQ' });
125
102
  }
126
-
127
103
  // Always include UID in the response even if not explicitly requested,
128
104
  // since we use it internally for message identification and tracking
129
105
  if (!query.uid) {
130
106
  queryStructure.push({ type: 'ATOM', value: 'UID' });
131
107
  }
132
-
133
108
  // Headers: fetch all headers or only specific ones via HEADER.FIELDS
134
109
  if (query.headers) {
135
110
  if (Array.isArray(query.headers)) {
136
111
  setBodyPeek([{ type: 'ATOM', value: 'HEADER.FIELDS' }, query.headers.map(header => ({ type: 'ATOM', value: header }))]);
137
- } else {
112
+ }
113
+ else {
138
114
  setBodyPeek({ type: 'ATOM', value: 'HEADER' });
139
115
  }
140
116
  }
141
-
142
117
  // Fetch specific body parts by MIME part number (e.g., "1", "1.2", "2.MIME")
143
118
  // Each part can optionally include a byte range (start/maxLength)
144
119
  if (query.bodyParts && query.bodyParts.length) {
@@ -159,24 +134,23 @@ module.exports = async (connection, range, query, options) => {
159
134
  partial.push(Number(part.maxLength));
160
135
  }
161
136
  }
162
- } else if (typeof part === 'string') {
137
+ }
138
+ else if (typeof part === 'string') {
163
139
  key = part.toUpperCase();
164
- } else {
140
+ }
141
+ else {
165
142
  return;
166
143
  }
167
-
168
144
  setBodyPeek({ type: 'ATOM', value: key }, partial);
169
145
  });
170
146
  }
171
-
172
147
  // IMAP requires a single item to not be wrapped in parentheses, but
173
148
  // multiple items must be in a list. If only one item, unwrap the array.
149
+ let queryAttribute = queryStructure;
174
150
  if (queryStructure.length === 1) {
175
- queryStructure = queryStructure.pop();
151
+ queryAttribute = queryStructure.pop();
176
152
  }
177
-
178
- attributes.push(queryStructure);
179
-
153
+ attributes.push(queryAttribute);
180
154
  // CONDSTORE extension: only fetch messages with modseq higher than the given value.
181
155
  // QRESYNC adds VANISHED to also get expunged UIDs since last sync.
182
156
  if (options.changedSince && connection.enabled.has('CONDSTORE') && !mailbox.noModseq) {
@@ -190,23 +164,20 @@ module.exports = async (connection, range, query, options) => {
190
164
  value: options.changedSince.toString()
191
165
  }
192
166
  ];
193
-
194
167
  if (options.uid && connection.enabled.has('QRESYNC')) {
195
168
  changedSinceArgs.push({
196
169
  type: 'ATOM',
197
170
  value: 'VANISHED'
198
171
  });
199
172
  }
200
-
201
173
  attributes.push(changedSinceArgs);
202
174
  }
203
-
204
175
  response = await connection.exec(options.uid ? 'UID FETCH' : 'FETCH', attributes, {
205
176
  untagged: {
206
177
  // Each matching message triggers an untagged FETCH response.
207
178
  // If onUntaggedFetch callback is provided, stream messages to it one by one
208
179
  // (useful for large result sets). Otherwise, collect all into messages.list.
209
- FETCH: async untagged => {
180
+ FETCH: async (untagged) => {
210
181
  messages.count++;
211
182
  let formatted = await formatMessageResponse(untagged, mailbox);
212
183
  if (typeof options.onUntaggedFetch === 'function') {
@@ -214,32 +185,32 @@ module.exports = async (connection, range, query, options) => {
214
185
  options.onUntaggedFetch(formatted, err => {
215
186
  if (err) {
216
187
  reject(err);
217
- } else {
188
+ }
189
+ else {
218
190
  resolve();
219
191
  }
220
192
  });
221
193
  });
222
- } else {
194
+ }
195
+ else {
223
196
  messages.list.push(formatted);
224
197
  }
225
198
  }
226
199
  }
227
200
  });
228
-
229
201
  response.next();
230
202
  return messages;
231
- } catch (err) {
203
+ }
204
+ catch (err) {
232
205
  if (err.code === 'ETHROTTLE') {
233
206
  // Server returned a throttle error (rate limiting). Retry with exponential backoff.
234
207
  // Delay doubles each retry: 1s, 2s, 4s, 8s (capped at 30s).
235
208
  // If server provides a throttleReset hint, use that if longer.
236
209
  const backoffDelay = Math.min(baseDelay * Math.pow(2, retryCount), 30000); // Cap at 30 seconds
237
-
238
210
  // Use throttle reset time if provided and longer than backoff. The hint is
239
211
  // server-controlled, so the wait goes through connection.throttleWait(), which caps
240
212
  // it and keeps the timer tracked and abortable.
241
213
  const delay = err.throttleReset && err.throttleReset > backoffDelay ? err.throttleReset : backoffDelay;
242
-
243
214
  connection.log.warn({
244
215
  msg: 'Retrying throttled request with exponential backoff',
245
216
  cid: connection.id,
@@ -249,20 +220,17 @@ module.exports = async (connection, range, query, options) => {
249
220
  retryCount,
250
221
  delayMs: delay
251
222
  });
252
-
253
223
  // An aborted wait means the client was closed, so give up rather than reissuing
254
224
  // the FETCH on a connection that is already gone.
255
225
  let aborted = await connection.throttleWait(delay);
256
226
  if (aborted) {
257
227
  throw connection.createNoConnectionError(connection.byeReason, { rejectedFrom: 'throttleAbort', command: 'FETCH' });
258
228
  }
259
-
260
229
  retryCount++;
261
230
  continue;
262
231
  }
263
-
264
232
  connection.log.warn({ err, cid: connection.id });
265
233
  throw err;
266
234
  }
267
235
  }
268
- };
236
+ }
@@ -0,0 +1,10 @@
1
+ import type { ImapFlow } from '../imap-flow.js';
2
+ import type { IdInfoObject } from '../types.js';
3
+ /**
4
+ * Sends ID info to the server and updates server info data based on the response.
5
+ *
6
+ * @param connection - IMAP connection instance
7
+ * @param clientInfo - Client identification key-value pairs to send to the server
8
+ * @returns Server information map, false on failure, or undefined if ID not supported
9
+ */
10
+ export default function id(connection: ImapFlow, clientInfo?: IdInfoObject | null | undefined): Promise<IdInfoObject | false | undefined>;
@@ -1,51 +1,45 @@
1
- 'use strict';
2
-
3
- const { formatDateTime } = require('../tools.js');
4
-
1
+ import { formatDateTime } from '../tools.js';
5
2
  /**
6
3
  * Sends ID info to the server and updates server info data based on the response.
7
4
  *
8
- * @param {Object} connection - IMAP connection instance
9
- * @param {Object} clientInfo - Client identification key-value pairs to send to the server
10
- * @returns {Promise<Object|boolean|undefined>} Server information map, false on failure, or undefined if ID not supported
5
+ * @param connection - IMAP connection instance
6
+ * @param clientInfo - Client identification key-value pairs to send to the server
7
+ * @returns Server information map, false on failure, or undefined if ID not supported
11
8
  */
12
9
  // RFC 2971: The ID command exchanges client/server implementation info
13
10
  // (name, version, vendor, etc.) for diagnostic and compatibility purposes.
14
- module.exports = async (connection, clientInfo) => {
11
+ export default async function id(connection, clientInfo) {
15
12
  if (!connection.capabilities.has('ID')) {
16
13
  // nothing to do here
17
14
  return;
18
15
  }
19
-
20
16
  let response;
21
17
  try {
22
18
  let map = {};
23
-
24
19
  // Convert the clientInfo object into a flat array of alternating key-value strings
25
20
  // for the IMAP wire format: ("key1" "value1" "key2" "value2" ...)
26
21
  let formattedClientInfo = !clientInfo
27
22
  ? null
28
23
  : Object.keys(clientInfo)
29
- .map(key => [key, formatValue(key, clientInfo[key])])
30
- .filter(entry => entry[1])
31
- .flatMap(entry => entry);
32
-
24
+ .map(key => [key, formatValue(key, clientInfo[key])])
25
+ .filter(entry => entry[1])
26
+ .flatMap(entry => entry);
33
27
  if (formattedClientInfo && !formattedClientInfo.length) {
34
28
  // value array has no elements
35
29
  formattedClientInfo = null;
36
30
  }
37
-
38
31
  response = await connection.exec('ID', [formattedClientInfo], {
39
32
  untagged: {
40
33
  // Parse the server's ID response: a flat list of alternating key-value atoms.
41
34
  // Even indices (i % 2 === 0) are keys, odd indices are the corresponding values.
42
- ID: async untagged => {
35
+ ID: async (untagged) => {
43
36
  let params = untagged.attributes && untagged.attributes[0];
44
37
  let key;
45
38
  (Array.isArray(params) ? params : [].concat(params || [])).forEach((val, i) => {
46
39
  if (i % 2 === 0) {
47
40
  key = val.value;
48
- } else if (typeof key === 'string' && typeof val.value === 'string') {
41
+ }
42
+ else if (typeof key === 'string' && typeof val.value === 'string') {
49
43
  map[key.toLowerCase().trim()] = val.value;
50
44
  }
51
45
  });
@@ -55,18 +49,18 @@ module.exports = async (connection, clientInfo) => {
55
49
  connection.serverInfo = map;
56
50
  response.next();
57
51
  return map;
58
- } catch (err) {
52
+ }
53
+ catch (err) {
59
54
  connection.log.warn({ err, cid: connection.id });
60
55
  return false;
61
56
  }
62
- };
63
-
57
+ }
64
58
  /**
65
59
  * Formats a client info value for the ID command.
66
60
  *
67
- * @param {string} key - The info key name
68
- * @param {*} value - The value to format
69
- * @returns {string} Formatted value string
61
+ * @param key - The info key name
62
+ * @param value - The value to format
63
+ * @returns Formatted value string
70
64
  */
71
65
  function formatValue(key, value) {
72
66
  switch (key.toLowerCase()) {
@@ -0,0 +1,9 @@
1
+ import type { ImapFlow } from '../imap-flow.js';
2
+ /**
3
+ * Listens for changes in the selected mailbox using IDLE or NOOP polling fallback.
4
+ *
5
+ * @param connection - IMAP connection instance
6
+ * @param maxIdleTime - Maximum time in milliseconds to stay in IDLE before restarting
7
+ * @returns Void on success, false on failure, or undefined if not in SELECTED state
8
+ */
9
+ export default function idle(connection: ImapFlow, maxIdleTime?: number | false | undefined): Promise<void | false | undefined>;