imapkit 4.3.1 → 5.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 (93) hide show
  1. package/README.md +167 -51
  2. package/bin/help.txt +17 -3
  3. package/bin/imapkit.js +53 -23
  4. package/dist/cjs/commands/append.js +1 -1
  5. package/dist/cjs/commands/create.js +2 -2
  6. package/dist/cjs/commands/delete.js +2 -14
  7. package/dist/cjs/commands/handlers/flags.d.ts +3 -3
  8. package/dist/cjs/commands/handlers/flags.js +3 -3
  9. package/dist/cjs/commands/handlers/store.js +3 -3
  10. package/dist/cjs/commands/rename.js +6 -46
  11. package/dist/cjs/commands/select.js +1 -0
  12. package/dist/cjs/commands/subscribe.js +7 -8
  13. package/dist/cjs/commands/unsubscribe.js +3 -9
  14. package/dist/cjs/control.d.ts +430 -0
  15. package/dist/cjs/control.js +637 -0
  16. package/dist/cjs/index.d.ts +8 -1
  17. package/dist/cjs/index.js +9 -2
  18. package/dist/cjs/load-plugins.d.ts +1 -1
  19. package/dist/cjs/load-plugins.js +7 -2
  20. package/dist/cjs/plugins/acl.js +109 -42
  21. package/dist/cjs/plugins/condstore.js +7 -0
  22. package/dist/cjs/plugins/index.js +1 -3
  23. package/dist/cjs/plugins/metadata.js +140 -57
  24. package/dist/cjs/plugins/objectid.js +10 -0
  25. package/dist/cjs/plugins/quota.js +50 -2
  26. package/dist/cjs/plugins/savedate.js +1 -1
  27. package/dist/cjs/plugins/special-use.d.ts +0 -8
  28. package/dist/cjs/plugins/special-use.js +23 -0
  29. package/dist/cjs/quirks.d.ts +28 -0
  30. package/dist/cjs/quirks.js +124 -0
  31. package/dist/cjs/random.d.ts +10 -0
  32. package/dist/cjs/random.js +22 -0
  33. package/dist/cjs/rest.d.ts +50 -0
  34. package/dist/cjs/rest.js +561 -0
  35. package/dist/cjs/script.d.ts +33 -4
  36. package/dist/cjs/script.js +64 -4
  37. package/dist/cjs/server.d.ts +147 -8
  38. package/dist/cjs/server.js +398 -144
  39. package/dist/cjs/smtp-listener.d.ts +3 -2
  40. package/dist/cjs/smtp-listener.js +10 -6
  41. package/dist/cjs/storage-schema.d.ts +139 -0
  42. package/dist/cjs/storage-schema.js +215 -0
  43. package/dist/cjs/store-operations.d.ts +168 -0
  44. package/dist/cjs/store-operations.js +422 -0
  45. package/dist/cjs/types.d.ts +22 -1
  46. package/dist/esm/commands/append.js +1 -1
  47. package/dist/esm/commands/create.js +2 -2
  48. package/dist/esm/commands/delete.js +2 -14
  49. package/dist/esm/commands/handlers/flags.d.ts +3 -3
  50. package/dist/esm/commands/handlers/flags.js +3 -3
  51. package/dist/esm/commands/handlers/store.js +3 -3
  52. package/dist/esm/commands/rename.js +6 -46
  53. package/dist/esm/commands/select.js +1 -0
  54. package/dist/esm/commands/subscribe.js +7 -8
  55. package/dist/esm/commands/unsubscribe.js +3 -9
  56. package/dist/esm/control.d.ts +430 -0
  57. package/dist/esm/control.js +630 -0
  58. package/dist/esm/index.d.ts +8 -1
  59. package/dist/esm/index.js +5 -2
  60. package/dist/esm/load-plugins.d.ts +1 -1
  61. package/dist/esm/load-plugins.js +7 -2
  62. package/dist/esm/plugins/acl.js +109 -42
  63. package/dist/esm/plugins/condstore.js +7 -0
  64. package/dist/esm/plugins/index.js +1 -3
  65. package/dist/esm/plugins/metadata.js +140 -57
  66. package/dist/esm/plugins/objectid.js +10 -0
  67. package/dist/esm/plugins/quota.js +50 -2
  68. package/dist/esm/plugins/savedate.js +1 -1
  69. package/dist/esm/plugins/special-use.d.ts +0 -8
  70. package/dist/esm/plugins/special-use.js +23 -0
  71. package/dist/esm/quirks.d.ts +28 -0
  72. package/dist/esm/quirks.js +120 -0
  73. package/dist/esm/random.d.ts +10 -0
  74. package/dist/esm/random.js +19 -0
  75. package/dist/esm/rest.d.ts +50 -0
  76. package/dist/esm/rest.js +553 -0
  77. package/dist/esm/script.d.ts +33 -4
  78. package/dist/esm/script.js +63 -4
  79. package/dist/esm/server.d.ts +147 -8
  80. package/dist/esm/server.js +399 -145
  81. package/dist/esm/smtp-listener.d.ts +3 -2
  82. package/dist/esm/smtp-listener.js +10 -6
  83. package/dist/esm/storage-schema.d.ts +139 -0
  84. package/dist/esm/storage-schema.js +211 -0
  85. package/dist/esm/store-operations.d.ts +168 -0
  86. package/dist/esm/store-operations.js +407 -0
  87. package/dist/esm/types.d.ts +22 -1
  88. package/dist/plugin-help.json +0 -14
  89. package/package.json +11 -3
  90. package/dist/cjs/plugins/xtoybird.d.ts +0 -2
  91. package/dist/cjs/plugins/xtoybird.js +0 -236
  92. package/dist/esm/plugins/xtoybird.d.ts +0 -2
  93. package/dist/esm/plugins/xtoybird.js +0 -218
