@bobfrankston/iflow 1.0.39 → 1.0.40

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.
@@ -112,6 +112,8 @@ export declare class NativeImapClient {
112
112
  appendMessage(mailbox: string, message: string | Uint8Array, flags?: string[]): Promise<number | null>;
113
113
  startIdle(onNewMail: (count: number) => void): Promise<() => Promise<void>>;
114
114
  getMessageCount(mailbox: string): Promise<number>;
115
+ /** Default timeout for IMAP commands (30s). Prevents hanging connections. */
116
+ private commandTimeout;
115
117
  private sendCommand;
116
118
  private waitForContinuation;
117
119
  private waitForTagged;
@@ -31,10 +31,24 @@ export class NativeImapClient {
31
31
  async connect() {
32
32
  const useTls = this.config.port === 993;
33
33
  this.transport.onData((data) => this.handleData(data));
34
- this.transport.onClose(() => { this._connected = false; });
34
+ this.transport.onClose(() => {
35
+ this._connected = false;
36
+ // Reject any pending command so it doesn't hang forever
37
+ if (this.pendingCommand) {
38
+ const { reject } = this.pendingCommand;
39
+ this.pendingCommand = null;
40
+ reject(new Error("Connection closed"));
41
+ }
42
+ });
35
43
  this.transport.onError((err) => {
36
44
  if (this.verbose)
37
45
  console.error(` [imap] Transport error: ${err.message}`);
46
+ // Reject any pending command on transport error
47
+ if (this.pendingCommand) {
48
+ const { reject } = this.pendingCommand;
49
+ this.pendingCommand = null;
50
+ reject(err);
51
+ }
38
52
  });
39
53
  await this.transport.connect(this.config.server, this.config.port, useTls, this.config.server);
40
54
  // Read server greeting
@@ -133,10 +147,15 @@ export class NativeImapClient {
133
147
  try {
134
148
  if (this._connected) {
135
149
  const tag = proto.nextTag();
136
- await this.sendCommand(tag, proto.logoutCommand(tag));
150
+ // Timeout the LOGOUT command — don't let it hang forever
151
+ await Promise.race([
152
+ this.sendCommand(tag, proto.logoutCommand(tag)),
153
+ new Promise((_, reject) => setTimeout(() => reject(new Error("LOGOUT timeout")), 5000))
154
+ ]);
137
155
  }
138
156
  }
139
- catch { /* ignore */ }
157
+ catch { /* ignore — always close transport below */ }
158
+ this.pendingCommand = null; // clear any hanging promise
140
159
  this.transport.close();
141
160
  this._connected = false;
142
161
  }
@@ -399,13 +418,23 @@ export class NativeImapClient {
399
418
  return status.messages || 0;
400
419
  }
401
420
  // ── Low-level command handling ──
421
+ /** Default timeout for IMAP commands (30s). Prevents hanging connections. */
422
+ commandTimeout = 30000;
402
423
  sendCommand(tag, command) {
403
424
  return new Promise((resolve, reject) => {
404
425
  if (this.verbose && !command.includes("LOGIN") && !command.includes("AUTHENTICATE")) {
405
426
  console.log(` [imap] > ${command.trimEnd()}`);
406
427
  }
407
- this.pendingCommand = { tag, resolve, reject, responses: [] };
408
- this.transport.write(command).catch(reject);
428
+ const timer = setTimeout(() => {
429
+ this.pendingCommand = null;
430
+ reject(new Error(`IMAP command timeout (${this.commandTimeout / 1000}s): ${command.split("\r")[0].substring(0, 50)}`));
431
+ }, this.commandTimeout);
432
+ this.pendingCommand = {
433
+ tag, responses: [],
434
+ resolve: (responses) => { clearTimeout(timer); resolve(responses); },
435
+ reject: (err) => { clearTimeout(timer); reject(err); },
436
+ };
437
+ this.transport.write(command).catch((err) => { clearTimeout(timer); reject(err); });
409
438
  });
410
439
  }
411
440
  waitForContinuation(tag) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bobfrankston/iflow",
3
- "version": "1.0.39",
3
+ "version": "1.0.40",
4
4
  "description": "IMAP client wrapper library",
5
5
  "main": "index.js",
6
6
  "types": "index.ts",