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
@@ -1,59 +1,26 @@
1
- 'use strict';
2
-
3
- const Transform = require('stream').Transform;
4
- const logger = require('../logger');
5
- const { MAX_LITERAL_SIZE, MAX_LINE_SIZE, MAX_RESPONSE_SIZE, normalizeLimit, createLiteralTooLargeError } = require('./limits');
6
-
1
+ import { Transform } from 'node:stream';
2
+ import logger from '../logger.js';
3
+ import { MAX_LITERAL_SIZE, MAX_LINE_SIZE, MAX_RESPONSE_SIZE, normalizeLimit, createLiteralTooLargeError } from './limits.js';
7
4
  const LINE = 0x01;
8
5
  const LITERAL = 0x02;
9
-
10
6
  const LF = 0x0a;
11
7
  const CR = 0x0d;
12
8
  const NUM_0 = 0x30;
13
9
  const NUM_9 = 0x39;
14
10
  const CURLY_OPEN = 0x7b;
15
11
  const CURLY_CLOSE = 0x7d;
16
-
17
12
  /**
18
13
  * A Transform stream that parses raw IMAP protocol data from a socket into structured
19
14
  * command/response objects. Reads binary input, splits it into lines delimited by LF,
20
15
  * extracts literal data blocks based on IMAP literal size markers (e.g., "{123}\r\n"),
21
16
  * and emits each complete command as a readable object containing the payload Buffer
22
17
  * and any associated literal Buffers. Enforces a maximum literal size of 1GB.
23
- *
24
- * @extends Transform
25
18
  */