@@ -7,7 +7,8 @@ import type { IMAPServer } from './types.js';
7
7
  *
8
8
  * @param {Number} smtpPort - port to listen on for SMTP commands
9
9
  * @param {Object} imapServer - the ImapKit IMAP server
10
- * @param {Function} [callback] - function executed when SMTP server is listening
10
+ * @param {Function} [callback] - function executed when SMTP server is listening, with the port
11
+ * @param {String} [host] - address to listen on, all addresses if not set
11
12
  * @return {SMTPServer} the SMTP server instance, use `close()` to stop it
12
13
  */
13
- export declare function startSMTPServer(smtpPort: number, imapServer: IMAPServer, callback?: (() => void) | null): SMTPServer;
14
+ export declare function startSMTPServer(smtpPort: number, imapServer: IMAPServer, callback?: ((port: number) => void) | null, host?: string): SMTPServer;
@@ -9,10 +9,11 @@ const smtp_server_1 = require("smtp-server");
9
9
  *
10
10
  * @param {Number} smtpPort - port to listen on for SMTP commands
11
11
  * @param {Object} imapServer - the ImapKit IMAP server
12
- * @param {Function} [callback] - function executed when SMTP server is listening
12
+ * @param {Function} [callback] - function executed when SMTP server is listening, with the port
13
+ * @param {String} [host] - address to listen on, all addresses if not set
13
14
  * @return {SMTPServer} the SMTP server instance, use `close()` to stop it
14
15
  */
