@bobfrankston/iflow-direct 0.1.69 → 0.1.72
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-compat.d.ts +3 -0
- package/imap-compat.js +14 -0
- package/imap-native.d.ts +8 -0
- package/imap-native.js +20 -0
- package/imap-protocol.d.ts +6 -1
- package/imap-protocol.js +16 -0
- package/package.json +1 -1
package/imap-compat.d.ts
CHANGED
|
@@ -105,6 +105,9 @@ export declare class CompatImapClient {
|
|
|
105
105
|
searchByHeader(mailbox: string, headerName: string, headerValue: string): Promise<number[]>;
|
|
106
106
|
/** Delete a message by UID */
|
|
107
107
|
deleteMessageByUid(mailbox: string, uid: number): Promise<void>;
|
|
108
|
+
/** Delete many messages by UID in one mailbox — chunked STORE + one
|
|
109
|
+
* EXPUNGE (see ImapNative.deleteMessages). 2026-09-16 Claude Code. */
|
|
110
|
+
deleteMessagesByUid(mailbox: string, uids: number[]): Promise<void>;
|
|
108
111
|
/** Move a message between mailboxes (same server) */
|
|
109
112
|
moveMessage(msg: any, fromMailbox: string, toMailbox: string): Promise<void>;
|
|
110
113
|
/** Add flags to a message */
|
package/imap-compat.js
CHANGED
|
@@ -239,6 +239,20 @@ export class CompatImapClient {
|
|
|
239
239
|
await this.native.deleteMessage(uid);
|
|
240
240
|
await this.native.closeMailbox();
|
|
241
241
|
}
|
|
242
|
+
/** Delete many messages by UID in one mailbox — chunked STORE + one
|
|
243
|
+
* EXPUNGE (see ImapNative.deleteMessages). 2026-09-16 Claude Code. */
|
|
244
|
+
async deleteMessagesByUid(mailbox, uids) {
|
|
245
|
+
if (!uids.length)
|
|
246
|
+
return;
|
|
247
|
+
await this.ensureConnected();
|
|
248
|
+
await this.native.select(mailbox);
|
|
249
|
+
try {
|
|
250
|
+
await this.native.deleteMessages(uids);
|
|
251
|
+
}
|
|
252
|
+
finally {
|
|
253
|
+
await this.native.closeMailbox();
|
|
254
|
+
}
|
|
255
|
+
}
|
|
242
256
|
/** Move a message between mailboxes (same server) */
|
|
243
257
|
async moveMessage(msg, fromMailbox, toMailbox) {
|
|
244
258
|
await this.ensureConnected();
|
package/imap-native.d.ts
CHANGED
|
@@ -273,6 +273,14 @@ export declare class NativeImapClient {
|
|
|
273
273
|
moveMessage(uid: number, destination: string): Promise<void>;
|
|
274
274
|
/** Delete a message by UID (flag + expunge) */
|
|
275
275
|
deleteMessage(uid: number): Promise<void>;
|
|
276
|
+
/** Delete many messages in the selected mailbox: one `UID STORE <set>
|
|
277
|
+
* +FLAGS.SILENT (\Deleted)` per chunk, then a single EXPUNGE.
|
|
278
|
+
* 2026-09-16 — Claude Code (Fable 5.1), at Bob's direction. Emptying
|
|
279
|
+
* Trash looped deleteMessage() per UID — a STORE and an EXPUNGE round
|
|
280
|
+
* trip for every message — so a large Trash took minutes and the
|
|
281
|
+
* caller's IPC timed out ("mailxapi timeout: emptyFolder"). Chunked so a
|
|
282
|
+
* ten-thousand-UID set never produces a command line the server rejects. */
|
|
283
|
+
deleteMessages(uids: number[], chunkSize?: number): Promise<void>;
|
|
276
284
|
/** Expunge deleted messages */
|
|
277
285
|
expunge(): Promise<void>;
|
|
278
286
|
/** Append a message to a mailbox */
|
package/imap-native.js
CHANGED
|
@@ -828,6 +828,26 @@ export class NativeImapClient {
|
|
|
828
828
|
await this.addFlags(uid, ["\\Deleted"]);
|
|
829
829
|
await this.expunge();
|
|
830
830
|
}
|
|
831
|
+
/** Delete many messages in the selected mailbox: one `UID STORE <set>
|
|
832
|
+
* +FLAGS.SILENT (\Deleted)` per chunk, then a single EXPUNGE.
|
|
833
|
+
* 2026-09-16 — Claude Code (Fable 5.1), at Bob's direction. Emptying
|
|
834
|
+
* Trash looped deleteMessage() per UID — a STORE and an EXPUNGE round
|
|
835
|
+
* trip for every message — so a large Trash took minutes and the
|
|
836
|
+
* caller's IPC timed out ("mailxapi timeout: emptyFolder"). Chunked so a
|
|
837
|
+
* ten-thousand-UID set never produces a command line the server rejects. */
|
|
838
|
+
async deleteMessages(uids, chunkSize = 1000) {
|
|
839
|
+
if (!uids.length)
|
|
840
|
+
return;
|
|
841
|
+
for (let i = 0; i < uids.length; i += chunkSize) {
|
|
842
|
+
const set = proto.uidSequenceSet(uids.slice(i, i + chunkSize));
|
|
843
|
+
const tag = proto.nextTag();
|
|
844
|
+
const responses = await this.sendCommand(tag, proto.storeCommand(tag, set, "+FLAGS.SILENT", ["\\Deleted"]));
|
|
845
|
+
const tagged = responses.find(r => r.tag === tag);
|
|
846
|
+
if (!tagged || tagged.type !== "OK")
|
|
847
|
+
throw new Error(`STORE +FLAGS \\Deleted (${uids.length} uids) failed: ${tagged?.text || "unknown"}`);
|
|
848
|
+
}
|
|
849
|
+
await this.expunge();
|
|
850
|
+
}
|
|
831
851
|
/** Expunge deleted messages */
|
|
832
852
|
async expunge() {
|
|
833
853
|
const tag = proto.nextTag();
|
package/imap-protocol.d.ts
CHANGED
|
@@ -107,7 +107,12 @@ export declare function seqFetchCommand(tag: string, range: string, items: strin
|
|
|
107
107
|
/** Build UID SEARCH command */
|
|
108
108
|
export declare function searchCommand(tag: string, criteria: string): string;
|
|
109
109
|
/** Build UID STORE command (set/add/remove flags) */
|
|
110
|
-
|
|
110
|
+
/** `uid` may be a single UID or an RFC 3501 sequence set ("1:500,502") —
|
|
111
|
+
* 2026-09-16 Claude Code (Fable 5.1): needed so one STORE can flag a whole
|
|
112
|
+
* folder for deletion instead of one round trip per message. */
|
|
113
|
+
export declare function storeCommand(tag: string, uid: number | string, action: string, flags: string[]): string;
|
|
114
|
+
/** Compress sorted UIDs into an RFC 3501 sequence set: [1,2,3,7,9,10] → "1:3,7,9:10". */
|
|
115
|
+
export declare function uidSequenceSet(uids: number[]): string;
|
|
111
116
|
/** Build UID COPY command */
|
|
112
117
|
export declare function copyCommand(tag: string, uid: number, destination: string): string;
|
|
113
118
|
/** Build UID MOVE command */
|
package/imap-protocol.js
CHANGED
|
@@ -110,9 +110,25 @@ export function searchCommand(tag, criteria) {
|
|
|
110
110
|
return buildCommand(tag, `UID SEARCH ${criteria}`);
|
|
111
111
|
}
|
|
112
112
|
/** Build UID STORE command (set/add/remove flags) */
|
|
113
|
+
/** `uid` may be a single UID or an RFC 3501 sequence set ("1:500,502") —
|
|
114
|
+
* 2026-09-16 Claude Code (Fable 5.1): needed so one STORE can flag a whole
|
|
115
|
+
* folder for deletion instead of one round trip per message. */
|
|
113
116
|
export function storeCommand(tag, uid, action, flags) {
|
|
114
117
|
return buildCommand(tag, `UID STORE ${uid} ${action} (${flags.join(" ")})`);
|
|
115
118
|
}
|
|
119
|
+
/** Compress sorted UIDs into an RFC 3501 sequence set: [1,2,3,7,9,10] → "1:3,7,9:10". */
|
|
120
|
+
export function uidSequenceSet(uids) {
|
|
121
|
+
const sorted = Array.from(new Set(uids)).sort((a, b) => a - b);
|
|
122
|
+
const parts = [];
|
|
123
|
+
for (let i = 0; i < sorted.length;) {
|
|
124
|
+
let j = i;
|
|
125
|
+
while (j + 1 < sorted.length && sorted[j + 1] === sorted[j] + 1)
|
|
126
|
+
j++;
|
|
127
|
+
parts.push(j > i ? `${sorted[i]}:${sorted[j]}` : String(sorted[i]));
|
|
128
|
+
i = j + 1;
|
|
129
|
+
}
|
|
130
|
+
return parts.join(",");
|
|
131
|
+
}
|
|
116
132
|
/** Build UID COPY command */
|
|
117
133
|
export function copyCommand(tag, uid, destination) {
|
|
118
134
|
return buildCommand(tag, `UID COPY ${uid} ${quoteMailbox(destination)}`);
|