@bobfrankston/iflow-direct 0.1.32 → 0.1.33
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/imap-native.d.ts +5 -0
- package/imap-native.js +34 -3
- package/package.json +1 -1
- package/types.d.ts +1 -0
package/imap-native.d.ts
CHANGED
|
@@ -173,6 +173,11 @@ export declare class NativeImapClient {
|
|
|
173
173
|
* 60s accommodates Gmail which is slow on SEARCH for large folders.
|
|
174
174
|
* Overridable via ImapClientConfig.inactivityTimeout — slow Dovecot servers need 180s+. */
|
|
175
175
|
private inactivityTimeout;
|
|
176
|
+
/** Hard wall-clock cap per command (independent of inactivityTimeout).
|
|
177
|
+
* A pathological server that returns one byte every (inactivityTimeout-1)
|
|
178
|
+
* seconds would otherwise defer the inactivity timer forever; this is
|
|
179
|
+
* the absolute deadline that always fires. Default 5 minutes. */
|
|
180
|
+
private commandWallClockTimeout;
|
|
176
181
|
/** Server-greeting timeout in ms — how long to wait for the server's
|
|
177
182
|
* initial banner after TCP/TLS connects. Default 10s; bumped to 30s
|
|
178
183
|
* for slow shared-hosting Dovecot in mailx-imap. */
|
package/imap-native.js
CHANGED
|
@@ -32,6 +32,10 @@ export class NativeImapClient {
|
|
|
32
32
|
this.transport = transportFactory();
|
|
33
33
|
this.verbose = config.verbose || false;
|
|
34
34
|
this.inactivityTimeout = config.inactivityTimeout ?? 60000;
|
|
35
|
+
// Hard wall-clock deadline per command (default 5 min). Distinct
|
|
36
|
+
// from inactivityTimeout — that one resets on each data chunk and
|
|
37
|
+
// can be deferred indefinitely by a slow-trickling server.
|
|
38
|
+
this.commandWallClockTimeout = config.commandWallClockTimeout ?? 300_000;
|
|
35
39
|
this.fetchChunkSize = config.fetchChunkSize ?? 25;
|
|
36
40
|
this.fetchChunkSizeMax = config.fetchChunkSizeMax ?? 500;
|
|
37
41
|
this.greetingTimeout = config.greetingTimeout ?? 10000;
|
|
@@ -729,6 +733,11 @@ export class NativeImapClient {
|
|
|
729
733
|
* 60s accommodates Gmail which is slow on SEARCH for large folders.
|
|
730
734
|
* Overridable via ImapClientConfig.inactivityTimeout — slow Dovecot servers need 180s+. */
|
|
731
735
|
inactivityTimeout;
|
|
736
|
+
/** Hard wall-clock cap per command (independent of inactivityTimeout).
|
|
737
|
+
* A pathological server that returns one byte every (inactivityTimeout-1)
|
|
738
|
+
* seconds would otherwise defer the inactivity timer forever; this is
|
|
739
|
+
* the absolute deadline that always fires. Default 5 minutes. */
|
|
740
|
+
commandWallClockTimeout;
|
|
732
741
|
/** Server-greeting timeout in ms — how long to wait for the server's
|
|
733
742
|
* initial banner after TCP/TLS connects. Default 10s; bumped to 30s
|
|
734
743
|
* for slow shared-hosting Dovecot in mailx-imap. */
|
|
@@ -796,21 +805,39 @@ export class NativeImapClient {
|
|
|
796
805
|
const waited = Date.now() - cmdStart;
|
|
797
806
|
console.log(` [imap] still waiting for tag ${tag} after ${(waited / 1000).toFixed(1)}s — ${cmdSummary}${transportDiag()}`);
|
|
798
807
|
}, HEARTBEAT_INTERVAL_MS);
|
|
799
|
-
const onTimeout = () => {
|
|
808
|
+
const onTimeout = (kind) => {
|
|
800
809
|
this.commandTimer = null;
|
|
801
810
|
this.pendingCommand = null;
|
|
802
811
|
if (heartbeatTimer) {
|
|
803
812
|
clearInterval(heartbeatTimer);
|
|
804
813
|
heartbeatTimer = null;
|
|
805
814
|
}
|
|
815
|
+
if (wallClockTimer) {
|
|
816
|
+
clearTimeout(wallClockTimer);
|
|
817
|
+
wallClockTimer = null;
|
|
818
|
+
}
|
|
806
819
|
// Kill the connection — a timed-out connection has stale data in the pipe.
|
|
807
820
|
// Mark disconnected so ensureConnected() reconnects on the next call —
|
|
808
821
|
// transport.close() may or may not fire onClose synchronously.
|
|
809
822
|
this._connected = false;
|
|
810
823
|
this.transport.close?.();
|
|
811
|
-
reject(new Error(
|
|
824
|
+
reject(new Error(`${kind}: ${cmdSummary}${transportDiag()}`));
|
|
812
825
|
};
|
|
813
|
-
|
|
826
|
+
// Two timers, two responsibilities:
|
|
827
|
+
// commandTimer = "no bytes for N seconds" — handleData resets it
|
|
828
|
+
// on every chunk so a steadily-streaming FETCH
|
|
829
|
+
// doesn't get killed mid-flight.
|
|
830
|
+
// wallClockTimer = "this command has been pending too long
|
|
831
|
+
// total" — fires regardless of trickling bytes.
|
|
832
|
+
// Catches the pathological case where a server
|
|
833
|
+
// drips one byte every <inactivityTimeout> seconds
|
|
834
|
+
// for hours (real bobma bug we hit overnight:
|
|
835
|
+
// 3 connections wedged 2-3 hours each because
|
|
836
|
+
// the inactivity reset kept deferring the only
|
|
837
|
+
// timer in play).
|
|
838
|
+
this.commandTimer = setTimeout(() => onTimeout(`IMAP inactivity timeout (${this.inactivityTimeout / 1000}s)`), this.inactivityTimeout);
|
|
839
|
+
const COMMAND_WALL_CLOCK_TIMEOUT_MS = this.commandWallClockTimeout;
|
|
840
|
+
let wallClockTimer = setTimeout(() => onTimeout(`IMAP command wall-clock timeout (${COMMAND_WALL_CLOCK_TIMEOUT_MS / 1000}s)`), COMMAND_WALL_CLOCK_TIMEOUT_MS);
|
|
814
841
|
const clearTimers = () => {
|
|
815
842
|
if (this.commandTimer) {
|
|
816
843
|
clearTimeout(this.commandTimer);
|
|
@@ -820,6 +847,10 @@ export class NativeImapClient {
|
|
|
820
847
|
clearInterval(heartbeatTimer);
|
|
821
848
|
heartbeatTimer = null;
|
|
822
849
|
}
|
|
850
|
+
if (wallClockTimer) {
|
|
851
|
+
clearTimeout(wallClockTimer);
|
|
852
|
+
wallClockTimer = null;
|
|
853
|
+
}
|
|
823
854
|
};
|
|
824
855
|
this.pendingCommand = {
|
|
825
856
|
tag, responses: [],
|
package/package.json
CHANGED
package/types.d.ts
CHANGED