15
- function startSMTPServer(smtpPort, imapServer, callback) {
16
+ function startSMTPServer(smtpPort, imapServer, callback, host) {
16
17
  const credentials = imapServer.getCredentials();
17
18
  const server = new smtp_server_1.SMTPServer({
18
19
  banner: 'ImapKit',
@@ -39,9 +40,12 @@ function startSMTPServer(smtpPort, imapServer, callback) {
39
40
  console.error('SMTP server error: %s', err.message);
40
41
  }
41
42
  });
42
- server.listen(smtpPort, () => {
43
- console.log('Incoming SMTP server up and running on port %s', server.server.address().port);
44
- callback?.();
45
- });
43
+ const onListening = () => callback?.(server.server.address().port);
44
+ if (host) {
45
+ server.listen(smtpPort, host, onListening);
46
+ }
47
+ else {
48
+ server.listen(smtpPort, onListening);
49
+ }
46
50
  return server;
47
51
  }
@@ -0,0 +1,139 @@
1
+ /**
2
+ * The shape of the `storage` option, which is also the shape of `server.control.snapshot()`: a JSON Schema for
3
+ * editors and other tools, and the check the server runs on the option, so that a typo in a fixture ("message" for
4
+ * "messages") fails with a clear error instead of an empty mailbox. Plugins keep their own data on mailboxes and
5
+ * messages (acl, metadata, MODSEQ ...), so other keys are allowed, only the types of the known keys are checked
6
+ */
7
+ /** JSON Schema (draft 2020-12) of the `storage` option */
8
+ export declare const storageSchema: {
9
+ readonly $schema: "https://json-schema.org/draft/2020-12/schema";
10
+ readonly title: "ImapKit storage";
11
+ readonly description: "Namespaces by prefix (\"INBOX\", \"\", \"INBOX.\", \"#shared/\" ...), INBOX is a mailbox of its own";
12
+ readonly type: "object";
13
+ readonly properties: {
14
+ readonly INBOX: {
15
+ readonly $ref: "#/$defs/mailbox";
16
+ };
17
+ };
18
+ readonly additionalProperties: {
19
+ readonly $ref: "#/$defs/namespace";
20
+ };
21
+ readonly $defs: {
22
+ readonly message: {
23
+ readonly oneOf: readonly [{
24
+ readonly type: "string";
25
+ readonly description: "the message source";
26
+ }, {
27
+ readonly type: "object";
28
+ readonly properties: {
29
+ readonly raw: {
30
+ readonly type: "string";
31
+ readonly description: "the message source (a Buffer also works in JavaScript)";
32
+ };
33
+ readonly uid: {
34
+ type: string;
35
+ minimum: number;
36
+ maximum: number;
37
+ };
38
+ readonly flags: {
39
+ readonly oneOf: readonly [{
40
+ readonly type: "string";
41
+ }, {
42
+ type: string;
43
+ items: {
44
+ type: string;
45
+ };
46
+ }];
47
+ };
48
+ readonly internaldate: {
49
+ readonly type: "string";
50
+ readonly description: "RFC 3501 date-time, e.g. \"14-Sep-2013 21:22:28 -0300\" (a Date also works in JavaScript)";
51
+ };
52
+ readonly recent: {
53
+ readonly type: "boolean";
54
+ };
55
+ };
56
+ }];
57
+ };
58
+ readonly mailbox: {
59
+ readonly type: "object";
60
+ readonly properties: {
61
+ readonly uid: {
62
+ readonly type: "integer";
63
+ };
64
+ readonly uidvalidity: {
65
+ type: string;
66
+ minimum: number;
67
+ maximum: number;
68
+ };
69
+ readonly uidnext: {
70
+ type: string;
71
+ minimum: number;
72
+ maximum: number;
73
+ };
74
+ readonly flags: {
75
+ type: string;
76
+ items: {
77
+ type: string;
78
+ };
79
+ };
80
+ readonly permanentFlags: {
81
+ type: string;
82
+ items: {
83
+ type: string;
84
+ };
85
+ };
86
+ readonly allowPermanentFlags: {
87
+ readonly type: "boolean";
88
+ };
89
+ readonly subscribed: {
90
+ readonly type: "boolean";
91
+ };
92
+ readonly knownFlags: {
93
+ type: string;
94
+ items: {
95
+ type: string;
96
+ };
97
+ };
98
+ readonly messages: {
99
+ readonly type: "array";
100
+ readonly items: {
101
+ readonly $ref: "#/$defs/message";
102
+ };
103
+ };
104
+ readonly folders: {
105
+ readonly type: "object";
106
+ readonly additionalProperties: {
107
+ readonly $ref: "#/$defs/mailbox";
108
+ };
109
+ };
110
+ };
111
+ };
112
+ readonly namespace: {
113
+ readonly type: "object";
114
+ readonly properties: {
115
+ readonly separator: {
116
+ readonly type: "string";
117
+ readonly minLength: 1;
118
+ readonly maxLength: 1;
119
+ };
120
+ readonly type: {
121
+ readonly enum: readonly ["personal", "user", "shared"];
122
+ };
123
+ readonly folders: {
124
+ readonly type: "object";
125
+ readonly additionalProperties: {
126
+ readonly $ref: "#/$defs/mailbox";
127
+ };
128
+ };
129
+ };
130
+ };
131
+ };
132
+ };
133
+ /**
134
+ * Checks the `storage` option
135
+ *
136
+ * @param {Object} storage Storage
137
+ * @throws {Error} "Invalid storage at <path>: <problem>"
138
+ */
139
+ export declare function validateStorage(storage: unknown): void;
@@ -0,0 +1,215 @@
1
+ "use strict";
2
+ /**
3
+ * The shape of the `storage` option, which is also the shape of `server.control.snapshot()`: a JSON Schema for
4
+ * editors and other tools, and the check the server runs on the option, so that a typo in a fixture ("message" for
5
+ * "messages") fails with a clear error instead of an empty mailbox. Plugins keep their own data on mailboxes and
6
+ * messages (acl, metadata, MODSEQ ...), so other keys are allowed, only the types of the known keys are checked
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.storageSchema = void 0;
10
+ exports.validateStorage = validateStorage;
11
+ const numbers_js_1 = require("./numbers.js");
12
+ // keys of plugins, an unknown key that looks like a typo of a known key is refused unless a plugin uses it
13
+ const PLUGIN_KEYS = [
14
+ 'acl',
15
+ 'metadata',
16
+ 'special-use',
17
+ 'MAILBOXID',
18
+ 'HIGHESTMODSEQ',
19
+ 'qresyncExpunged',
20
+ 'appendLimit',
21
+ 'SAVEDATE',
22
+ 'MODSEQ',
23
+ 'EMAILID',
24
+ 'THREADID',
25
+ 'X-GM-LABELS',
26
+ 'X-GM-MSGID',
27
+ 'X-GM-THRID'
28
+ ];
29
+ const flagList = { type: 'array', items: { type: 'string' } };
30
+ const nzNumber = { type: 'integer', minimum: 1, maximum: numbers_js_1.MAX_NUMBER };
31
+ /** JSON Schema (draft 2020-12) of the `storage` option */
32
+ exports.storageSchema = {
33
+ $schema: 'https://json-schema.org/draft/2020-12/schema',
34
+ title: 'ImapKit storage',
35
+ description: 'Namespaces by prefix ("INBOX", "", "INBOX.", "#shared/" ...), INBOX is a mailbox of its own',
36
+ type: 'object',
37
+ properties: { INBOX: { $ref: '#/$defs/mailbox' } },
38
+ additionalProperties: { $ref: '#/$defs/namespace' },
39
+ $defs: {
40
+ message: {
41
+ oneOf: [
42
+ { type: 'string', description: 'the message source' },
43
+ {
44
+ type: 'object',
45
+ properties: {
46
+ raw: { type: 'string', description: 'the message source (a Buffer also works in JavaScript)' },
47
+ uid: nzNumber,
48
+ flags: { oneOf: [{ type: 'string' }, flagList] },
49
+ internaldate: {
50
+ type: 'string',
51
+ description: 'RFC 3501 date-time, e.g. "14-Sep-2013 21:22:28 -0300" (a Date also works in JavaScript)'
52
+ },
53
+ recent: { type: 'boolean' }
54
+ }
55
+ }
56
+ ]
57
+ },
58
+ mailbox: {
59
+ type: 'object',
60
+ properties: {
61
+ uid: { type: 'integer' },
62
+ uidvalidity: nzNumber,
63
+ uidnext: nzNumber,
64
+ flags: flagList,
65
+ permanentFlags: flagList,
66
+ allowPermanentFlags: { type: 'boolean' },
67
+ subscribed: { type: 'boolean' },
68
+ knownFlags: flagList,
69
+ messages: { type: 'array', items: { $ref: '#/$defs/message' } },
70
+ folders: { type: 'object', additionalProperties: { $ref: '#/$defs/mailbox' } }
71
+ }
72
+ },
73
+ namespace: {
74
+ type: 'object',
75
+ properties: {
76
+ separator: { type: 'string', minLength: 1, maxLength: 1 },
77
+ type: { enum: ['personal', 'user', 'shared'] },
78
+ folders: { type: 'object', additionalProperties: { $ref: '#/$defs/mailbox' } }
79
+ }
80
+ }
81
+ }
82
+ };
83
+ // the keys the schema knows, the typo check compares unknown keys with them
84
+ const MAILBOX_KEYS = Object.keys(exports.storageSchema.$defs.mailbox.properties);
85
+ const NAMESPACE_KEYS = ['separator', 'type'];
86
+ const MESSAGE_KEYS = Object.keys(exports.storageSchema.$defs.message.oneOf[1].properties);
87
+ /**
88
+ * Finds the known key that an unknown key looks like a typo of: the same key in another case, or one edit away
89
+ *
90
+ * @param {String} key Unknown key
91
+ * @param {Array} known Known keys
92
+ * @return {String|null} the known key, or null
93
+ */
94
+ function typoOf(key, known) {
95
+ if (known.includes(key) || PLUGIN_KEYS.includes(key)) {
96
+ return null;
97
+ }
98
+ return known.find(name => name.toLowerCase() === key.toLowerCase() || (key.length > 3 && editDistance(name, key) === 1)) || null;
99
+ }
100
+ /**
101
+ * Levenshtein distance, only used for short keys
102
+ */
103
+ function editDistance(a, b) {
104
+ const row = Array.from({ length: b.length + 1 }, (_, i) => i);
105
+ for (let i = 1; i <= a.length; i++) {
106
+ let previous = row[0];
107
+ row[0] = i;
108
+ for (let j = 1; j <= b.length; j++) {
109
+ const current = row[j];
110
+ row[j] = Math.min(row[j] + 1, row[j - 1] + 1, previous + (a[i - 1] === b[j - 1] ? 0 : 1));
111
+ previous = current;
112
+ }
113
+ }
114
+ return row[b.length];
115
+ }
116
+ const isObject = (value) => !!value && typeof value === 'object' && !Array.isArray(value);
117
+ const isFlagList = (value) => Array.isArray(value) && value.every(flag => typeof flag === 'string');
118
+ const isNz = (value) => Number.isSafeInteger(value) && value >= 1 && value <= numbers_js_1.MAX_NUMBER;
119
+ /**
120
+ * Checks the `storage` option
121
+ *
122
+ * @param {Object} storage Storage
123
+ * @throws {Error} "Invalid storage at <path>: <problem>"
124
+ */
125
+ function validateStorage(storage) {
126
+ const fail = (path, problem) => {
127
+ throw new Error('Invalid storage at ' + path + ': ' + problem);
128
+ };
129
+ const checkKeys = (value, path, known) => {
130
+ Object.keys(value).forEach(key => {
131
+ const typo = typoOf(key, known);
132
+ if (typo) {
133
+ fail(path, 'unknown key ' + JSON.stringify(key) + ', did you mean ' + JSON.stringify(typo) + '?');
134
+ }
135
+ });
136
+ };
137
+ const checkMessage = (message, path) => {
138
+ if (typeof message === 'string' || message instanceof Uint8Array) {
139
+ return;
140
+ }
141
+ if (!isObject(message)) {
142
+ return fail(path, 'a message is a string or an object');
143
+ }
144
+ checkKeys(message, path, MESSAGE_KEYS);
145
+ if (message.raw !== undefined && typeof message.raw !== 'string' && !(message.raw instanceof Uint8Array)) {
146
+ fail(path + '.raw', 'must be a string');
147
+ }
148
+ if (message.uid !== undefined && !isNz(message.uid)) {
149
+ fail(path + '.uid', 'must be an integer from 1 to ' + numbers_js_1.MAX_NUMBER);
150
+ }
151
+ if (message.flags !== undefined && typeof message.flags !== 'string' && !isFlagList(message.flags)) {
152
+ fail(path + '.flags', 'must be a flag or a list of flags');
153
+ }
154
+ if (message.internaldate !== undefined &&
155
+ message.internaldate !== false &&
156
+ typeof message.internaldate !== 'string' &&
157
+ !(message.internaldate instanceof Date)) {
158
+ fail(path + '.internaldate', 'must be a date-time string or a Date');
159
+ }
160
+ if (message.recent !== undefined && typeof message.recent !== 'boolean') {
161
+ fail(path + '.recent', 'must be true or false');
162
+ }
163
+ };
164
+ const checkMailbox = (mailbox, path, known) => {
165
+ if (!isObject(mailbox)) {
166
+ return fail(path, 'a mailbox is an object');
167
+ }
168
+ checkKeys(mailbox, path, known);
169
+ for (const key of ['uidvalidity', 'uidnext']) {
170
+ if (mailbox[key] !== undefined && !isNz(mailbox[key])) {
171
+ fail(path + '.' + key, 'must be an integer from 1 to ' + numbers_js_1.MAX_NUMBER);
172
+ }
173
+ }
174
+ for (const key of ['flags', 'permanentFlags', 'knownFlags']) {
175
+ if (mailbox[key] !== undefined && !isFlagList(mailbox[key])) {
176
+ fail(path + '.' + key, 'must be a list of strings');
177
+ }
178
+ }
179
+ for (const key of ['allowPermanentFlags', 'subscribed']) {
180
+ if (mailbox[key] !== undefined && typeof mailbox[key] !== 'boolean') {
181
+ fail(path + '.' + key, 'must be true or false');
182
+ }
183
+ }
184
+ if (mailbox.messages !== undefined) {
185
+ if (!Array.isArray(mailbox.messages)) {
186
+ fail(path + '.messages', 'must be a list of messages');
187
+ }
188
+ mailbox.messages.forEach((message, i) => checkMessage(message, path + '.messages[' + i + ']'));
189
+ }
190
+ if (mailbox.folders !== undefined) {
191
+ if (!isObject(mailbox.folders)) {
192
+ fail(path + '.folders', 'must be an object of mailboxes by name');
193
+ }
194
+ Object.keys(mailbox.folders).forEach(name => checkMailbox(mailbox.folders[name], path + '.folders[' + JSON.stringify(name) + ']', MAILBOX_KEYS));
195
+ }
196
+ };
197
+ if (!isObject(storage)) {
198
+ fail('the top level', 'storage is an object of namespaces');
199
+ }
200
+ Object.keys(storage).forEach(key => {
201
+ const value = storage[key];
202
+ const path = JSON.stringify(key);
203
+ if (key === 'INBOX') {
204
+ return checkMailbox(value, path, MAILBOX_KEYS.concat('separator'));
205
+ }
206
+ checkMailbox(value, path, MAILBOX_KEYS.concat(NAMESPACE_KEYS));
207
+ const namespace = value;
208
+ if (namespace.separator !== undefined && (typeof namespace.separator !== 'string' || namespace.separator.length !== 1)) {
209
+ fail(path + '.separator', 'must be a single character');
210
+ }
211
+ if (namespace.type !== undefined && !['personal', 'user', 'shared'].includes(namespace.type)) {
212
+ fail(path + '.type', 'must be "personal", "user" or "shared"');
213
+ }
214
+ });
215
+ }
@@ -0,0 +1,168 @@
1
+ /**
2
+ * Changes of the message store that IMAP commands and the control API share: expunge, flag changes, and the
3
+ * mailbox operations of DELETE, RENAME, SUBSCRIBE and UNSUBSCRIBE. Each one tells the sessions about the change
4
+ * the way another session's command would (EXISTS, EXPUNGE, unsolicited FETCH, BYE, `mailbox` events). The
5
+ * session that caused a change is `server.activeConnection` (null for the control API), the commands keep only
6
+ * what is specific to a session: argument checks, the selected mailbox, read-only state and the responses.
7
+ */
8
+ import type { IMAPConnection, IMAPServer, Mailbox, Message } from './types.js';
9
+ /** the XOAUTH2 session timeout of the default user, and of a user the control API adds without one */
10
+ declare const DEFAULT_SESSION_TIMEOUT: number;
11
+ /** An error of a failed store operation or control API call, `code` is a RFC 5530 response code or INVALID */
12
+ declare class ImapKitError extends Error {
13
+ code: string;
14
+ constructor(message: string, code: string);
15
+ }
16
+ /**
17
+ * Creates an error for a failed operation, with a RFC 5530 response code
18
+ *
19
+ * @param {String} message Error message
20
+ * @param {String} code Response code, e.g. "NONEXISTENT"
21
+ * @return {Error} Error object
22
+ */
23
+ declare function storeError(message: string, code: string): ImapKitError;
24
+ interface ExpungeOptions {
25
+ /** the session that caused the expunge, for the `expunge` event (QRESYNC, NOTIFY), defaults to the active session */
26
+ origin?: IMAPConnection | null | undefined;
27
+ /** a session that gets no EXPUNGE and no EXISTS responses (CLOSE) */
28
+ skip?: IMAPConnection | false | null | undefined;
29
+ /** a session that gets the EXPUNGE responses but no EXISTS response (EXPUNGE, MOVE) */
30
+ skipExists?: IMAPConnection | false | null | undefined;
31
+ /** the EXPUNGE responses go from the highest UID to the lowest (MESSAGELIMIT, RFC 9738 section 3.1) */
32
+ highestFirst?: boolean | undefined;
33
+ }
34
+ /**
35
+ * Removes messages from a mailbox and tells the sessions that have it selected with EXPUNGE responses
36
+ * (VANISHED with QRESYNC) and a new EXISTS. The `expunge` event goes out before the notifications
37
+ *
38
+ * @param {Object} server IMAP server
39
+ * @param {Object} mailbox Mailbox of the messages
40
+ * @param {Array|Function} messagesOrFilterFunc Messages to remove, or a function that returns true for them
41
+ * @param {Object} [options] `{ origin, skip, skipExists, highestFirst }`
42
+ * @return {Array} the removed messages
43
+ */
44
+ declare function expungeMessages(server: IMAPServer, mailbox: Mailbox, messagesOrFilterFunc: Message[] | ((message: Message) => unknown), options?: ExpungeOptions): Message[];
45
+ /**
46
+ * Tells the sessions that have a mailbox selected about changed flags, they get an untagged FETCH with the
47
+ * new flags (RFC 3501 section 5.2)
48
+ *
49
+ * @param {Object} server IMAP server
50
+ * @param {Object} mailbox Mailbox of the messages
51
+ * @param {Array} messages Messages with changed flags
52
+ * @param {Object} [ignoreConnection] A session that is not told, e.g. the one whose STORE changed the flags
53
+ */
54
+ declare function notifyFlagChanges(server: IMAPServer, mailbox: Mailbox, messages: Message[], ignoreConnection?: IMAPConnection | null): void;
55
+ type FlagMode = 'set' | 'add' | 'remove';
56
+ /**
57
+ * Checks flags the way STORE does: system flags the server knows (never \Recent), valid keywords, and only
58
+ * permanent flags in a mailbox that does not allow new keywords
59
+ *
60
+ * @param {Object} server IMAP server
61
+ * @param {Object} mailbox Mailbox the flags are for
62
+ * @param {Array} flags Flags to check
63
+ * @param {Boolean} stored true if the flags are stored, so they must be permanent flags of the mailbox
64
+ * @return {Array} the normalized flags without duplicates
65
+ * @throws {Error} INVALID for a flag that can not be used
66
+ */
67
+ declare function checkFlags(server: IMAPServer, mailbox: Mailbox, flags: unknown, stored: boolean): string[];
68
+ /**
69
+ * Changes the flags of messages outside of a STORE command. The flags follow the rules of STORE: system flags
70
+ * the server knows (never \Recent), valid keywords, and only permanent flags in a mailbox that does not allow
71
+ * new keywords. Plugins learn about the changed messages from the `flags` event `(mailbox, messages, origin)`
72
+ * before the sessions are told (CONDSTORE gives them new mod-sequences there)
73
+ *
74
+ * @param {Object} server IMAP server
75
+ * @param {Object} mailbox Mailbox of the messages
76
+ * @param {Array} messages Messages to change
77
+ * @param {Array} flags Flags to set, add or remove
78
+ * @param {String} mode "set", "add" or "remove"
79
+ * @return {Array} the messages whose flags changed
80
+ */
81
+ declare function changeFlags(server: IMAPServer, mailbox: Mailbox, messages: Message[], flags: string[], mode: FlagMode): Message[];
82
+ /**
83
+ * Creates a mailbox (CREATE), with any missing superior hierarchy levels
84
+ *
85
+ * @param {Object} server IMAP server
86
+ * @param {String} path Storage name of the mailbox
87
+ * @return {Object} the created mailbox
88
+ * @throws {Error} with a RFC 5530 `code` (ALREADYEXISTS, CANNOT ...)
89
+ */
90
+ declare function createMailbox(server: IMAPServer, path: string): Mailbox;
91
+ /**
92
+ * Deletes a mailbox (DELETE). Other sessions that have it selected are disconnected with an untagged BYE
93
+ * (RFC 2180 section 3.3, RFC 2683 section 3.1.2), as they can not be told about the deletion in any other way
94
+ *
95
+ * @param {Object} server IMAP server
96
+ * @param {String} path Storage name of the mailbox
97
+ * @throws {Error} with a RFC 5530 `code` (NONEXISTENT, CANNOT, HASCHILDREN ...)
98
+ */
99
+ declare function deleteMailbox(server: IMAPServer, path: string): void;
100
+ /**
101
+ * Renames a mailbox (RENAME). Renaming INBOX moves its messages to the new mailbox and leaves INBOX
102
+ * empty (RFC 3501 section 6.3.5). Everything that can be checked is checked up front, so that a failed
103
+ * rename never loses the source
104
+ *
105
+ * @param {Object} server IMAP server
106
+ * @param {String} source Storage name of the mailbox
107
+ * @param {String} destination New storage name
108
+ * @return {Object} `{ path, mailbox }`: the new name, and the source mailbox object, which is INBOX itself for
109
+ * a rename of INBOX
110
+ * @throws {Error} with a RFC 5530 `code` (NONEXISTENT, ALREADYEXISTS, CANNOT ...)
111
+ */
112
+ declare function renameMailbox(server: IMAPServer, source: string, destination: string): {
113
+ path: string;
114
+ mailbox: Mailbox;
115
+ };
116
+ type UidMode = 'keep' | 'renumber' | 'shuffle' | 'offset';
117
+ interface UidValidityOptions {
118
+ /** the new UIDVALIDITY, it must be greater than the current one. Default: one above every value in use */
119
+ uidvalidity?: number | undefined;
120
+ /** what happens to the UIDs: "keep" (default), "renumber" (1 to n in the current order), "shuffle" (1 to n in a
121
+ * random order) or "offset" (every UID moves above the old UIDNEXT, plus `offset`) */
122
+ uids?: UidMode | undefined;
123
+ /** extra gap for "offset" */
124
+ offset?: number | undefined;
125
+ /** seed of the "shuffle" order, for repeatable tests */
126
+ seed?: number | undefined;
127
+ }
128
+ /**
129
+ * Gives a mailbox a new UIDVALIDITY, optionally with new UIDs. A UID never changes during a session (RFC 9051
130
+ * section 2.3.1.1), so the sessions that have the mailbox selected are disconnected with BYE, and the new value
131
+ * is greater than every earlier one, as UIDs that do not persist require. A client that keeps its cached UIDs
132
+ * without checking UIDVALIDITY gets other messages ("shuffle") or none ("offset") for them
133
+ *
134
+ * @param {Object} server IMAP server
135
+ * @param {Object} mailbox Mailbox, not \Noselect
136
+ * @param {Object} [options] `{ uidvalidity, uids, offset, seed }`
137
+ * @return {Object} `{ uidvalidity, uidnext, uids }`, `uids` maps every old UID to its new one
138
+ * @throws {Error} INVALID for a UIDVALIDITY that is not greater, or invalid options
139
+ */
140
+ declare function resetUidValidity(server: IMAPServer, mailbox: Mailbox, options?: UidValidityOptions): {
141
+ uidvalidity: number;
142
+ uidnext: number;
143
+ uids: {
144
+ uid: number;
145
+ newUid: number;
146
+ }[];
147
+ };
148
+ /**
149
+ * Subscribes a mailbox (SUBSCRIBE), only an existing mailbox can be subscribed
150
+ *
151
+ * @param {Object} server IMAP server
152
+ * @param {String} path Storage name of the mailbox
153
+ * @return {Boolean} true if the subscription changed
154
+ * @throws {Error} NONEXISTENT for a name that is not a mailbox
155
+ */
156
+ declare function subscribeMailbox(server: IMAPServer, path: string): boolean;
157
+ /**
158
+ * Unsubscribes a name (UNSUBSCRIBE). The subscription list holds names, so a name stays removable after its
159
+ * mailbox is deleted (RFC 3501 section 6.3.6). Removing a name that is not subscribed is not an error
160
+ * (RFC 9051 section 6.3.8)
161
+ *
162
+ * @param {Object} server IMAP server
163
+ * @param {String} path Storage name
164
+ * @return {Boolean} true if the subscription changed
165
+ */
166
+ declare function unsubscribeMailbox(server: IMAPServer, path: string): boolean;
167
+ export { DEFAULT_SESSION_TIMEOUT, ImapKitError, storeError, expungeMessages, notifyFlagChanges, checkFlags, changeFlags, createMailbox, deleteMailbox, renameMailbox, resetUidValidity, subscribeMailbox, unsubscribeMailbox };
168
+ export type { ExpungeOptions, FlagMode, UidMode, UidValidityOptions };