@bobfrankston/mailx-imap 0.1.85 → 0.1.86
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/index.js +34 -8
- package/package.json +11 -11
package/index.js
CHANGED
|
@@ -4193,19 +4193,37 @@ export class ImapManager extends EventEmitter {
|
|
|
4193
4193
|
if (host !== this.hostname)
|
|
4194
4194
|
continue;
|
|
4195
4195
|
const pid = parseInt(pidStr);
|
|
4196
|
-
|
|
4197
|
-
|
|
4196
|
+
let ageMs = Infinity;
|
|
4197
|
+
try {
|
|
4198
|
+
ageMs = Date.now() - fs.statSync(path.join(dir, f)).mtimeMs;
|
|
4199
|
+
}
|
|
4200
|
+
catch { /* */ }
|
|
4201
|
+
if (pid === myPid) {
|
|
4202
|
+
// Our own claim. Normally we're actively sending it — leave
|
|
4203
|
+
// it. But the send is now bounded (60s APPEND timeout), so
|
|
4204
|
+
// an OWN claim older than STALE_CLAIM_MS means the send
|
|
4205
|
+
// hung past its timeout, or a prior tick orphaned it (the
|
|
4206
|
+
// release rename failed). Without reclaiming it the file
|
|
4207
|
+
// sits in `.sending-` forever — recovery used to skip every
|
|
4208
|
+
// own-PID claim unconditionally, so a transient connection
|
|
4209
|
+
// wedge pinned the message even after the link recovered
|
|
4210
|
+
// (Bob 2026-06-11: two messages stuck .sending-<ourpid>
|
|
4211
|
+
// while SELECT Outbox was already succeeding again).
|
|
4212
|
+
if (ageMs < STALE_CLAIM_MS)
|
|
4213
|
+
continue;
|
|
4214
|
+
try {
|
|
4215
|
+
fs.renameSync(path.join(dir, f), path.join(dir, original));
|
|
4216
|
+
console.log(` [outbox] Recovered our own stale claim ${f} → ${original} (hung ${Math.round(ageMs / 60_000)}m)`);
|
|
4217
|
+
}
|
|
4218
|
+
catch { /* ignore */ }
|
|
4219
|
+
continue;
|
|
4220
|
+
}
|
|
4198
4221
|
let alive = false;
|
|
4199
4222
|
try {
|
|
4200
4223
|
process.kill(pid, 0);
|
|
4201
4224
|
alive = true;
|
|
4202
4225
|
}
|
|
4203
4226
|
catch { /* dead */ }
|
|
4204
|
-
let ageMs = Infinity;
|
|
4205
|
-
try {
|
|
4206
|
-
ageMs = Date.now() - fs.statSync(path.join(dir, f)).mtimeMs;
|
|
4207
|
-
}
|
|
4208
|
-
catch { /* */ }
|
|
4209
4227
|
// Live PID + recent mtime → genuine sibling owner, leave it.
|
|
4210
4228
|
// Live PID + ancient mtime → recycled PID, sweep. Dead PID → sweep.
|
|
4211
4229
|
if (alive && ageMs < STALE_CLAIM_MS)
|
|
@@ -4338,7 +4356,15 @@ export class ImapManager extends EventEmitter {
|
|
|
4338
4356
|
}
|
|
4339
4357
|
try {
|
|
4340
4358
|
const raw = fs.readFileSync(claimedPath, "utf-8");
|
|
4341
|
-
|
|
4359
|
+
// Bound the APPEND. On a wedged connection (Dovecot
|
|
4360
|
+
// ETIMEDOUT storm) the bare await can hang the full
|
|
4361
|
+
// 300s inactivity timeout, pinning the file in
|
|
4362
|
+
// `.sending-` state the whole time and reading to the
|
|
4363
|
+
// user as "stuck, not sending" (Bob 2026-06-11). A
|
|
4364
|
+
// 60s cap force-closes the socket and throws, so the
|
|
4365
|
+
// catch below releases the claim and the next tick
|
|
4366
|
+
// retries instead of hanging for 5 minutes.
|
|
4367
|
+
await withTimeout(client.appendMessage(outboxPath, raw, ["\\Seen"]), 60_000, client, `outbox APPEND ${file}`);
|
|
4342
4368
|
fs.renameSync(claimedPath, path.join(sentDir, file));
|
|
4343
4369
|
console.log(` [outbox] Moved ${file} to IMAP Outbox → sent/`);
|
|
4344
4370
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bobfrankston/mailx-imap",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.86",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -12,11 +12,11 @@
|
|
|
12
12
|
"@bobfrankston/mailx-types": "^0.1.18",
|
|
13
13
|
"@bobfrankston/mailx-settings": "^0.1.26",
|
|
14
14
|
"@bobfrankston/mailx-store": "^0.1.45",
|
|
15
|
-
"@bobfrankston/iflow-direct": "^0.1.
|
|
16
|
-
"@bobfrankston/tcp-transport": "^0.1.
|
|
17
|
-
"@bobfrankston/smtp-direct": "^0.1.
|
|
18
|
-
"@bobfrankston/mailx-sync": "^0.1.
|
|
19
|
-
"@bobfrankston/oauthsupport": "^1.0.
|
|
15
|
+
"@bobfrankston/iflow-direct": "^0.1.53",
|
|
16
|
+
"@bobfrankston/tcp-transport": "^0.1.7",
|
|
17
|
+
"@bobfrankston/smtp-direct": "^0.1.9",
|
|
18
|
+
"@bobfrankston/mailx-sync": "^0.1.20",
|
|
19
|
+
"@bobfrankston/oauthsupport": "^1.0.32"
|
|
20
20
|
},
|
|
21
21
|
"repository": {
|
|
22
22
|
"type": "git",
|
|
@@ -40,11 +40,11 @@
|
|
|
40
40
|
"@bobfrankston/mailx-types": "^0.1.18",
|
|
41
41
|
"@bobfrankston/mailx-settings": "^0.1.26",
|
|
42
42
|
"@bobfrankston/mailx-store": "^0.1.45",
|
|
43
|
-
"@bobfrankston/iflow-direct": "^0.1.
|
|
44
|
-
"@bobfrankston/tcp-transport": "^0.1.
|
|
45
|
-
"@bobfrankston/smtp-direct": "^0.1.
|
|
46
|
-
"@bobfrankston/mailx-sync": "^0.1.
|
|
47
|
-
"@bobfrankston/oauthsupport": "^1.0.
|
|
43
|
+
"@bobfrankston/iflow-direct": "^0.1.53",
|
|
44
|
+
"@bobfrankston/tcp-transport": "^0.1.7",
|
|
45
|
+
"@bobfrankston/smtp-direct": "^0.1.9",
|
|
46
|
+
"@bobfrankston/mailx-sync": "^0.1.20",
|
|
47
|
+
"@bobfrankston/oauthsupport": "^1.0.32"
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
}
|