imapkit 5.0.1 → 5.1.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.
- package/README.md +18 -0
- package/dist/browser/imapkit.js +105 -0
- package/dist/cjs/index.d.ts +1 -0
- package/dist/cjs/memory-socket.d.ts +69 -0
- package/dist/cjs/memory-socket.js +187 -0
- package/dist/cjs/plugins/idle.js +2 -2
- package/dist/cjs/server.d.ts +13 -0
- package/dist/cjs/server.js +31 -5
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/memory-socket.d.ts +69 -0
- package/dist/esm/memory-socket.js +182 -0
- package/dist/esm/plugins/idle.js +2 -2
- package/dist/esm/server.d.ts +13 -0
- package/dist/esm/server.js +31 -5
- package/package.json +8 -1
package/dist/esm/server.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ import type { ResolvedCommandOptions } from './command-states.js';
|
|
|
6
6
|
import { Control } from './control.js';
|
|
7
7
|
import type { RestServer } from './rest.js';
|
|
8
8
|
import type { SessionInfo } from './control.js';
|
|
9
|
+
import type { MemorySocket } from './memory-socket.js';
|
|
9
10
|
import { ServerScript } from './script.js';
|
|
10
11
|
import type { DeferredOutput, OutputOperation, ScriptContext, ScriptEvent, ScriptRule } from './script.js';
|
|
11
12
|
import type { AppendCheck, AppendCheckOptions, AppendDataHandler, AppendMessage, CapabilityCheck, CheckResult, ClosedCheck, CommandCheck, CommandContext, CommandOptions, CommandHandler, ConnectionHandler, ConnectionState, CopyHandler, FetchHandler, IMAPResponse, IMAPServerOptions, ListedMailbox, LiteralFilter, Mailbox, MailboxHandler, MailboxStatus, Message, MessageFilter, MessageHandler, MessageRange, Namespace, Notification, NotifyEvent, NotifyFilter, OutputHandler, ParsedCommand, RangeLimit, Refusal, SearchAccessCheck, SearchHandler, SearchLimit, ServerStorage, StatusHandler, StorageMailbox, StorageMessage, StoreHandler, SubscriptionStandIn, Transport, UrlAccessCheck, UserData } from './types.js';
|
|
@@ -158,6 +159,18 @@ declare class IMAPServer extends Stream {
|
|
|
158
159
|
};
|
|
159
160
|
address(): ReturnType<net.Server['address']>;
|
|
160
161
|
createClient(socket: net.Socket): void;
|
|
162
|
+
/**
|
|
163
|
+
* Opens a connection to the server in memory, without a network socket (no `listen()` needed). This is how the
|
|
164
|
+
* server runs in a browser, see the README "Run in a browser"
|
|
165
|
+
*
|
|
166
|
+
* @param {Object} [options] `{ secure }`: false makes the connection a plaintext one, where STARTTLS turns on the
|
|
167
|
+
* encryption (nothing is encrypted, the session only counts as encrypted). By default the connection counts as
|
|
168
|
+
* one over TLS
|
|
169
|
+
* @return {MemorySocket} the client end, write commands to it and read the responses from its `data` events
|
|
170
|
+
*/
|
|
171
|
+
connect(options?: {
|
|
172
|
+
secure?: boolean | undefined;
|
|
173
|
+
}): MemorySocket;
|
|
161
174
|
registerCapability(keyword: string, handler?: CapabilityCheck | null): void;
|
|
162
175
|
/**
|
|
163
176
|
* Sets the handler of a command
|
package/dist/esm/server.js
CHANGED
|
@@ -19,6 +19,7 @@ import { resolveQuirks } from './quirks.js';
|
|
|
19
19
|
import { validateStorage } from './storage-schema.js';
|
|
20
20
|
import { createRestServer } from './rest.js';
|
|
21
21
|
import * as bundledCert from './cert.js';
|
|
22
|
+
import { createSocketPair } from './memory-socket.js';
|
|
22
23
|
import { ServerScript, sendOutput, handleLine, handleQuiet, literalResponse, releaseDeferred } from './script.js';
|
|
23
24
|
// longest command line (not counting literals) accepted from a client
|
|
24
25
|
const MAX_LINE_LENGTH = 1024 * 1024;
|
|
@@ -359,6 +360,21 @@ class IMAPServer extends Stream {
|
|
|
359
360
|
handler(connection);
|
|
360
361
|
});
|
|
361
362
|
}
|
|
363
|
+
/**
|
|
364
|
+
* Opens a connection to the server in memory, without a network socket (no `listen()` needed). This is how the
|
|
365
|
+
* server runs in a browser, see the README "Run in a browser"
|
|
366
|
+
*
|
|
367
|
+
* @param {Object} [options] `{ secure }`: false makes the connection a plaintext one, where STARTTLS turns on the
|
|
368
|
+
* encryption (nothing is encrypted, the session only counts as encrypted). By default the connection counts as
|
|
369
|
+
* one over TLS
|
|
370
|
+
* @return {MemorySocket} the client end, write commands to it and read the responses from its `data` events
|
|
371
|
+
*/
|
|
372
|
+
connect(options) {
|
|
373
|
+
const [serverSocket, clientSocket] = createSocketPair();
|
|
374
|
+
serverSocket.encrypted = clientSocket.encrypted = !options || options.secure !== false;
|
|
375
|
+
this.createClient(serverSocket);
|
|
376
|
+
return clientSocket;
|
|
377
|
+
}
|
|
362
378
|
registerCapability(keyword, handler) {
|
|
363
379
|
this.capabilities[keyword] =
|
|
364
380
|
handler ||
|
|
@@ -1396,7 +1412,8 @@ class IMAPConnection {
|
|
|
1396
1412
|
this._outputQueue = null;
|
|
1397
1413
|
this._outputTimer = null;
|
|
1398
1414
|
this._deferredOutput = null;
|
|
1399
|
-
|
|
1415
|
+
// a TLS socket is encrypted, and so can be an in-memory connection of server.connect()
|
|
1416
|
+
this.secureConnection = !!this.options.secureConnection || socket.encrypted === true;
|
|
1400
1417
|
this._remainder = '';
|
|
1401
1418
|
this._command = '';
|
|
1402
1419
|
this._literalRemaining = 0;
|
|
@@ -1414,7 +1431,7 @@ class IMAPConnection {
|
|
|
1414
1431
|
this.messageGlobal = false;
|
|
1415
1432
|
this._commandQueue = [];
|
|
1416
1433
|
this._processing = false;
|
|
1417
|
-
if (this.options.debug) {
|
|
1434
|
+
if (this.options.debug && typeof this.socket.pipe === 'function') {
|
|
1418
1435
|
this.socket.pipe(process.stdout);
|
|
1419
1436
|
}
|
|
1420
1437
|
this.socket.on('data', this.receive.bind(this));
|
|
@@ -1653,7 +1670,8 @@ class IMAPConnection {
|
|
|
1653
1670
|
this.watchQuiet(quiet);
|
|
1654
1671
|
}
|
|
1655
1672
|
}, Math.max(0, next - (Date.now() - last)));
|
|
1656
|
-
|
|
1673
|
+
// browsers have no unref
|
|
1674
|
+
this._quietTimer.unref?.();
|
|
1657
1675
|
}
|
|
1658
1676
|
/**
|
|
1659
1677
|
* Handles data from the socket, through the transport layer if there is one
|
|
@@ -2323,6 +2341,16 @@ class IMAPConnection {
|
|
|
2323
2341
|
// section 6.2.1). STARTTLS is refused when input is waiting (the noPipelining command option), this only
|
|
2324
2342
|
// guards against plugins that upgrade the connection otherwise
|
|
2325
2343
|
this.discardInput();
|
|
2344
|
+
// STARTTLS runs on a live connection
|
|
2345
|
+
const socket = this.socket;
|
|
2346
|
+
if (typeof socket.startTls === 'function') {
|
|
2347
|
+
// a socket without a TLS layer that can count as encrypted (MemorySocket of server.connect())
|
|
2348
|
+
return socket.startTls(() => {
|
|
2349
|
+
this.secureConnection = true;
|
|
2350
|
+
this.upgrading = false;
|
|
2351
|
+
callback();
|
|
2352
|
+
});
|
|
2353
|
+
}
|
|
2326
2354
|
const secureContext = tls.createSecureContext(this.server.getCredentials());
|
|
2327
2355
|
const socketOptions = {
|
|
2328
2356
|
secureContext: secureContext,
|
|
@@ -2333,8 +2361,6 @@ class IMAPConnection {
|
|
|
2333
2361
|
cb(null, secureContext);
|
|
2334
2362
|
}
|
|
2335
2363
|
};
|
|
2336
|
-
// STARTTLS runs on a live connection
|
|
2337
|
-
const socket = this.socket;
|
|
2338
2364
|
// the RST of a script rule goes to the TCP socket under the TLS layer, see resetSocket. Node also has it as the
|
|
2339
2365
|
// _parent of the TLS socket, Bun does not
|
|
2340
2366
|
this.tcpSocket = socket;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "imapkit",
|
|
3
|
-
"version": "5.0
|
|
3
|
+
"version": "5.1.0",
|
|
4
4
|
"description": "Scriptable, strictly RFC compliant in-memory IMAP server for testing IMAP clients",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/cjs/index.js",
|
|
@@ -18,6 +18,10 @@
|
|
|
18
18
|
"import": "./dist/esm/index.js",
|
|
19
19
|
"require": "./dist/cjs/index.js"
|
|
20
20
|
},
|
|
21
|
+
"./browser": {
|
|
22
|
+
"types": "./dist/esm/index.d.ts",
|
|
23
|
+
"default": "./dist/browser/imapkit.js"
|
|
24
|
+
},
|
|
21
25
|
"./lib/server": {
|
|
22
26
|
"import": "./dist/esm/index.js",
|
|
23
27
|
"require": "./dist/cjs/index.js"
|
|
@@ -89,8 +93,11 @@
|
|
|
89
93
|
"@eslint/js": "10.0.1",
|
|
90
94
|
"@types/node": "20.19.43",
|
|
91
95
|
"@types/smtp-server": "3.5.13",
|
|
96
|
+
"buffer": "6.0.3",
|
|
97
|
+
"esbuild": "0.28.2",
|
|
92
98
|
"eslint": "10.12.0",
|
|
93
99
|
"eslint-config-prettier": "10.1.8",
|
|
100
|
+
"events": "3.3.0",
|
|
94
101
|
"globals": "17.13.0",
|
|
95
102
|
"imapflow": "2.2.9",
|
|
96
103
|
"prettier": "3.9.9",
|