26
- class ImapStream extends Transform {
19
+ export class ImapStream extends Transform {
27
20
  /**
28
21
  * Creates a new ImapStream instance.
29
22
  *
30
- * @param {Object} [options] - Stream options.
31
- * @param {string} [options.cid] - Connection identifier used for logging.
32
- * @param {Object} [options.logger] - A pino-compatible logger instance. If not provided, a default child logger is created.
33
- * @param {boolean} [options.logRaw] - If true, logs raw socket data at trace level.
34
- * @param {boolean} [options.secureConnection] - Whether the connection uses TLS.
35
- * @param {number} [options.maxLineLength] - Maximum allowed length (in bytes) of a single
36
- * line (a response without a literal). Defaults to MAX_LITERAL_SIZE (1GB). Guards against a
37
- * malicious or broken server that never sends a line terminator, which would otherwise grow
38
- * the internal line buffer without bound. The line terminator counts toward the limit, and a
39
- * line exactly at the limit is accepted. Exceeding it is terminal: the stream is destroyed
40
- * with a `LineTooLarge` error and no further input is parsed.
41
- * @param {number} [options.maxLiteralSize] - Maximum allowed size (in bytes) of a single
42
- * literal block. Defaults to MAX_LITERAL_SIZE (1GB). Lower it to bound peak memory
43
- * allocation against a malicious or broken server announcing an oversized literal. A literal
44
- * exactly at the limit is accepted. Exceeding it is terminal: the stream is destroyed with a
45
- * `LiteralTooLarge` error, the marker line is not emitted, and no byte of the rejected
46
- * literal body is parsed as protocol.
47
- * @param {number} [options.maxResponseSize] - Maximum allowed total size (in bytes) of a
48
- * single assembled response: every line segment and literal of one response combined.
49
- * Defaults to MAX_RESPONSE_SIZE (2GB), which leaves room above the literal cap for a
50
- * maximum-size literal plus its marker line. The per-line and per-literal caps alone
51
- * cannot stop a server that spreads attacker-controlled bytes across an unbounded
52
- * number of tokens of a single response. Declared literal sizes count when their
53
- * marker is parsed, so an oversized total is rejected before the literal bytes arrive,
54
- * and a line still being assembled counts against whatever budget is left.
55
- * Exceeding the limit is terminal: the stream is destroyed with a `ResponseTooLarge`
56
- * error and no further input is parsed.
23
+ * @param options - Stream options, see ImapStreamOptions.
57
24
  */
58
25
  constructor(options) {
59
26
  super({
@@ -61,30 +28,23 @@ class ImapStream extends Transform {
61
28
  readableObjectMode: true,
62
29
  writableObjectMode: false
63
30
  });
64
-
65
31
  this.options = options || {};
66
32
  this.cid = this.options.cid;
67
-
68
33
  this.log =
69
34
  this.options.logger && typeof this.options.logger === 'object'
70
35
  ? this.options.logger
71
36
  : logger.child({
72
- component: 'imap-connection',
73
- cid: this.cid
74
- });
75
-
37
+ component: 'imap-connection',
38
+ cid: this.cid
39
+ });
76
40
  this.readBytesCounter = 0;
77
-
78
41
  // Maximum length of a single line (response without a literal). Bounds the line buffer
79
42
  // so a server that never sends a line terminator cannot exhaust memory.
80
43
  this.maxLineLength = normalizeLimit(this.options.maxLineLength, MAX_LINE_SIZE);
81
-
82
44
  // Maximum size of a single literal block. Bounds peak memory allocation so a server
83
45
  // announcing an oversized literal cannot exhaust memory.
84
46
  this.maxLiteralSize = normalizeLimit(this.options.maxLiteralSize, MAX_LITERAL_SIZE);
85
-
86
47
  this.maxResponseSize = normalizeLimit(this.options.maxResponseSize, MAX_RESPONSE_SIZE);
87
-
88
48
  this.state = LINE;
89
49
  this.literalWaiting = 0;
90
50
  this.inputBuffer = []; // lines
@@ -93,19 +53,15 @@ class ImapStream extends Transform {
93
53
  this.literalBuffer = [];
94
54
  this.literals = [];
95
55
  this.responseBytes = 0; // bytes accumulated for the in-progress response (lines + declared literals)
96
-
97
56
  this.compress = false;
98
57
  this.secureConnection = this.options.secureConnection;
99
-
100
58
  this.processingInput = false;
101
59
  this.inputQueue = []; // unprocessed input chunks
102
60
  this.activeInput = null; // chunk currently being processed (already shifted off inputQueue)
103
-
104
61
  // Resolver of the in-flight push() backpressure promise, so destruction can settle it
105
62
  // instead of leaving processInput() awaiting a consumer that will never read again.
106
63
  this.pendingPush = null;
107
64
  }
108
-
109
65
  /**
110
66
  * Terminally fails the stream. Used for response limit violations and for any other
111
67
  * error raised while parsing.
@@ -119,8 +75,8 @@ class ImapStream extends Transform {
119
75
  * `destroyed` (set synchronously by destroy()) is the single liveness flag every other path
120
76
  * checks, so a second failure attempt is a no-op and nothing is parsed after the first.
121
77
  *
122
- * @param {Error} err - The error to destroy the stream with.
123
- * @returns {boolean} Always false, so callers can `return this.failStream(err)`.
78
+ * @param err - The error to destroy the stream with.
79
+ * @returns Always false, so callers can `return this.failStream(err)`.
124
80
  */
125
81
  failStream(err) {
126
82
  if (this.destroyed) {
@@ -129,13 +85,12 @@ class ImapStream extends Transform {
129
85
  this.destroy(err);
130
86
  return false;
131
87
  }
132
-
133
88
  /**
134
89
  * Releases a queued input chunk's transform callback exactly once, signalling the writable
135
90
  * side that the chunk was consumed. The mirror image of ImapFlow's releaseStreamData(), which
136
91
  * releases the readable items this stream pushes downstream.
137
92
  *
138
- * @param {Object} item - Queue entry holding the chunk and its transform callback.
93
+ * @param item - Queue entry holding the chunk and its transform callback.
139
94
  */
140
95
  releaseInput(item) {
141
96
  if (!item || item.released) {
@@ -146,37 +101,31 @@ class ImapStream extends Transform {
146
101
  item.next();
147
102
  }
148
103
  }
149
-
150
104
  /**
151
105
  * Checks whether the given line buffer ends with an IMAP literal size marker
152
106
  * (e.g., "{123}\r\n"). If a valid marker is found and the literal size is within
153
107
  * the allowed maximum, switches the stream state to LITERAL mode and records
154
108
  * the expected number of literal bytes.
155
109
  *
156
- * @param {Buffer} line - The line buffer to check for a trailing literal marker.
157
- * @returns {boolean} True if a valid literal marker was found and literal state was activated, false otherwise.
110
+ * @param line - The line buffer to check for a trailing literal marker.
111
+ * @returns True if a valid literal marker was found and literal state was activated, false otherwise.
158
112
  */
159
113
  checkLiteralMarker(line) {
160
114
  if (!line || !line.length) {
161
115
  return false;
162
116
  }
163
-
164
117
  let pos = line.length - 1;
165
-
166
118
  if (line[pos] !== LF) {
167
119
  return false;
168
120
  }
169
121
  pos--;
170
-
171
122
  if (pos >= 0 && line[pos] === CR) {
172
123
  pos--;
173
124
  }
174
-
175
125
  if (pos < 0 || !pos || line[pos] !== CURLY_CLOSE) {
176
126
  return false;
177
127
  }
178
128
  pos--;
179
-
180
129
  // Scan backwards through the line to find an IMAP literal marker: {size}\r\n
181
130
  // The format is: '{' followed by one or more ASCII digits followed by '}'.
182
131
  // Only the digit run's bounds are tracked - a single linear pass, unlike
@@ -200,19 +149,15 @@ class ImapStream extends Transform {
200
149
  while (digitsStart < digitsEnd && line[digitsStart] === NUM_0) {
201
150
  digitsStart++;
202
151
  }
203
-
204
152
  // More significant digits than any number64 has cannot fit any
205
153
  // permissible maxLiteralSize; fail closed without materializing them
206
154
  if (digitsEnd + 1 - digitsStart > 19) {
207
155
  return this.failStream(createLiteralTooLargeError(Infinity, this.maxLiteralSize, 'the widest permissible literal size (19 digits)'));
208
156
  }
209
-
210
157
  const literalSize = Number(line.toString('latin1', digitsStart, digitsEnd + 1));
211
-
212
158
  if (literalSize > this.maxLiteralSize) {
213
159
  return this.failStream(createLiteralTooLargeError(literalSize, this.maxLiteralSize));
214
160
  }
215
-
216
161
  this.state = LITERAL;
217
162
  this.literalWaiting = literalSize;
218
163
  return true;
@@ -221,14 +166,13 @@ class ImapStream extends Transform {
221
166
  }
222
167
  return false;
223
168
  }
224
-
225
169
  /**
226
170
  * Enforces the configured line-length cap for a projected line length. The projected length
227
171
  * covers every byte of the line, the line terminator included, whether or not the line was
228
172
  * split across input chunks. A line exactly at the limit is accepted.
229
173
  *
230
- * @param {number} lineLength - Total length the current line would reach.
231
- * @returns {boolean} True if the line is within the limit, false if the stream was failed.
174
+ * @param lineLength - Total length the current line would reach.
175
+ * @returns True if the line is within the limit, false if the stream was failed.
232
176
  */
233
177
  checkLineLength(lineLength) {
234
178
  if (lineLength <= this.maxLineLength) {
@@ -240,18 +184,17 @@ class ImapStream extends Transform {
240
184
  err.maxSize = this.maxLineLength;
241
185
  return this.failStream(err);
242
186
  }
243
-
244
187
  /**
245
188
  * Enforces the configured per-response size cap: the cumulative bytes of every line
246
189
  * segment and declared literal of the response currently being assembled. Counting
247
190
  * declared literal sizes at marker time means an oversized total is rejected before
248
191
  * the literal bytes even arrive. The counter is reset when a response is emitted.
249
192
  *
250
- * @param {number} additionalBytes - Bytes the next token would add to the response.
251
- * @param {boolean} [peek] - Measure only, without committing the bytes to the counter.
193
+ * @param additionalBytes - Bytes the next token would add to the response.
194
+ * @param peek - Measure only, without committing the bytes to the counter.
252
195
  * Used for a line that is still being assembled: its bytes are committed once, when the
253
196
  * line completes.
254
- * @returns {boolean} True if within the limit, false if the stream was failed.
197
+ * @returns True if within the limit, false if the stream was failed.
255
198
  */
256
199
  checkResponseSize(additionalBytes, peek) {
257
200
  let total = this.responseBytes + additionalBytes;
@@ -267,23 +210,20 @@ class ImapStream extends Transform {
267
210
  err.maxSize = this.maxResponseSize;
268
211
  return this.failStream(err);
269
212
  }
270
-
271
213
  /**
272
214
  * Processes a single input chunk of raw data. In LINE state, scans for LF-terminated
273
215
  * lines and checks for literal markers. In LITERAL state, collects the expected number
274
216
  * of literal bytes. When a complete command (with all its literals) is assembled, it is
275
217
  * pushed downstream as a readable object.
276
218
  *
277
- * @param {Buffer} chunk - The raw data chunk to process.
278
- * @param {number} [startPos=0] - The byte offset within the chunk to start processing from.
279
- * @returns {Promise<void>}
219
+ * @param chunk - The raw data chunk to process.
220
+ * @param startPos - The byte offset within the chunk to start processing from.
280
221
  */
281
222
  async processInputChunk(chunk, startPos) {
282
223
  startPos = startPos || 0;
283
224
  if (this.destroyed || startPos >= chunk.length) {
284
225
  return;
285
226
  }
286
-
287
227
  switch (this.state) {
288
228
  case LINE: {
289
229
  let lineStart = startPos;
@@ -296,15 +236,11 @@ class ImapStream extends Transform {
296
236
  if (!this.checkLineLength(this.lineBytes + segment.length)) {
297
237
  return;
298
238
  }
299
-
300
239
  this.lineBuffer.push(segment);
301
240
  lineStart = i + 1;
302
-
303
241
  let line = this.lineBuffer.length === 1 ? this.lineBuffer[0] : Buffer.concat(this.lineBuffer);
304
-
305
242
  this.lineBuffer = [];
306
243
  this.lineBytes = 0;
307
-
308
244
  // try to detect if this is a literal start. An oversized literal fails the
309
245
  // stream, so the marker line must not be buffered before the check - it
310
246
  // would otherwise be emitted as part of the rejected command.
@@ -312,28 +248,23 @@ class ImapStream extends Transform {
312
248
  if (this.destroyed) {
313
249
  return;
314
250
  }
315
-
316
251
  // Count the line itself and, for a literal marker, the declared
317
252
  // literal bytes against the cumulative per-response budget, so a
318
253
  // response assembled from many tokens stays bounded as a whole
319
254
  if (!this.checkResponseSize(line.length + (isLiteralMarker ? this.literalWaiting : 0))) {
320
255
  return;
321
256
  }
322
-
323
257
  this.inputBuffer.push(line);
324
-
325
258
  if (isLiteralMarker) {
326
259
  // switch into literal mode and start over
327
260
  return await this.processInputChunk(chunk, lineStart);
328
261
  }
329
-
330
262
  // reached end of command input, emit it
331
263
  let payload = this.inputBuffer.length === 1 ? this.inputBuffer[0] : Buffer.concat(this.inputBuffer);
332
264
  let literals = this.literals;
333
265
  this.inputBuffer = [];
334
266
  this.literals = [];
335
267
  this.responseBytes = 0;
336
-
337
268
  if (payload.length) {
338
269
  // remove final line terminator (\n or \r\n)
339
270
  if (payload[payload.length - 1] === LF) {
@@ -343,10 +274,9 @@ class ImapStream extends Transform {
343
274
  }
344
275
  payload = payload.slice(0, end);
345
276
  }
346
-
347
277
  if (payload.length) {
348
278
  // Whether more buffered input already followed this command on the
349
- // wire — more bytes in this chunk or another queued chunk. Captured
279
+ // wire - more bytes in this chunk or another queued chunk. Captured
350
280
  // per emitted command (immutable on the pushed object) so a later
351
281
  // command cannot overwrite it; consumers that care about pipelining
352
282
  // boundaries can read it from the pushed object.
@@ -356,10 +286,10 @@ class ImapStream extends Transform {
356
286
  // this loop (and the chunk's transform callback) pending forever
357
287
  // when the consumer stops reading.
358
288
  this.pendingPush = resolve;
359
- this.push({ payload, literals, next: resolve, trailingAfterLine });
289
+ const item = { payload, literals, next: resolve, trailingAfterLine };
290
+ this.push(item);
360
291
  });
361
292
  this.pendingPush = null;
362
-
363
293
  if (this.destroyed) {
364
294
  return;
365
295
  }
@@ -384,20 +314,16 @@ class ImapStream extends Transform {
384
314
  }
385
315
  break;
386
316
  }
387
-
388
317
  case LITERAL: {
389
318
  const remainingInChunk = chunk.length - startPos;
390
319
  const bytesToRead = Math.min(remainingInChunk, this.literalWaiting);
391
320
  const partial = startPos === 0 && bytesToRead === chunk.length ? chunk : chunk.slice(startPos, startPos + bytesToRead);
392
-
393
321
  this.literalBuffer.push(partial);
394
322
  this.literalWaiting -= bytesToRead;
395
-
396
323
  if (this.literalWaiting === 0) {
397
324
  this.literals.push(Buffer.concat(this.literalBuffer));
398
325
  this.literalBuffer = [];
399
326
  this.state = LINE;
400
-
401
327
  if (remainingInChunk > bytesToRead) {
402
328
  return await this.processInputChunk(chunk, startPos + bytesToRead);
403
329
  }
@@ -406,13 +332,10 @@ class ImapStream extends Transform {
406
332
  }
407
333
  }
408
334
  }
409
-
410
335
  /**
411
336
  * Drains the input queue by processing each queued chunk sequentially.
412
337
  * Yields to the event loop every 10 chunks to prevent CPU blocking on
413
338
  * large bursts of incoming data.
414
- *
415
- * @returns {Promise<void>}
416
339
  */
417
340
  async processInput() {
418
341
  let data;
@@ -423,7 +346,6 @@ class ImapStream extends Transform {
423
346
  this.activeInput = null;
424
347
  // mark chunk as processed
425
348
  this.releaseInput(data);
426
-
427
349
  // Yield to event loop every 10 chunks to prevent CPU blocking
428
350
  processedCount++;
429
351
  if (processedCount % 10 === 0) {
@@ -431,27 +353,23 @@ class ImapStream extends Transform {
431
353
  }
432
354
  }
433
355
  }
434
-
435
356
  /**
436
357
  * Transform stream implementation. Receives raw data chunks from the writable side,
437
358
  * converts strings to Buffers, tracks total bytes read, optionally logs raw data,
438
359
  * and queues the chunk for asynchronous processing.
439
360
  *
440
- * @param {Buffer|string} chunk - The incoming data chunk.
441
- * @param {string} encoding - The encoding if chunk is a string.
442
- * @param {Function} next - Callback to signal that this chunk has been consumed.
361
+ * @param chunk - The incoming data chunk.
362
+ * @param encoding - The encoding if chunk is a string.
363
+ * @param next - Callback to signal that this chunk has been consumed.
443
364
  */
444
365
  _transform(chunk, encoding, next) {
445
366
  if (typeof chunk === 'string') {
446
367
  chunk = Buffer.from(chunk, encoding);
447
368
  }
448
-
449
369
  if (!chunk || !chunk.length) {
450
370
  return next();
451
371
  }
452
-
453
372
  this.readBytesCounter += chunk.length;
454
-
455
373
  if (this.options.logRaw) {
456
374
  this.log.trace({
457
375
  src: 's',
@@ -462,18 +380,15 @@ class ImapStream extends Transform {
462
380
  cid: this.cid
463
381
  });
464
382
  }
465
-
466
383
  // A terminal parser failure must not accept any more protocol input, even if the
467
384
  // transport delivers a chunk that was already in flight.
468
385
  if (this.destroyed) {
469
386
  return next();
470
387
  }
471
-
472
388
  // Queue the chunk for async processing. The 'next' callback serves as
473
389
  // backpressure: it is called only after this chunk is fully processed,
474
390
  // which signals the writable side that more data can be accepted.
475
391
  this.inputQueue.push({ chunk, next });
476
-
477
392
  if (!this.processingInput) {
478
393
  this.processingInput = true;
479
394
  this.processInput()
@@ -481,22 +396,20 @@ class ImapStream extends Transform {
481
396
  .finally(() => (this.processingInput = false));
482
397
  }
483
398
  }
484
-
485
399
  /**
486
400
  * Flush implementation called when the writable side ends. Signals completion immediately.
487
401
  *
488
- * @param {Function} next - Callback to signal flush completion.
402
+ * @param next - Callback to signal flush completion.
489
403
  */
490
404
  _flush(next) {
491
405
  next();
492
406
  }
493
-
494
407
  /**
495
408
  * Destroy implementation for cleanup. Clears all internal buffers, drains the input queue
496
409
  * by invoking pending callbacks, and forwards the error (if any) to the callback.
497
410
  *
498
- * @param {Error|null} err - The error that caused destruction, or null.
499
- * @param {Function} callback - Callback to signal destruction completion.
411
+ * @param err - The error that caused destruction, or null.
412
+ * @param callback - Callback to signal destruction completion.
500
413
  */
501
414
  _destroy(err, callback) {
502
415
  // Destruction is the single release point for parser-owned callbacks, so a terminal
@@ -507,14 +420,12 @@ class ImapStream extends Transform {
507
420
  this.literalBuffer = [];
508
421
  this.literals = [];
509
422
  this.responseBytes = 0;
510
-
511
423
  // Settle an in-flight push() wait so processInput() can unwind
512
424
  if (typeof this.pendingPush === 'function') {
513
425
  const resolve = this.pendingPush;
514
426
  this.pendingPush = null;
515
427
  resolve();
516
428
  }
517
-
518
429
  // Release the chunk currently being processed, then everything still queued.
519
430
  // releaseInput() is idempotent, so the processing loop releasing the same chunk
520
431
  // afterwards is a no-op.
@@ -523,9 +434,6 @@ class ImapStream extends Transform {
523
434
  while (this.inputQueue.length) {
524
435
  this.releaseInput(this.inputQueue.shift());
525
436
  }
526
-
527
437
  callback(err);
528
438
  }
529
439
  }
530
-
531
- module.exports.ImapStream = ImapStream;
@@ -0,0 +1,25 @@
1
+ import type { ImapFlowError } from '../errors.js';
2
+ export declare const MAX_LITERAL_SIZE: number;
3
+ export declare const MAX_LINE_SIZE: number;
4
+ export declare const MAX_RESPONSE_SIZE: number;
5
+ /**
6
+ * Normalizes a configured size limit. A non-negative integer is honored as-is (including 0, which
7
+ * means "reject anything non-empty"), and `Infinity` disables the limit; anything else falls back
8
+ * to the default, so an explicit 0 is not silently swallowed the way `value || DEFAULT` would
9
+ * swallow it.
10
+ *
11
+ * @param value - The configured value.
12
+ * @param defaultValue - Fallback when the value is not a usable limit.
13
+ * @returns The normalized limit.
14
+ */
15
+ export declare const normalizeLimit: (value: unknown, defaultValue: number) => number;
16
+ /**
17
+ * Builds the `LiteralTooLarge` error. One shape for every place a literal is refused, so callers
18
+ * can rely on `code`, `literalSize` and `maxSize` regardless of which parser rejected it.
19
+ *
20
+ * @param literalSize - The declared literal size.
21
+ * @param maxSize - The bound that was exceeded.
22
+ * @param reason - What the bound was, when it is not the configured maximum.
23
+ * @returns The error to emit or throw.
24
+ */
25
+ export declare const createLiteralTooLargeError: (literalSize: number, maxSize: number, reason?: string | null | undefined) => ImapFlowError;
@@ -1,17 +1,12 @@
1
- 'use strict';
2
-
3
1
  // Shared response-size limits for the IMAP parser. Kept in one place so the streaming parser
4
2
  // (ImapStream) and the standalone token parser cannot drift apart, and so the documented
5
- // defaults in imap-flow.d.ts describe both paths.
6
-
3
+ // defaults in the ImapFlowOptions type describe both paths.
7
4
  // Maximum allowed literal size: 1GB (1073741824 bytes)
8
- const MAX_LITERAL_SIZE = 1024 * 1024 * 1024;
9
-
5
+ export const MAX_LITERAL_SIZE = 1024 * 1024 * 1024;
10
6
  // Default maximum length of a single line (a response without a literal). Matches the literal cap:
11
7
  // large literal-free responses (e.g. big SEARCH/LIST results) are legitimate, so this bound exists
12
8
  // only to stop a server that never sends a line terminator, not to constrain normal traffic.
13
- const MAX_LINE_SIZE = MAX_LITERAL_SIZE;
14
-
9
+ export const MAX_LINE_SIZE = MAX_LITERAL_SIZE;
15
10
  // Default maximum total size of a single assembled response: every line segment and literal of
16
11
  // one response combined. The per-line and per-literal caps alone cannot stop a server that
17
12
  // spreads attacker-controlled bytes across an unbounded number of tokens of a single response
@@ -21,35 +16,31 @@ const MAX_LINE_SIZE = MAX_LITERAL_SIZE;
21
16
  // and the rest of the response framing, so a cap equal to MAX_LITERAL_SIZE would make a literal
22
17
  // of exactly the maximum permitted size impossible to receive. Configuring both limits calls for
23
18
  // the same headroom - set maxResponseSize above maxLiteralSize, not equal to it.
24
- const MAX_RESPONSE_SIZE = 2 * MAX_LITERAL_SIZE;
25
-
19
+ export const MAX_RESPONSE_SIZE = 2 * MAX_LITERAL_SIZE;
26
20
  /**
27
21
  * Normalizes a configured size limit. A non-negative integer is honored as-is (including 0, which
28
22
  * means "reject anything non-empty"), and `Infinity` disables the limit; anything else falls back
29
23
  * to the default, so an explicit 0 is not silently swallowed the way `value || DEFAULT` would
30
24
  * swallow it.
31
25
  *
32
- * @param {*} value - The configured value.
33
- * @param {number} defaultValue - Fallback when the value is not a usable limit.
34
- * @returns {number} The normalized limit.
26
+ * @param value - The configured value.
27
+ * @param defaultValue - Fallback when the value is not a usable limit.
28
+ * @returns The normalized limit.
35
29
  */
36
- const normalizeLimit = (value, defaultValue) => ((Number.isInteger(value) || value === Infinity) && value >= 0 ? value : defaultValue);
37
-
30
+ export const normalizeLimit = (value, defaultValue) => (Number.isInteger(value) || value === Infinity) && value >= 0 ? value : defaultValue;
38
31
  /**
39
32
  * Builds the `LiteralTooLarge` error. One shape for every place a literal is refused, so callers
40
33
  * can rely on `code`, `literalSize` and `maxSize` regardless of which parser rejected it.
41
34
  *
42
- * @param {number} literalSize - The declared literal size.
43
- * @param {number} maxSize - The bound that was exceeded.
44
- * @param {string} [reason] - What the bound was, when it is not the configured maximum.
45
- * @returns {Error} The error to emit or throw.
35
+ * @param literalSize - The declared literal size.
36
+ * @param maxSize - The bound that was exceeded.
37
+ * @param reason - What the bound was, when it is not the configured maximum.
38
+ * @returns The error to emit or throw.
46
39
  */
47
- const createLiteralTooLargeError = (literalSize, maxSize, reason) => {
40
+ export const createLiteralTooLargeError = (literalSize, maxSize, reason) => {
48
41
  const err = new Error(`Literal size ${literalSize} exceeds ${reason || `maximum allowed size of ${maxSize} bytes`}`);
49
42
  err.code = 'LiteralTooLarge';
50
43
  err.literalSize = literalSize;
51
44
  err.maxSize = maxSize;
52
45
  return err;
53
46
  };
54
-
55
- module.exports = { MAX_LITERAL_SIZE, MAX_LINE_SIZE, MAX_RESPONSE_SIZE, normalizeLimit, createLiteralTooLargeError };
@@ -0,0 +1,68 @@
1
+ import type { ImapAttributeList, ParserOptions } from './types.js';
2
+ /**
3
+ * Parses a single IMAP response line into its structural components: tag, command,
4
+ * and attributes. Handles status responses (OK, NO, BAD, PREAUTH, BYE) with their
5
+ * human-readable text and response codes, as well as continuation responses ("+").
6
+ */
7
+ export declare class ParserInstance {
8
+ input: string;
9
+ options: ParserOptions;
10
+ remainder: string;
11
+ pos: number;
12
+ tag?: string | undefined;
13
+ command?: string | undefined;
14
+ humanReadable?: string | undefined;
15
+ /**
16
+ * Creates a new ParserInstance for parsing an IMAP response line.
17
+ *
18
+ * @param input - The raw IMAP response line to parse.
19
+ * @param options - Parser options passed through to the TokenParser for attribute parsing.
20
+ * @param options.literalPlus - Whether the LITERAL+ extension is in use.
21
+ * @param options.literals - Pre-parsed literal values from the stream.
22
+ */
23
+ constructor(input?: Buffer | string | null | undefined, options?: ParserOptions | undefined);
24
+ /**
25
+ * Extracts and returns the IMAP tag from the beginning of the response.
26
+ * The tag is typically "*" for untagged responses, "+" for continuation requests,
27
+ * or a client-assigned command tag like "A1".
28
+ *
29
+ * @returns The parsed tag string.
30
+ * @throws {Error} If the tag contains invalid characters.
31
+ */
32
+ getTag(): Promise<string>;
33
+ /**
34
+ * Extracts and returns the IMAP command or response name from the input.
35
+ * For continuation responses (tag "+"), returns an empty string and stores
36
+ * the remainder as human-readable text. For status responses (OK, NO, BAD,
37
+ * PREAUTH, BYE), separates the optional response code from the human-readable text.
38
+ *
39
+ * @returns The parsed command string.
40
+ * @throws {Error} If the command contains invalid characters or input ends unexpectedly.
41
+ */
42
+ getCommand(): Promise<string>;
43
+ /**
44
+ * Extracts the next whitespace-delimited element from the input and validates it
45
+ * against the given syntax character set. Advances the parser position past the element.
46
+ *
47
+ * @param syntax - A string of allowed characters for the element (as returned by imap-formal-syntax methods).
48
+ * @returns The extracted element string.
49
+ * @throws {Error} If the element contains characters not in the syntax set, or if input ends unexpectedly.
50
+ */
51
+ getElement(syntax: string): Promise<string>;
52
+ /**
53
+ * Consumes a single space character from the current position in the input.
54
+ * Advances the parser position by one.
55
+ *
56
+ * @throws {Error} If the current character is not a space, or if input has ended unexpectedly.
57
+ */
58
+ getSpace(): Promise<void>;
59
+ /**
60
+ * Parses the remaining input as IMAP attributes using the TokenParser.
61
+ * This handles complex structures including nested lists, literals, strings,
62
+ * atoms, sections, sequences, and partial ranges.
63
+ *
64
+ * @returns A promise that resolves to an array of parsed attribute objects.
65
+ * @throws {Error} If the input contains unexpected whitespace, invalid characters, or ends unexpectedly.
66
+ */
67
+ getAttributes(): Promise<ImapAttributeList>;
68
+ }