imapflow 1.7.8 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (296) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/README.md +8 -2
  3. package/dist/cjs/charsets.d.ts +1 -0
  4. package/dist/cjs/charsets.js +294 -0
  5. package/dist/cjs/commands/append.d.ts +22 -0
  6. package/dist/cjs/commands/append.js +151 -0
  7. package/dist/cjs/commands/authenticate.d.ts +24 -0
  8. package/dist/cjs/commands/authenticate.js +223 -0
  9. package/dist/cjs/commands/capability.d.ts +8 -0
  10. package/dist/cjs/commands/capability.js +32 -0
  11. package/dist/cjs/commands/close.d.ts +8 -0
  12. package/dist/cjs/commands/close.js +39 -0
  13. package/dist/cjs/commands/compress.d.ts +8 -0
  14. package/dist/cjs/commands/compress.js +56 -0
  15. package/dist/cjs/commands/copy.d.ts +13 -0
  16. package/dist/cjs/commands/copy.js +44 -0
  17. package/dist/cjs/commands/copyuid-parser.d.ts +11 -0
  18. package/dist/cjs/commands/copyuid-parser.js +32 -0
  19. package/dist/cjs/commands/create.d.ts +11 -0
  20. package/dist/cjs/commands/create.js +80 -0
  21. package/dist/cjs/commands/delete.d.ts +11 -0
  22. package/dist/cjs/commands/delete.js +40 -0
  23. package/dist/cjs/commands/enable.d.ts +9 -0
  24. package/dist/cjs/commands/enable.js +61 -0
  25. package/dist/cjs/commands/esearch-parser.d.ts +17 -0
  26. package/dist/cjs/commands/esearch-parser.js +91 -0
  27. package/dist/cjs/commands/expunge.d.ts +12 -0
  28. package/dist/cjs/commands/expunge.js +60 -0
  29. package/dist/cjs/commands/fetch.d.ts +30 -0
  30. package/dist/cjs/commands/fetch.js +241 -0
  31. package/dist/cjs/commands/id.d.ts +10 -0
  32. package/dist/cjs/commands/id.js +80 -0
  33. package/dist/cjs/commands/idle.d.ts +9 -0
  34. package/dist/cjs/commands/idle.js +347 -0
  35. package/dist/cjs/commands/list.d.ts +16 -0
  36. package/dist/cjs/commands/list.js +520 -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 +3956 -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} +387 -517
  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 +60 -123
  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 +769 -1790
  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,7 +1,4 @@
1
- 'use strict';
2
-
3
- const { parseBigIntValue, parseUintValue, MAX_UINT32_DIGITS } = require('../tools.js');
4
-
1
+ import { parseBigIntValue, parseUintValue, MAX_UINT32_DIGITS } from '../tools.js';
5
2
  // STATUS data items (RFC 3501 section 6.3.10, RFC 7162 for HIGHESTMODSEQ, RFC 9051 for SIZE
6
3
  // and DELETED) mapped to the property name each one is exposed under, together with the
7
4
  // parser that turns the raw response token into a usable value. Shared by the STATUS command
