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,30 +1,27 @@
1
- 'use strict';
2
-
3
1
  /**
4
2
  * Requests DEFLATE compression from the server.
5
3
  *
6
- * @param {Object} connection - IMAP connection instance
7
- * @returns {Promise<boolean>} True if compression was enabled, false otherwise
4
+ * @param connection - IMAP connection instance
5
+ * @returns True if compression was enabled, false otherwise
8
6
  */
9
7
  // COMPRESS=DEFLATE (RFC 4978): enables zlib compression on the IMAP connection
10
8
  // to reduce bandwidth. Once enabled, all subsequent data in both directions is compressed.
11
- module.exports = async connection => {
9
+ export default async function compress(connection) {
12
10
  // Skip if the server doesn't support COMPRESS=DEFLATE, or if compression
13
11
  // is already active (connection._inflate exists) to avoid double-compression.
14
12
  if (!connection.capabilities.has('COMPRESS=DEFLATE') || connection._inflate) {
15
13
  // nothing to do here
16
14
  return false;
17
15
  }
18
-
19
16
  let response;
20
17
  try {
21
18
  response = await connection.exec('COMPRESS', [{ type: 'ATOM', value: 'DEFLATE' }]);
22
- } catch (err) {
19
+ }
20
+ catch (err) {
23
21
  // The server declined (NO/BAD): nothing switched, staying uncompressed is safe.
24
22
  connection.log.warn({ err, cid: connection.id });
25
23
  return false;
26
24
  }
27
-
28
25
  // Everything after the tagged OK is already deflate-framed (RFC 4978 section 4) -
29
26
  // the server switches at the OK, so declining the upgrade at this point is not a
30
27
  // protocol option. The socket stays piped into the plaintext parser until the
@@ -42,14 +39,13 @@ module.exports = async connection => {
42
39
  // Schedule the close before releasing parser backpressure, so the buffered
43
40
  // deflate-framed bytes cannot settle anything before teardown begins. This is
44
41
  // why the decision lives here rather than at the connection layer the way the
45
- // STARTTLS guard does (starttls.js records a flag, upgradeToSTARTTLS decides):
42
+ // STARTTLS guard does (starttls.ts records a flag, upgradeToSTARTTLS decides):
46
43
  // only the command module holds the response before its backpressure release,
47
44
  // so only it can order teardown ahead of that release.
48
45
  connection.closeAfter();
49
46
  response.next();
50
47
  throw error;
51
48
  }
52
-
53
49
  response.next();
54
50
  return true;
55
- };
51
+ }
@@ -0,0 +1,13 @@
1
+ import type { ImapFlow } from '../imap-flow.js';
2
+ import type { CopyResponseObject, MessageRangeOptions } from '../types.js';
3
+ /**
4
+ * Copies messages from the current mailbox to another mailbox.
5
+ *
6
+ * @param connection - IMAP connection instance
7
+ * @param range - Message sequence number or UID range
8
+ * @param destination - Destination mailbox path
9
+ * @param options - Copy options
10
+ * @param options.uid - If true, use UID COPY instead of COPY
11
+ * @returns Copy result with UID mapping if available, false on failure, or undefined if preconditions not met
12
+ */
13
+ export default function copy(connection: ImapFlow, range: string, destination: string | string[], options?: MessageRangeOptions | undefined): Promise<CopyResponseObject | false | undefined>;
@@ -1,47 +1,39 @@
1
- 'use strict';
2
-
3
- const { normalizePath, encodePath, enhanceCommandError } = require('../tools.js');
4
- const { parseCopyUid } = require('./copyuid-parser.js');
5
-
1
+ import { normalizePath, encodePath, enhanceCommandError } from '../tools.js';
2
+ import { parseCopyUid } from './copyuid-parser.js';
6
3
  /**
7
4
  * Copies messages from the current mailbox to another mailbox.
8
5
  *
9
- * @param {Object} connection - IMAP connection instance
10
- * @param {string} range - Message sequence number or UID range
11
- * @param {string} destination - Destination mailbox path
12
- * @param {Object} [options] - Copy options
13
- * @param {boolean} [options.uid] - If true, use UID COPY instead of COPY
14
- * @returns {Promise<{path: string, destination: string, uidValidity?: BigInt, uidMap?: Map}|boolean|undefined>} Copy result with UID mapping if available, false on failure, or undefined if preconditions not met
6
+ * @param connection - IMAP connection instance
7
+ * @param range - Message sequence number or UID range
8
+ * @param destination - Destination mailbox path
9
+ * @param options - Copy options
10
+ * @param options.uid - If true, use UID COPY instead of COPY
11
+ * @returns Copy result with UID mapping if available, false on failure, or undefined if preconditions not met
15
12
  */
