@bobfrankston/iflow-direct 0.1.50 → 0.1.52
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.js +41 -3
- package/imap-protocol.d.ts +1 -1
- package/imap-protocol.js +10 -2
- package/package.json +1 -1
package/imap-native.js
CHANGED
|
@@ -132,8 +132,29 @@ export class NativeImapClient {
|
|
|
132
132
|
}
|
|
133
133
|
});
|
|
134
134
|
this.transport.onError((err) => {
|
|
135
|
+
// Diagnose transport-level errors fully. Node emits socket errors
|
|
136
|
+
// with a populated `.message` in normal cases (ECONNRESET, ETIMEDOUT,
|
|
137
|
+
// etc.) — but TLS-layer errors, abrupt FINs surfaced as errors,
|
|
138
|
+
// and some wrapper paths produce an Error with empty `.message`
|
|
139
|
+
// and the useful info on `.code` / `.errno` / `.syscall` instead.
|
|
140
|
+
// Logging only `.message` left "Transport error: " in the log
|
|
141
|
+
// with no diagnostic content, which masked why bobma INBOX prefetch
|
|
142
|
+
// kept dying (2026-05-27). Build a richer description.
|
|
143
|
+
const errAny = err;
|
|
144
|
+
const parts = [];
|
|
145
|
+
if (errAny?.message)
|
|
146
|
+
parts.push(String(errAny.message));
|
|
147
|
+
if (errAny?.code)
|
|
148
|
+
parts.push(`code=${errAny.code}`);
|
|
149
|
+
if (errAny?.errno !== undefined)
|
|
150
|
+
parts.push(`errno=${errAny.errno}`);
|
|
151
|
+
if (errAny?.syscall)
|
|
152
|
+
parts.push(`syscall=${errAny.syscall}`);
|
|
153
|
+
const desc = parts.length > 0
|
|
154
|
+
? parts.join(" ")
|
|
155
|
+
: `<no message> ${typeof err} ${err?.constructor?.name || ""}`.trim();
|
|
135
156
|
if (this.verbose)
|
|
136
|
-
console.error(` [imap] Transport error: ${
|
|
157
|
+
console.error(` [imap] Transport error: ${desc}`);
|
|
137
158
|
// Transport errors (DNS failure, ECONNRESET, TLS failure, etc.) mean
|
|
138
159
|
// the connection is dead — clear the flag so ensureConnected() will
|
|
139
160
|
// reconnect on the next call, and drop the stale IDLE state so we
|
|
@@ -149,7 +170,17 @@ export class NativeImapClient {
|
|
|
149
170
|
if (this.pendingCommand) {
|
|
150
171
|
const { reject } = this.pendingCommand;
|
|
151
172
|
this.pendingCommand = null;
|
|
152
|
-
|
|
173
|
+
// Make sure the error that propagates to upper-layer catches
|
|
174
|
+
// (prefetch, sync, etc.) has a non-empty message — wrap if
|
|
175
|
+
// the underlying err has a blank message.
|
|
176
|
+
if (err instanceof Error && !err.message) {
|
|
177
|
+
const wrapped = new Error(desc);
|
|
178
|
+
wrapped.cause = err;
|
|
179
|
+
reject(wrapped);
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
reject(err);
|
|
183
|
+
}
|
|
153
184
|
}
|
|
154
185
|
});
|
|
155
186
|
await this.transport.connect(this.config.server, this.config.port, useTls, this.config.server);
|
|
@@ -325,8 +356,15 @@ export class NativeImapClient {
|
|
|
325
356
|
// is the QRESYNC case; without it, the message just vanished
|
|
326
357
|
// mid-session (post-EXPUNGE on another client).
|
|
327
358
|
const text = r.text.replace(/^\(EARLIER\)\s*/i, "").trim();
|
|
328
|
-
|
|
359
|
+
// Cap expansion (see parseUidSet): a stale-modseq VANISHED range
|
|
360
|
+
// can be millions of UIDs. Stop at 100k — the caller's bounded
|
|
361
|
+
// reconcile takes over for an over-cap set rather than trusting
|
|
362
|
+
// it (Bob 2026-06-04). 100k > any real single-cycle vanish.
|
|
363
|
+
const VANISHED_EXPAND_CAP = 100_000;
|
|
364
|
+
for (const uid of proto.parseUidSet(text, VANISHED_EXPAND_CAP))
|
|
329
365
|
vanishedUids.push(uid);
|
|
366
|
+
if (vanishedUids.length >= VANISHED_EXPAND_CAP)
|
|
367
|
+
break;
|
|
330
368
|
}
|
|
331
369
|
}
|
|
332
370
|
this.selectedMailbox = mailbox;
|
package/imap-protocol.d.ts
CHANGED
|
@@ -90,7 +90,7 @@ export declare function enableCommand(tag: string, extensions: string[]): string
|
|
|
90
90
|
* when it has one; here `*` is treated as a sentinel and skipped so the
|
|
91
91
|
* call site can decide what to do (typically: ignore — VANISHED never
|
|
92
92
|
* emits `*` because that would be open-ended). */
|
|
93
|
-
export declare function parseUidSet(set: string): number[];
|
|
93
|
+
export declare function parseUidSet(set: string, maxExpand?: number): number[];
|
|
94
94
|
/** Build EXAMINE command (read-only SELECT) */
|
|
95
95
|
export declare function examineCommand(tag: string, mailbox: string): string;
|
|
96
96
|
/** Build STATUS command */
|
package/imap-protocol.js
CHANGED
|
@@ -56,9 +56,17 @@ export function enableCommand(tag, extensions) {
|
|
|
56
56
|
* when it has one; here `*` is treated as a sentinel and skipped so the
|
|
57
57
|
* call site can decide what to do (typically: ignore — VANISHED never
|
|
58
58
|
* emits `*` because that would be open-ended). */
|
|
59
|
-
export function parseUidSet(set) {
|
|
59
|
+
export function parseUidSet(set, maxExpand = Infinity) {
|
|
60
|
+
// maxExpand caps the expanded output. A VANISHED *range* like
|
|
61
|
+
// `(EARLIER) 1:4828883` (sent when the client's modseq is very stale)
|
|
62
|
+
// would otherwise expand to MILLIONS of integers — burning CPU/memory
|
|
63
|
+
// here and wedging the consumer downstream. The caller passes a cap and
|
|
64
|
+
// treats an at-cap result as "too stale, reconcile some other way"
|
|
65
|
+
// (Bob 2026-06-04). Default Infinity keeps every existing caller unchanged.
|
|
60
66
|
const out = [];
|
|
61
67
|
for (const part of set.split(",")) {
|
|
68
|
+
if (out.length >= maxExpand)
|
|
69
|
+
break;
|
|
62
70
|
const trimmed = part.trim();
|
|
63
71
|
if (!trimmed)
|
|
64
72
|
continue;
|
|
@@ -73,7 +81,7 @@ export function parseUidSet(set) {
|
|
|
73
81
|
const hi = range[1] === "*" ? lo : parseInt(range[1], 10);
|
|
74
82
|
if (!Number.isFinite(lo) || !Number.isFinite(hi) || hi < lo)
|
|
75
83
|
continue;
|
|
76
|
-
for (let u = lo; u <= hi; u++)
|
|
84
|
+
for (let u = lo; u <= hi && out.length < maxExpand; u++)
|
|
77
85
|
out.push(u);
|
|
78
86
|
}
|
|
79
87
|
}
|