@@ -12,8 +9,7 @@ const { parseBigIntValue, parseUintValue, MAX_UINT32_DIGITS } = require('../tool
12
9
  // mailbox state, where a NaN or a value coerced to Infinity corrupts every later range
13
10
  // computation. A plain isNaN() test is not enough: it passes '1e5', ' 12 ' and 'Infinity',
14
11
  // and BigInt() throws on all three, aborting the walk over the remaining fields.
15
- const uint32 = value => parseUintValue(value, MAX_UINT32_DIGITS);
16
-
12
+ const uint32 = (value) => parseUintValue(value, MAX_UINT32_DIGITS);
17
13
  const STATUS_FIELDS = {
18
14
  MESSAGES: { key: 'messages', parser: uint32 },
19
15
  RECENT: { key: 'recent', parser: uint32 },
@@ -28,41 +24,34 @@ const STATUS_FIELDS = {
28
24
  SIZE: { key: 'size', parser: value => parseUintValue(value) },
29
25
  DELETED: { key: 'deleted', parser: uint32 }
30
26
  };
31
-
32
27
  /**
33
28
  * Walks a STATUS data-item list - alternating item-name and item-value tokens - and reports
34
29
  * every recognized field that parsed successfully. Unknown item names and unusable values are
35
30
  * skipped, so one bad field never costs the rest of the response.
36
31
  *
37
- * @param {Array} list - Parsed attribute list from the untagged STATUS response.
38
- * @param {Function} onField - Called as (key, value) for each usable field.
32
+ * @param list - Parsed attribute list from the untagged STATUS response.
33
+ * @param onField - Called as (key, value) for each usable field.
39
34
  */
40
- const parseStatusList = (list, onField) => {
35
+ export const parseStatusList = (list, onField) => {
41
36
  let name;
42
37
  list.forEach((entry, i) => {
43
38
  if (i % 2 === 0) {
44
39
  name = entry && typeof entry.value === 'string' ? entry.value : false;
45
40
  return;
46
41
  }
47
-
48
42
  if (!name || !entry) {
49
43
  return;
50
44
  }
51
-
52
45
  // The item name is server-controlled, but uppercasing it before the lookup means no
53
46
  // Object.prototype member can be reached: every builtin name has a lowercase letter.
54
47
  const field = STATUS_FIELDS[name.toUpperCase()];
55
48
  if (!field) {
56
49
  return;
57
50
  }
58
-
59
51
  const value = field.parser(entry.value);
60
52
  if (value === false) {
61
53
  return;
62
54
  }
63
-
64
55
  onField(field.key, value);
65
56
  });
66
57
  };
67
-
68
- module.exports = { parseStatusList };
@@ -0,0 +1,12 @@
1
+ import type { ImapFlow } from '../imap-flow.js';
2
+ import type { StatusObject, StatusQuery } from '../types.js';
3
+ /**
4
+ * Requests status information about a mailbox.
5
+ *
6
+ * @param connection - IMAP connection instance
7
+ * @param path - Mailbox path to query
8
+ * @param query - Status data items to request (e.g., {messages: true, uidNext: true, unseen: true})
9
+ * @returns Status information object, or false if preconditions not met or on failure
10
+ * @throws {Error} If the mailbox does not exist
11
+ */
12
+ export default function status(connection: ImapFlow, path: string | string[], query: StatusQuery | undefined): Promise<StatusObject | false>;
@@ -1,15 +1,13 @@
1
- 'use strict';
2
-
3
- const { encodePath, normalizePath, buildStatusQueryAttributes, isRev2Active } = require('../tools.js');
4
- const { parseStatusList } = require('./status-fields.js');
5
-
1
+ import { encodePath, normalizePath, buildStatusQueryAttributes, isRev2Active } from '../tools.js';
2
+ import { parseStatusList } from './status-fields.js';
6
3
  // STATUS fields that also refresh the live mailbox state when the queried mailbox is the
7
4
  // currently selected one. Keyed by the output property name parseStatusList() reports.
8
5
  const MAILBOX_UPDATERS = {
9
6
  messages: (value, connection, path) => {
10
- let prevCount = connection.mailbox.exists;
7
+ let mailbox = connection.mailbox;
8
+ let prevCount = mailbox.exists;
11
9
  if (prevCount !== value) {
12
- connection.mailbox.exists = value;
10
+ mailbox.exists = value;
13
11
  connection.emit('exists', { path, count: value, prevCount });
14
12
  }
15
13
  },
@@ -20,45 +18,37 @@ const MAILBOX_UPDATERS = {
20
18
  connection.mailbox.highestModseq = value;
21
19
  }
22
20
  };
23
-
24
21
  /**
25
22
  * Requests status information about a mailbox.
26
23
  *
27
- * @param {Object} connection - IMAP connection instance
28
- * @param {string} path - Mailbox path to query
29
- * @param {Object} query - Status data items to request (e.g., {messages: true, uidNext: true, unseen: true})
30
- * @returns {Promise<{path: string, messages?: number, recent?: number, uidNext?: number, uidValidity?: BigInt, unseen?: number, highestModseq?: BigInt}|boolean>} Status information object, or false if preconditions not met or on failure
24
+ * @param connection - IMAP connection instance
25
+ * @param path - Mailbox path to query
26
+ * @param query - Status data items to request (e.g., {messages: true, uidNext: true, unseen: true})
27
+ * @returns Status information object, or false if preconditions not met or on failure
31
28
  * @throws {Error} If the mailbox does not exist
32
29
  */
33
- module.exports = async (connection, path, query) => {
30
+ export default async function status(connection, path, query) {
34
31
  if (![connection.states.AUTHENTICATED, connection.states.SELECTED].includes(connection.state) || !path) {
35
32
  // nothing to do here
36
33
  return false;
37
34
  }
38
-
39
35
  path = normalizePath(connection, path);
40
36
  let encodedPath = encodePath(connection, path);
41
-
42
37
  // Use quoted STRING if the encoded path contains '&' (modified UTF-7 marker),
43
38
  // otherwise use unquoted ATOM. Same approach as in SELECT.
44
39
  let attributes = [{ type: encodedPath.indexOf('&') >= 0 ? 'STRING' : 'ATOM', value: encodedPath }];
45
-
46
40
  // Build the list of STATUS data items the caller wants
47
41
  let queryAttributes = buildStatusQueryAttributes(connection, query);
48
-
49
42
  // RECENT does not exist in IMAP4rev2 so it is never requested from a rev2
50
43
  // session; its defined value there is always 0. Synthesizing it keeps the
51
44
  // return shape identical to a rev1 session for the same query.
52
45
  let syntheticRecent = query && query.recent && isRev2Active(connection);
53
-
54
46
  if (!queryAttributes.length) {
55
47
  // A query that only contained items unavailable on this session - the
56
48
  // caller still gets a status object if every such item has a defined value
57
49
  return syntheticRecent ? { path, recent: 0 } : false;
58
50
  }
59
-
60
51
  attributes.push(queryAttributes);
61
-
62
52
  let response;
63
53
  try {
64
54
  let map = { path };
@@ -66,20 +56,19 @@ module.exports = async (connection, path, query) => {
66
56
  untagged: {
67
57
  // STATUS response: * STATUS <mailbox> (<key> <value> <key> <value> ...)
68
58
  // Parsed as alternating key-value pairs (i % 2 pattern).
69
- STATUS: async untagged => {
59
+ STATUS: async (untagged) => {
70
60
  // If querying the currently selected mailbox, also update the
71
61
  // connection's live mailbox state and emit events for changes.
72
62
  let updateCurrent = connection.state === connection.states.SELECTED && path === connection.mailbox.path;
73
-
74
63
  let list = untagged.attributes && Array.isArray(untagged.attributes[1]) ? untagged.attributes[1] : false;
75
64
  if (!list) {
76
65
  return;
77
66
  }
78
67
  parseStatusList(list, (key, value) => {
79
68
  map[key] = value;
80
-
81
- if (updateCurrent && MAILBOX_UPDATERS[key]) {
82
- MAILBOX_UPDATERS[key](value, connection, path);
69
+ let updater = MAILBOX_UPDATERS[key];
70
+ if (updateCurrent && updater) {
71
+ updater(value, connection, path);
83
72
  }
84
73
  });
85
74
  }
@@ -90,9 +79,10 @@ module.exports = async (connection, path, query) => {
90
79
  map.recent = 0;
91
80
  }
92
81
  return map;
93
- } catch (err) {
82
+ }
83
+ catch (err) {
94
84
  // A NO response usually means the mailbox doesn't exist. Verify by
95
- // running LIST -- if no results, throw a clear NotFound error instead
85
+ // running LIST: if no results, throw a clear NotFound error instead
96
86
  // of the generic IMAP error.
97
87
  // Note: this uses run(), so when STATUS was dispatched by fallback polling through
98
88
  // runInternal() the LIST awaits that polling session's own preCheck and cancels it.
@@ -107,8 +97,7 @@ module.exports = async (connection, path, query) => {
107
97
  throw error;
108
98
  }
109
99
  }
110
-
111
100
  connection.log.warn({ err, cid: connection.id });
112
101
  return false;
113
102
  }
114
- };
103
+ }
@@ -0,0 +1,19 @@
1
+ import type { ImapFlow } from '../imap-flow.js';
2
+ import type { StoreOptions } from '../types.js';
3
+ /**
4
+ * Options for the STORE command
5
+ */
6
+ export interface StoreCommandOptions extends StoreOptions {
7
+ /** Operation type: 'set', 'add', or 'remove' */
8
+ operation?: string | undefined;
9
+ }
10
+ /**
11
+ * Updates flags or labels for messages in the selected mailbox.
12
+ *
13
+ * @param connection - IMAP connection instance
14
+ * @param range - Message sequence number or UID range
15
+ * @param flags - Flag(s) to set, add, or remove
16
+ * @param options - Store options
17
+ * @returns True on success, false on failure or if nothing to do
18
+ */
19
+ export default function store(connection: ImapFlow, range: string, flags: string | string[], options: StoreCommandOptions): Promise<boolean>;
@@ -1,43 +1,32 @@
1
- 'use strict';
2
-
3
- const { formatFlag, canUseFlag, enhanceCommandError } = require('../tools.js');
4
-
1
+ import { formatFlag, canUseFlag, enhanceCommandError } from '../tools.js';
5
2
  /**
6
3
  * Updates flags or labels for messages in the selected mailbox.
7
4
  *
8
- * @param {Object} connection - IMAP connection instance
9
- * @param {string} range - Message sequence number or UID range
10
- * @param {string|string[]} flags - Flag(s) to set, add, or remove
11
- * @param {Object} options - Store options
12
- * @param {boolean} [options.uid] - If true, use UID STORE instead of STORE
13
- * @param {boolean} [options.useLabels] - If true, operate on Gmail labels instead of flags
14
- * @param {boolean} [options.silent] - If true, use .SILENT variant to suppress server response
15
- * @param {string} [options.operation] - Operation type: 'set', 'add', or 'remove'
16
- * @param {string} [options.unchangedSince] - Only update messages not changed since this modseq value
17
- * @returns {Promise<boolean>} True on success, false on failure or if nothing to do
5
+ * @param connection - IMAP connection instance
6
+ * @param range - Message sequence number or UID range
7
+ * @param flags - Flag(s) to set, add, or remove
8
+ * @param options - Store options
9
+ * @returns True on success, false on failure or if nothing to do
18
10
  */
19
- module.exports = async (connection, range, flags, options) => {
11
+ export default async function store(connection, range, flags, options) {
20
12
  if (connection.state !== connection.states.SELECTED || !range || (options.useLabels && !connection.capabilities.has('X-GM-EXT-1'))) {
21
13
  // nothing to do here
22
14
  return false;
23
15
  }
24
-
25
16
  /* c8 ignore next */ // options.useLabels is dereferenced in the guard above, so options is always defined here
26
17
  options = options || {};
27
-
28
18
  // Build the IMAP STORE operation name. The format is:
29
19
  // [+|-]FLAGS[.SILENT] or [+|-]X-GM-LABELS
30
20
  // Where: no prefix = replace all, + = add, - = remove
31
21
  // .SILENT suppresses the server from sending back updated flags (saves bandwidth).
32
22
  let operation = 'FLAGS';
33
-
34
23
  if (options.useLabels) {
35
24
  // Gmail labels (X-GM-EXT-1 extension): operates on labels instead of IMAP flags
36
25
  operation = 'X-GM-LABELS';
37
- } else if (options.silent) {
26
+ }
27
+ else if (options.silent) {
38
28
  operation = `${operation}.SILENT`;
39
29
  }
40
-
41
30
  // Prefix determines the operation: none = set (replace), + = add, - = remove
42
31
  switch ((options.operation || '').toLowerCase()) {
43
32
  case 'set':
@@ -50,29 +39,27 @@ module.exports = async (connection, range, flags, options) => {
50
39
  operation = `+${operation}`;
51
40
  break;
52
41
  }
53
-
54
42
  // Validate each flag: format it (normalize backslash prefix for system flags),
55
43
  // then check if the mailbox's permanentFlags allow it. Removal is always allowed
56
44
  // since it doesn't require the flag to be in permanentFlags.
57
45
  flags = (Array.isArray(flags) ? flags : [].concat(flags || []))
58
46
  .map(flag => {
59
- flag = formatFlag(flag);
60
-
61
- if (!canUseFlag(connection.mailbox, flag) && options.operation !== 'remove') {
62
- return false;
63
- }
64
-
65
- return flag;
66
- })
67
- .filter(flag => flag);
68
-
47
+ let formatted = formatFlag(flag);
48
+ if (!canUseFlag(connection.mailbox, formatted) && options.operation !== 'remove') {
49
+ return false;
50
+ }
51
+ return formatted;
52
+ })
53
+ .filter((flag) => !!flag);
69
54
  // Allow empty flags only for 'set' operation (which clears all flags)
70
55
  if (!flags.length && options.operation !== 'set') {
71
56
  return false;
72
57
  }
73
-
74
- let attributes = [{ type: 'SEQUENCE', value: range }, { type: 'ATOM', value: operation }, flags.map(flag => ({ type: 'ATOM', value: flag }))];
75
-
58
+ let attributes = [
59
+ { type: 'SEQUENCE', value: range },
60
+ { type: 'ATOM', value: operation },
61
+ flags.map(flag => ({ type: 'ATOM', value: flag }))
62
+ ];
76
63
  // CONDSTORE (RFC 7162): UNCHANGEDSINCE modifier prevents updating messages whose
77
64
  // mod-sequence is higher than the specified value, avoiding overwriting concurrent changes.
78
65
  if (options.unchangedSince && connection.enabled.has('CONDSTORE') && !connection.mailbox.noModseq) {
@@ -87,15 +74,15 @@ module.exports = async (connection, range, flags, options) => {
87
74
  }
88
75
  ]);
89
76
  }
90
-
91
77
  let response;
92
78
  try {
93
79
  response = await connection.exec(options.uid ? 'UID STORE' : 'STORE', attributes);
94
80
  response.next();
95
81
  return true;
96
- } catch (err) {
82
+ }
83
+ catch (err) {
97
84
  await enhanceCommandError(err);
98
85
  connection.log.warn({ err, cid: connection.id });
99
86
  return false;
100
87
  }
101
- };
88
+ }
@@ -0,0 +1,9 @@
1
+ import type { ImapFlow } from '../imap-flow.js';
2
+ /**
3
+ * Subscribes to a mailbox.
4
+ *
5
+ * @param connection - IMAP connection instance
6
+ * @param path - Mailbox path to subscribe to
7
+ * @returns True on success, false on failure, or undefined if preconditions not met
8
+ */
9
+ export default function subscribe(connection: ImapFlow, path: string | string[]): Promise<boolean | undefined>;
@@ -1,30 +1,26 @@
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
  * Subscribes to a mailbox.
7
4
  *
8
- * @param {Object} connection - IMAP connection instance
9
- * @param {string} path - Mailbox path to subscribe to
10
- * @returns {Promise<boolean|undefined>} True on success, false on failure, or undefined if preconditions not met
5
+ * @param connection - IMAP connection instance
6
+ * @param path - Mailbox path to subscribe to
7
+ * @returns True on success, false on failure, or undefined if preconditions not met
11
8
  */
12
- module.exports = async (connection, path) => {
9
+ export default async function subscribe(connection, path) {
13
10
  if (![connection.states.AUTHENTICATED, connection.states.SELECTED].includes(connection.state)) {
14
11
  // nothing to do here
15
12
  return;
16
13
  }
17
-
18
14
  path = normalizePath(connection, path);
19
-
20
15
  let response;
21
16
  try {
22
17
  response = await connection.exec('SUBSCRIBE', [{ type: 'ATOM', value: encodePath(connection, path) }]);
23
18
  response.next();
24
19
  return true;
25
- } catch (err) {
20
+ }
21
+ catch (err) {
26
22
  await enhanceCommandError(err);
27
23
  connection.log.warn({ err, cid: connection.id });
28
24
  return false;
29
25
  }
30
- };
26
+ }
@@ -0,0 +1,9 @@
1
+ import type { ImapFlow } from '../imap-flow.js';
2
+ /**
3
+ * Unsubscribes from a mailbox.
4
+ *
5
+ * @param connection - IMAP connection instance
6
+ * @param path - Mailbox path to unsubscribe from
7
+ * @returns True on success, false on failure, or undefined if preconditions not met
8
+ */
9
+ export default function unsubscribe(connection: ImapFlow, path: string | string[]): Promise<boolean | undefined>;
@@ -1,30 +1,26 @@
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
  * Unsubscribes from a mailbox.
7
4
  *
8
- * @param {Object} connection - IMAP connection instance
9
- * @param {string} path - Mailbox path to unsubscribe from
10
- * @returns {Promise<boolean|undefined>} True on success, false on failure, or undefined if preconditions not met
5
+ * @param connection - IMAP connection instance
6
+ * @param path - Mailbox path to unsubscribe from
7
+ * @returns True on success, false on failure, or undefined if preconditions not met
11
8
  */
12
- module.exports = async (connection, path) => {
9
+ export default async function unsubscribe(connection, path) {
13
10
  if (![connection.states.AUTHENTICATED, connection.states.SELECTED].includes(connection.state)) {
14
11
  // nothing to do here
15
12
  return;
16
13
  }
17
-
18
14
  path = normalizePath(connection, path);
19
-
20
15
  let response;
21
16
  try {
22
17
  response = await connection.exec('UNSUBSCRIBE', [{ type: 'ATOM', value: encodePath(connection, path) }]);
23
18
  response.next();
24
19
  return true;
25
- } catch (err) {
20
+ }
21
+ catch (err) {
26
22
  await enhanceCommandError(err);
27
23
  connection.log.warn({ err, cid: connection.id });
28
24
  return false;
29
25
  }
30
- };
26
+ }
@@ -0,0 +1,49 @@
1
+ import type { ImapFlowError } from './errors.js';
2
+ export declare const CONNECT_TIMEOUT: number;
3
+ /**
4
+ * One deadline for an entire connection attempt.
5
+ *
6
+ * DNS resolution, proxy negotiation and the transport handshake all draw from the same budget, so
7
+ * a phase that stalls cannot extend the documented `connectionTimeout`. Every expiry - whether it
8
+ * comes from this deadline or is normalized from a dependency - is reported with the same
9
+ * `CONNECT_TIMEOUT` error shape, so callers do not need to know which phase was blocked.
10
+ */
11
+ export declare class ConnectionDeadline {
12
+ timeout: number;
13
+ startedAt: number;
14
+ /**
15
+ * @param timeout Configured connection timeout in milliseconds. Normalized once
16
+ * here; 0 and any other falsy or invalid value fall back to the 90 second default.
17
+ */
18
+ constructor(timeout?: number | string | undefined);
19
+ /**
20
+ * @returns Milliseconds left in the budget, never negative.
21
+ */
22
+ remaining(): number;
23
+ /**
24
+ * @returns The shared `CONNECT_TIMEOUT` error.
25
+ */
26
+ error(): ImapFlowError;
27
+ /**
28
+ * Maps a dependency's own expiry onto the shared `CONNECT_TIMEOUT` shape, so callers see one
29
+ * timeout error whichever layer noticed first. The original error is kept as `_err`. Anything
30
+ * that is not a timeout is returned unchanged.
31
+ *
32
+ * @param err Error raised by a dependency during a connection phase.
33
+ * @returns Either the normalized timeout error or the original error.
34
+ */
35
+ normalize<T extends ImapFlowError | null | undefined>(err: T): T | ImapFlowError;
36
+ /**
37
+ * Throws before a phase is started if the budget is already used up, so no work is begun
38
+ * that could only ever time out.
39
+ */
40
+ check(): void;
41
+ /**
42
+ * Races a phase against the remaining budget. The timer is always cleared, so a completed
43
+ * phase never leaves a pending timer behind.
44
+ *
45
+ * @param promise Phase to run under the deadline.
46
+ * @returns Resolves with the phase result, rejects with `CONNECT_TIMEOUT`.
47
+ */
48
+ race<T>(promise: Promise<T>): Promise<T>;
49
+ }
@@ -1,8 +1,6 @@
1
- 'use strict';
2
-
1
+ import { clearTimer } from './tools.js';
3
2
  // Default upper bound for establishing a usable transport, including DNS and proxy negotiation.
4
- const CONNECT_TIMEOUT = 90 * 1000;
5
-
3
+ export const CONNECT_TIMEOUT = 90 * 1000;
6
4
  /**
7
5
  * One deadline for an entire connection attempt.
8
6
  *
@@ -11,25 +9,23 @@ const CONNECT_TIMEOUT = 90 * 1000;
11
9
  * comes from this deadline or is normalized from a dependency - is reported with the same
12
10
  * `CONNECT_TIMEOUT` error shape, so callers do not need to know which phase was blocked.
13
11
  */
14
- class ConnectionDeadline {
12
+ export class ConnectionDeadline {
15
13
  /**
16
- * @param {Number} [timeout] Configured connection timeout in milliseconds. Normalized once
14
+ * @param timeout Configured connection timeout in milliseconds. Normalized once
17
15
  * here; 0 and any other falsy or invalid value fall back to the 90 second default.
18
16
  */
19
17
  constructor(timeout) {
20
18
  this.timeout = Number(timeout) || CONNECT_TIMEOUT;
21
19
  this.startedAt = Date.now();
22
20
  }
23
-
24
21
  /**
25
- * @returns {Number} Milliseconds left in the budget, never negative.
22
+ * @returns Milliseconds left in the budget, never negative.
26
23
  */
27
24
  remaining() {
28
25
  return Math.max(0, this.timeout - (Date.now() - this.startedAt));
29
26
  }
30
-
31
27
  /**
32
- * @returns {Error} The shared `CONNECT_TIMEOUT` error.
28
+ * @returns The shared `CONNECT_TIMEOUT` error.
33
29
  */
34
30
  error() {
35
31
  let err = new Error('Failed to establish connection in required time');
@@ -37,30 +33,26 @@ class ConnectionDeadline {
37
33
  err.details = { connectionTimeout: this.timeout };
38
34
  return err;
39
35
  }
40
-
41
36
  /**
42
37
  * Maps a dependency's own expiry onto the shared `CONNECT_TIMEOUT` shape, so callers see one
43
38
  * timeout error whichever layer noticed first. The original error is kept as `_err`. Anything
44
39
  * that is not a timeout is returned unchanged.
45
40
  *
46
- * @param {Error} err Error raised by a dependency during a connection phase.
47
- * @returns {Error} Either the normalized timeout error or the original error.
41
+ * @param err Error raised by a dependency during a connection phase.
42
+ * @returns Either the normalized timeout error or the original error.
48
43
  */
49
44
  normalize(err) {
50
45
  if (!err || err.code === 'CONNECT_TIMEOUT') {
51
46
  return err;
52
47
  }
53
-
54
48
  // The `socks` client reports its own expiry as "Proxy connection timed out"
55
49
  if (err.code !== 'ETIMEDOUT' && !/timed out/i.test(err.message || '')) {
56
50
  return err;
57
51
  }
58
-
59
52
  let normalized = this.error();
60
53
  normalized._err = err;
61
54
  return normalized;
62
55
  }
63
-
64
56
  /**
65
57
  * Throws before a phase is started if the budget is already used up, so no work is begun
66
58
  * that could only ever time out.
@@ -70,29 +62,26 @@ class ConnectionDeadline {
70
62
  throw this.error();
71
63
  }
72
64
  }
73
-
74
65
  /**
75
66
  * Races a phase against the remaining budget. The timer is always cleared, so a completed
76
67
  * phase never leaves a pending timer behind.
77
68
  *
78
- * @param {Promise} promise Phase to run under the deadline.
79
- * @returns {Promise<*>} Resolves with the phase result, rejects with `CONNECT_TIMEOUT`.
69
+ * @param promise Phase to run under the deadline.
70
+ * @returns Resolves with the phase result, rejects with `CONNECT_TIMEOUT`.
80
71
  */
81
72
  async race(promise) {
82
73
  this.check();
83
-
84
74
  let timer = null;
85
75
  try {
86
76
  return await Promise.race([
87
77
  promise,
88
- new Promise((resolve, reject) => {
78
+ new Promise((_resolve, reject) => {
89
79
  timer = setTimeout(() => reject(this.error()), this.remaining());
90
80
  })
91
81
  ]);
92
- } finally {
93
- clearTimeout(timer);
82
+ }
83
+ finally {
84
+ clearTimer(timer);
94
85
  }
95
86
  }
96
87
  }
97
-
98
- module.exports = { ConnectionDeadline, CONNECT_TIMEOUT };