16
- module.exports = async (connection, range, destination, options) => {
13
+ export default async function copy(connection, range, destination, options) {
17
14
  if (connection.state !== connection.states.SELECTED || !range || !destination) {
18
15
  // nothing to do here
19
16
  return;
20
17
  }
21
-
22
18
  options = options || {};
23
19
  destination = normalizePath(connection, destination);
24
-
25
20
  let attributes = [
26
21
  { type: 'SEQUENCE', value: range },
27
22
  { type: 'ATOM', value: encodePath(connection, destination) }
28
23
  ];
29
-
30
24
  let response;
31
25
  try {
32
26
  response = await connection.exec(options.uid ? 'UID COPY' : 'COPY', attributes);
33
27
  response.next();
34
-
35
28
  let map = { path: connection.mailbox.path, destination };
36
-
37
29
  // UIDPLUS (RFC 4315): the server may include a COPYUID response code in the
38
30
  // tagged OK response, providing a mapping from source UIDs to destination UIDs.
39
31
  parseCopyUid(response.response, map);
40
-
41
32
  return map;
42
- } catch (err) {
33
+ }
34
+ catch (err) {
43
35
  await enhanceCommandError(err);
44
36
  connection.log.warn({ err, cid: connection.id });
45
37
  return false;
46
38
  }
47
- };
39
+ }
@@ -0,0 +1,11 @@
1
+ import type { ImapResponse } from '../handler/types.js';
2
+ import type { CopyResponseObject } from '../types.js';
3
+ /**
4
+ * Parses COPYUID response code from an IMAP response (RFC 4315).
5
+ * Used by both COPY and MOVE commands to extract the UID mapping
6
+ * from source mailbox to destination mailbox.
7
+ *
8
+ * @param response - IMAP response object with attributes
9
+ * @param map - Result map to populate with uidValidity and uidMap
10
+ */
11
+ export declare function parseCopyUid(response: ImapResponse, map: CopyResponseObject): void;
@@ -1,35 +1,29 @@
1
- 'use strict';
2
-
3
- const { expandRange, parseBigIntValue } = require('../tools.js');
4
-
1
+ import { expandRange, parseBigIntValue } from '../tools.js';
5
2
  /**
6
3
  * Parses COPYUID response code from an IMAP response (RFC 4315).
7
4
  * Used by both COPY and MOVE commands to extract the UID mapping
8
5
  * from source mailbox to destination mailbox.
9
6
  *
10
- * @param {Object} response - IMAP response object with attributes
11
- * @param {Object} map - Result map to populate with uidValidity and uidMap
7
+ * @param response - IMAP response object with attributes
8
+ * @param map - Result map to populate with uidValidity and uidMap
12
9
  */
13
- function parseCopyUid(response, map) {
10
+ export function parseCopyUid(response, map) {
14
11
  let section = response.attributes && response.attributes[0] && response.attributes[0].section;
15
12
  let responseCode = section && section.length && section[0] && typeof section[0].value === 'string' ? section[0].value : '';
16
-
17
13
  if (responseCode !== 'COPYUID') {
18
14
  return;
19
15
  }
20
-
16
+ // A COPYUID code always comes with its section, see responseCode above
17
+ let codeSection = section;
21
18
  // Only a bounded pure digit string is accepted: isNaN() also passes values like "1e5" or
22
19
  // "Infinity", which BigInt() then rejects with a throw that loses the uidMap.
23
- let uidValidity = parseBigIntValue(section[1] && section[1].value);
20
+ let uidValidity = parseBigIntValue(codeSection[1] && codeSection[1].value);
24
21
  if (uidValidity !== false) {
25
22
  map.uidValidity = uidValidity;
26
23
  }
27
-
28
- let sourceUids = section[2] && typeof section[2].value === 'string' ? expandRange(section[2].value) : false;
29
- let destinationUids = section[3] && typeof section[3].value === 'string' ? expandRange(section[3].value) : false;
24
+ const sourceUids = codeSection[2] && typeof codeSection[2].value === 'string' ? expandRange(codeSection[2].value) : false;
25
+ const destinationUids = codeSection[3] && typeof codeSection[3].value === 'string' ? expandRange(codeSection[3].value) : false;
30
26
  if (sourceUids && destinationUids && sourceUids.length === destinationUids.length) {
31
27
  map.uidMap = new Map(sourceUids.map((uid, i) => [uid, destinationUids[i]]));
32
28
  }
33
29
  }
34
-
35
- module.exports = { parseCopyUid };
@@ -0,0 +1,11 @@
1
+ import type { ImapFlow } from '../imap-flow.js';
2
+ import type { MailboxCreateResponse } from '../types.js';
3
+ /**
4
+ * Creates a new mailbox and subscribes to it.
5
+ *
6
+ * @param connection - IMAP connection instance
7
+ * @param path - Mailbox path to create
8
+ * @returns Object with path and creation status, or undefined if preconditions not met
9
+ * @throws If the CREATE command fails (except when mailbox already exists)
10
+ */
11
+ export default function create(connection: ImapFlow, path: string | string[]): Promise<MailboxCreateResponse | undefined>;
@@ -1,40 +1,32 @@
1
- 'use strict';
2
-
3
- const { encodePath, normalizePath, getStatusCode, enhanceCommandError } = require('../tools.js');
4
-
1
+ import { encodePath, normalizePath, getStatusCode, enhanceCommandError } from '../tools.js';
5
2
  /**
6
3
  * Creates a new mailbox and subscribes to it.
7
4
  *
8
- * @param {Object} connection - IMAP connection instance
9
- * @param {string} path - Mailbox path to create
10
- * @returns {Promise<{path: string, created: boolean, mailboxId?: string}|undefined>} Object with path and creation status, or undefined if preconditions not met
11
- * @throws {Error} If the CREATE command fails (except when mailbox already exists)
5
+ * @param connection - IMAP connection instance
6
+ * @param path - Mailbox path to create
7
+ * @returns Object with path and creation status, or undefined if preconditions not met
8
+ * @throws If the CREATE command fails (except when mailbox already exists)
12
9
  */
13
- module.exports = async (connection, path) => {
10
+ export default async function create(connection, path) {
14
11
  if (![connection.states.AUTHENTICATED, connection.states.SELECTED].includes(connection.state)) {
15
12
  // nothing to do here
16
13
  return;
17
14
  }
18
-
19
15
  path = normalizePath(connection, path);
20
-
21
16
  let response;
22
17
  try {
23
18
  let map = {
24
19
  path
25
20
  };
26
21
  response = await connection.exec('CREATE', [{ type: 'ATOM', value: encodePath(connection, path) }]);
27
-
28
22
  // Parse the response code section (e.g., [MAILBOXID (<id>)]) from the tagged OK response.
29
23
  // IMAP response code attributes are structured as alternating key-value pairs.
30
- let section =
31
- response.response.attributes &&
24
+ let section = response.response.attributes &&
32
25
  response.response.attributes[0] &&
33
26
  response.response.attributes[0].section &&
34
27
  response.response.attributes[0].section.length
35
- ? response.response.attributes[0].section
36
- : false;
37
-
28
+ ? response.response.attributes[0].section
29
+ : false;
38
30
  if (section) {
39
31
  let key;
40
32
  section.forEach((attribute, i) => {
@@ -43,11 +35,9 @@ module.exports = async (connection, path) => {
43
35
  key = attribute && typeof attribute.value === 'string' ? attribute.value : false;
44
36
  return;
45
37
  }
46
-
47
38
  if (!key) {
48
39
  return;
49
40
  }
50
-
51
41
  let value;
52
42
  switch (key.toLowerCase()) {
53
43
  case 'mailboxid':
@@ -55,25 +45,22 @@ module.exports = async (connection, path) => {
55
45
  value = Array.isArray(attribute) && attribute[0] && typeof attribute[0].value === 'string' ? attribute[0].value : false;
56
46
  break;
57
47
  }
58
-
59
48
  if (key && value) {
60
49
  map[key] = value;
61
50
  }
62
51
  });
63
52
  }
64
-
65
53
  map.created = true;
66
54
  response.next();
67
-
68
55
  // Auto-subscribe after creation so the new mailbox appears in LSUB listings
69
56
  // and is visible to clients that only show subscribed folders.
70
57
  await connection.run('SUBSCRIBE', path);
71
-
72
58
  return map;
73
- } catch (err) {
59
+ }
60
+ catch (err) {
74
61
  let errorCode = getStatusCode(err.response);
75
62
  // ALREADYEXISTS (RFC 5530) means the mailbox already exists on the server.
76
- // This is not a true error -- we return created:false to indicate nothing was created.
63
+ // This is not a true error, we return created:false to indicate nothing was created.
77
64
  if (errorCode === 'ALREADYEXISTS') {
78
65
  // no need to do anything, mailbox already exists
79
66
  return {
@@ -81,9 +68,8 @@ module.exports = async (connection, path) => {
81
68
  created: false
82
69
  };
83
70
  }
84
-
85
71
  await enhanceCommandError(err);
86
72
  connection.log.warn({ err, cid: connection.id });
87
73
  throw err;
88
74
  }
89
- };
75
+ }
@@ -0,0 +1,11 @@
1
+ import type { ImapFlow } from '../imap-flow.js';
2
+ import type { MailboxDeleteResponse } from '../types.js';
3
+ /**
4
+ * Deletes an existing mailbox.
5
+ *
6
+ * @param connection - IMAP connection instance
7
+ * @param path - Mailbox path to delete
8
+ * @returns Object with the deleted path, or undefined if preconditions not met
9
+ * @throws If the DELETE command fails
10
+ */
11
+ export default function deleteMailbox(connection: ImapFlow, path: string | string[]): Promise<MailboxDeleteResponse | undefined>;
@@ -1,29 +1,23 @@
1
- 'use strict';
2
-
3
- const { encodePath, normalizePath, enhanceCommandError } = require('../tools.js');
4
-
1
+ import { encodePath, normalizePath, enhanceCommandError } from '../tools.js';
5
2
  /**
6
3
  * Deletes an existing mailbox.
7
4
  *
8
- * @param {Object} connection - IMAP connection instance
9
- * @param {string} path - Mailbox path to delete
10
- * @returns {Promise<{path: string}|undefined>} Object with the deleted path, or undefined if preconditions not met
11
- * @throws {Error} If the DELETE command fails
5
+ * @param connection - IMAP connection instance
6
+ * @param path - Mailbox path to delete
7
+ * @returns Object with the deleted path, or undefined if preconditions not met
8
+ * @throws If the DELETE command fails
12
9
  */
13
- module.exports = async (connection, path) => {
10
+ export default async function deleteMailbox(connection, path) {
14
11
  if (![connection.states.AUTHENTICATED, connection.states.SELECTED].includes(connection.state)) {
15
12
  // nothing to do here
16
13
  return;
17
14
  }
18
-
19
15
  path = normalizePath(connection, path);
20
-
21
16
  // If the mailbox to delete is currently selected, we must close/deselect it first.
22
17
  // IMAP servers reject DELETE on the currently selected mailbox (RFC 3501 6.3.4).
23
18
  if (connection.state === connection.states.SELECTED && connection.mailbox.path === path) {
24
19
  await connection.run('CLOSE');
25
20
  }
26
-
27
21
  let response;
28
22
  try {
29
23
  let map = {
@@ -32,9 +26,10 @@ module.exports = async (connection, path) => {
32
26
  response = await connection.exec('DELETE', [{ type: 'ATOM', value: encodePath(connection, path) }]);
33
27
  response.next();
34
28
  return map;
35
- } catch (err) {
29
+ }
30
+ catch (err) {
36
31
  await enhanceCommandError(err);
37
32
  connection.log.warn({ err, cid: connection.id });
38
33
  throw err;
39
34
  }
40
- };
35
+ }
@@ -0,0 +1,9 @@
1
+ import type { ImapFlow } from '../imap-flow.js';
2
+ /**
3
+ * Enables IMAP extensions on the server.
4
+ *
5
+ * @param connection - IMAP connection instance
6
+ * @param extensionList - List of extension names to enable
7
+ * @returns Set of enabled extensions, false on failure, or undefined if not applicable
8
+ */
9
+ export default function enable(connection: ImapFlow, extensionList: string[]): Promise<Set<string> | false | undefined>;
@@ -1,21 +1,17 @@
1
- 'use strict';
2
-
3
- const { hasCapability } = require('../tools.js');
4
-
1
+ import { hasCapability } from '../tools.js';
5
2
  /**
6
3
  * Enables IMAP extensions on the server.
7
4
  *
8
- * @param {Object} connection - IMAP connection instance
9
- * @param {string[]} extensionList - List of extension names to enable
10
- * @returns {Promise<Set|boolean|undefined>} Set of enabled extensions, false on failure, or undefined if not applicable
5
+ * @param connection - IMAP connection instance
6
+ * @param extensionList - List of extension names to enable
7
+ * @returns Set of enabled extensions, false on failure, or undefined if not applicable
11
8
  */
12
- module.exports = async (connection, extensionList) => {
9
+ export default async function enable(connection, extensionList) {
13
10
  // ENABLE is part of base IMAP4rev2, so rev2-only servers may omit the token
14
11
  if (!hasCapability(connection, 'ENABLE') || connection.state !== connection.states.AUTHENTICATED) {
15
12
  // nothing to do here
16
13
  return;
17
14
  }
18
-
19
15
  // Pre-filter: only request extensions the server actually advertised in its
20
16
  // CAPABILITY response. Requesting unsupported extensions would cause an error.
21
17
  // Compared case-insensitively - the capability map keeps canonical casing for
@@ -25,39 +21,36 @@ module.exports = async (connection, extensionList) => {
25
21
  if (!extensionList.length) {
26
22
  return;
27
23
  }
28
-
29
24
  let response;
30
25
  try {
31
26
  let enabled = new Set();
32
- response = await connection.exec(
33
- 'ENABLE',
34
- extensionList.map(extension => ({ type: 'ATOM', value: extension.toUpperCase() })),
35
- {
36
- untagged: {
37
- // The untagged ENABLED response is a flat list of extension names
38
- // (e.g., "* ENABLED CONDSTORE UTF8=ACCEPT"), NOT key-value pairs.
39
- // Each attribute is a single extension identifier.
40
- ENABLED: async untagged => {
41
- if (!untagged.attributes || !untagged.attributes.length) {
42
- return;
43
- }
44
- untagged.attributes.forEach(attr => {
45
- if (attr.value && typeof attr.value === 'string') {
46
- enabled.add(attr.value.toUpperCase().trim());
47
- }
48
- });
27
+ response = await connection.exec('ENABLE', extensionList.map((extension) => ({ type: 'ATOM', value: extension.toUpperCase() })), {
28
+ untagged: {
29
+ // The untagged ENABLED response is a flat list of extension names
30
+ // (e.g., "* ENABLED CONDSTORE UTF8=ACCEPT"), NOT key-value pairs.
31
+ // Each attribute is a single extension identifier.
32
+ ENABLED: async (untagged) => {
33
+ if (!untagged.attributes || !untagged.attributes.length) {
34
+ return;
49
35
  }
36
+ untagged.attributes.forEach(attr => {
37
+ let value = attr.value;
38
+ if (value && typeof value === 'string') {
39
+ enabled.add(value.toUpperCase().trim());
40
+ }
41
+ });
50
42
  }
51
43
  }
52
- );
44
+ });
53
45
  // Merge instead of replace - the untagged ENABLED response only lists
54
46
  // extensions enabled by this command (RFC 5161), so a replace would drop
55
47
  // grants from an earlier ENABLE call
56
48
  connection.enabled = new Set([...connection.enabled, ...enabled]);
57
49
  response.next();
58
50
  return connection.enabled;
59
- } catch (err) {
51
+ }
52
+ catch (err) {
60
53
  connection.log.warn({ err, cid: connection.id });
61
54
  return false;
62
55
  }
63
- };
56
+ }
@@ -0,0 +1,17 @@
1
+ import type { ImapAttributeList } from '../handler/types.js';
2
+ import type { ESearchResult } from '../types.js';
3
+ /**
4
+ * Parses the key-value attributes from an ESEARCH untagged response.
5
+ *
6
+ * Receives the attribute list AFTER stripping the leading (TAG "X") list
7
+ * and the UID atom, i.e. only the result keyword/value pairs remain.
8
+ *
9
+ * ALL and PARTIAL.messages are kept as compact sequence-set strings.
10
+ * Use expandRange() from tools.ts if you need to expand them.
11
+ * MODSEQ (RFC 7162, sent when the search used a MODSEQ criterion) is
12
+ * returned as a BigInt.
13
+ *
14
+ * @param attrs - Attribute array from the IMAP parser
15
+ * @returns ESearchResult object
16
+ */
17
+ export declare function parseEsearchResponse(attrs: ImapAttributeList): ESearchResult;
@@ -0,0 +1,88 @@
1
+ import { parseBigIntValue, parseUintValue, MAX_UINT32_DIGITS } from '../tools.js';
2
+ /**
3
+ * Parses the key-value attributes from an ESEARCH untagged response.
4
+ *
5
+ * Receives the attribute list AFTER stripping the leading (TAG "X") list
6
+ * and the UID atom, i.e. only the result keyword/value pairs remain.
7
+ *
8
+ * ALL and PARTIAL.messages are kept as compact sequence-set strings.
9
+ * Use expandRange() from tools.ts if you need to expand them.
10
+ * MODSEQ (RFC 7162, sent when the search used a MODSEQ criterion) is
11
+ * returned as a BigInt.
12
+ *
13
+ * @param attrs - Attribute array from the IMAP parser
14
+ * @returns ESearchResult object
15
+ */
16
+ export function parseEsearchResponse(attrs) {
17
+ const result = {};
18
+ let i = 0;
19
+ while (i < attrs.length) {
20
+ const token = attrs[i];
21
+ if (!token || token.type !== 'ATOM') {
22
+ i++;
23
+ continue;
24
+ }
25
+ const key = token.value.toUpperCase();
26
+ if (i + 1 >= attrs.length) {
27
+ i++;
28
+ continue;
29
+ }
30
+ switch (key) {
31
+ // COUNT is a plain message count; MIN and MAX are sequence numbers or UIDs. All
32
+ // three are bounded decimal runs - isNaN() would also admit '1e400' (Infinity)
33
+ case 'COUNT': {
34
+ const n = parseUintValue(attrs[++i]?.value, MAX_UINT32_DIGITS);
35
+ if (n !== false)
36
+ result.count = n;
37
+ break;
38
+ }
39
+ case 'MIN': {
40
+ const n = parseUintValue(attrs[++i]?.value, MAX_UINT32_DIGITS);
41
+ if (n !== false)
42
+ result.min = n;
43
+ break;
44
+ }
45
+ case 'MAX': {
46
+ const n = parseUintValue(attrs[++i]?.value, MAX_UINT32_DIGITS);
47
+ if (n !== false)
48
+ result.max = n;
49
+ break;
50
+ }
51
+ case 'MODSEQ': {
52
+ // RFC 7162 section 3.1.5: present when the SEARCH used a MODSEQ
53
+ // criterion on a CONDSTORE-enabled session. BigInt because
54
+ // mod-sequence values are unsigned 63-bit
55
+ const modseq = parseBigIntValue(attrs[++i]?.value);
56
+ if (modseq !== false)
57
+ result.modseq = modseq;
58
+ break;
59
+ }
60
+ case 'ALL': {
61
+ const allToken = attrs[++i];
62
+ if (allToken && typeof allToken.value === 'string') {
63
+ result.all = allToken.value;
64
+ }
65
+ break;
66
+ }
67
+ case 'PARTIAL': {
68
+ const listToken = attrs[++i];
69
+ const items = Array.isArray(listToken) ? listToken : null;
70
+ if (!items || items.length < 2)
71
+ break;
72
+ result.partial = {
73
+ range: items[0].value,
74
+ messages: items[1].value
75
+ };
76
+ break;
77
+ }
78
+ default:
79
+ // Skip the value token for unknown keys to keep the stream aligned.
80
+ // The loop's unconditional i++ at the bottom advances past the key;
81
+ // this extra i++ advances past the value token.
82
+ i++;
83
+ break;
84
+ }
85
+ i++;
86
+ }
87
+ return result;
88
+ }
@@ -0,0 +1,12 @@
1
+ import type { ImapFlow } from '../imap-flow.js';
2
+ import type { MessageRangeOptions } from '../types.js';
3
+ /**
4
+ * Deletes specified messages by flagging them as Deleted and expunging.
5
+ *
6
+ * @param connection - IMAP connection instance
7
+ * @param range - Message sequence number or UID range
8
+ * @param options - Expunge options
9
+ * @param options.uid - If true, use UID EXPUNGE when UIDPLUS is available
10
+ * @returns True on success, false on failure, or undefined if preconditions not met
11
+ */
12
+ export default function expunge(connection: ImapFlow, range: string, options?: MessageRangeOptions | undefined): Promise<boolean | undefined>;
@@ -1,60 +1,55 @@
1
- 'use strict';
2
-
3
- const { enhanceCommandError, hasCapability, parseBigIntValue } = require('../tools.js');
4
-
1
+ import { enhanceCommandError, hasCapability, parseBigIntValue } from '../tools.js';
5
2
  /**
6
3
  * Deletes specified messages by flagging them as Deleted and expunging.
7
4
  *
8
- * @param {Object} connection - IMAP connection instance
9
- * @param {string} range - Message sequence number or UID range
10
- * @param {Object} [options] - Expunge options
11
- * @param {boolean} [options.uid] - If true, use UID EXPUNGE when UIDPLUS is available
12
- * @returns {Promise<boolean|undefined>} True on success, false on failure, or undefined if preconditions not met
5
+ * @param connection - IMAP connection instance
6
+ * @param range - Message sequence number or UID range
7
+ * @param options - Expunge options
8
+ * @param options.uid - If true, use UID EXPUNGE when UIDPLUS is available
9
+ * @returns True on success, false on failure, or undefined if preconditions not met
13
10
  */
14
- module.exports = async (connection, range, options) => {
11
+ export default async function expunge(connection, range, options) {
15
12
  if (connection.state !== connection.states.SELECTED || !range) {
16
13
  // nothing to do here
17
14
  return;
18
15
  }
19
-
20
16
  options = options || {};
21
-
22
17
  // Two-step deletion process per IMAP protocol:
23
18
  // Step 1: Mark the target messages with the \Deleted flag.
24
19
  await connection.messageFlagsAdd(range, ['\\Deleted'], options);
25
-
26
20
  // Step 2: Issue EXPUNGE to permanently remove \Deleted messages.
27
21
  // With UIDPLUS (RFC 4315): "UID EXPUNGE <uids>" removes only the specified UIDs,
28
- // leaving other \Deleted messages untouched -- important for concurrent access.
22
+ // leaving other \Deleted messages untouched, important for concurrent access.
29
23
  // Without UIDPLUS: plain "EXPUNGE" removes ALL messages flagged \Deleted in the mailbox.
30
24
  let byUid = options.uid && hasCapability(connection, 'UIDPLUS');
31
25
  let command = byUid ? 'UID EXPUNGE' : 'EXPUNGE';
32
26
  let attributes = byUid ? [{ type: 'SEQUENCE', value: range }] : false;
33
-
34
27
  let response;
35
28
  try {
36
29
  response = await connection.exec(command, attributes);
37
-
38
30
  // CONDSTORE (RFC 7162): the server may return HIGHESTMODSEQ in the response code
39
31
  // (e.g., "A OK [HIGHESTMODSEQ 9122] Expunge completed").
40
32
  // Track this so the client can detect concurrent mailbox changes via mod-sequences.
41
33
  let section = response.response.attributes && response.response.attributes[0] && response.response.attributes[0].section;
42
34
  let responseCode = section && section.length && section[0] && typeof section[0].value === 'string' ? section[0].value : '';
43
35
  if (responseCode.toUpperCase() === 'HIGHESTMODSEQ') {
36
+ // A response code always comes with its section, see responseCode above
37
+ let codeSection = section;
38
+ let mailbox = connection.mailbox;
44
39
  // Bounded digit runs only: isNaN() also passes '1e5', which BigInt() rejects with
45
40
  // a throw that the catch below would swallow, making messageDelete() report false
46
41
  // even though the server expunged the messages.
47
- let highestModseq = parseBigIntValue(section[1] && section[1].value);
48
- if (highestModseq && (!connection.mailbox.highestModseq || highestModseq > connection.mailbox.highestModseq)) {
49
- connection.mailbox.highestModseq = highestModseq;
42
+ let highestModseq = parseBigIntValue(codeSection[1] && codeSection[1].value);
43
+ if (highestModseq && (!mailbox.highestModseq || highestModseq > mailbox.highestModseq)) {
44
+ mailbox.highestModseq = highestModseq;
50
45
  }
51
46
  }
52
-
53
47
  response.next();
54
48
  return true;
55
- } catch (err) {
49
+ }
50
+ catch (err) {
56
51
  await enhanceCommandError(err);
57
52
  connection.log.warn({ err, cid: connection.id });
58
53
  return false;
59
54
  }
60
- };
55
+ }