@bobfrankston/iflow-direct 0.1.8 → 0.1.10

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/gmail.d.ts CHANGED
@@ -10,6 +10,8 @@ export interface GmailOAuthConfig {
10
10
  verbose?: boolean;
11
11
  rejectUnauthorized?: boolean;
12
12
  inactivityTimeout?: number;
13
+ fetchChunkSize?: number;
14
+ fetchChunkSizeMax?: number;
13
15
  }
14
16
  /**
15
17
  * Check if email address is Gmail
@@ -37,5 +39,7 @@ export declare function createAutoImapConfig(config: {
37
39
  verbose?: boolean;
38
40
  rejectUnauthorized?: boolean;
39
41
  inactivityTimeout?: number;
42
+ fetchChunkSize?: number;
43
+ fetchChunkSizeMax?: number;
40
44
  }): ImapClientConfig;
41
45
  //# sourceMappingURL=gmail.d.ts.map
package/gmail.js CHANGED
@@ -34,6 +34,8 @@ export function createGmailConfig(config) {
34
34
  verbose: config.verbose,
35
35
  rejectUnauthorized: config.rejectUnauthorized,
36
36
  inactivityTimeout: config.inactivityTimeout,
37
+ fetchChunkSize: config.fetchChunkSize,
38
+ fetchChunkSizeMax: config.fetchChunkSizeMax,
37
39
  };
38
40
  }
39
41
  /**
@@ -52,6 +54,8 @@ export function createAutoImapConfig(config) {
52
54
  verbose: config.verbose,
53
55
  rejectUnauthorized: config.rejectUnauthorized,
54
56
  inactivityTimeout: config.inactivityTimeout,
57
+ fetchChunkSize: config.fetchChunkSize,
58
+ fetchChunkSizeMax: config.fetchChunkSizeMax,
55
59
  });
56
60
  }
57
61
  else {
@@ -63,6 +67,8 @@ export function createAutoImapConfig(config) {
63
67
  verbose: config.verbose,
64
68
  rejectUnauthorized: config.rejectUnauthorized,
65
69
  inactivityTimeout: config.inactivityTimeout,
70
+ fetchChunkSize: config.fetchChunkSize,
71
+ fetchChunkSizeMax: config.fetchChunkSizeMax,
66
72
  };
67
73
  }
68
74
  }
package/imap-compat.js CHANGED
@@ -73,44 +73,51 @@ export class CompatImapClient {
73
73
  }
74
74
  /** Detect special folders from folder list */
75
75
  getSpecialFolders(folders) {
76
- // Match IMAP special-use flags (RFC 6154) first, then fall back to exact
77
- // LEAF NAME match. Do NOT use substring matches on the full path —
78
- // "Drafts.Older" used to get tagged as the Drafts folder because of a
79
- // lower.includes("draft") test, which made it impossible to rename or
80
- // delete the subfolder.
76
+ // Two-pass detection so RFC 6154 \Drafts / \Sent / \Trash / \Junk /
77
+ // \Archive flags always win over name-based guesses. Previous single-pass
78
+ // `else if (flag || name)` could tag a stray folder named "DRAFT" as the
79
+ // drafts folder on Gmail, beating out [Imap]/Drafts which has the real
80
+ // \Drafts flag — Gmail then rejects APPEND to "DRAFT" as NONEXISTENT.
81
81
  const result = {};
82
82
  const leafName = (f) => {
83
83
  const delim = f.delimiter || ".";
84
84
  return (f.path.split(delim).pop() || f.path).toLowerCase();
85
85
  };
86
+ const flagsLower = (f) => f.flags.map(fl => fl.toLowerCase());
87
+ // Pass 1: RFC 6154 flags only — authoritative if present
86
88
  for (const f of folders) {
87
- const name = leafName(f);
88
- const flags = f.flags.map(fl => fl.toLowerCase());
89
- if (flags.includes("\\inbox") || name === "inbox") {
90
- if (!result.inbox)
91
- result.inbox = f.path;
92
- }
93
- else if (flags.includes("\\sent") || name === "sent" || name === "sent items" || name === "sent mail") {
94
- if (!result.sent)
95
- result.sent = f.path;
96
- }
97
- else if (flags.includes("\\trash") || name === "trash" || name === "deleted items" || name === "deleted") {
98
- if (!result.trash)
99
- result.trash = f.path;
100
- }
101
- else if (flags.includes("\\drafts") || name === "drafts" || name === "draft") {
102
- if (!result.drafts)
103
- result.drafts = f.path;
104
- }
105
- else if (flags.includes("\\junk") || flags.includes("\\spam") || name === "spam" || name === "junk" || name === "junk email" || name === "junk e-mail") {
106
- if (!result.junk)
107
- result.junk = f.path;
89
+ const flags = flagsLower(f);
90
+ if (!result.inbox && (flags.includes("\\inbox") || leafName(f) === "inbox"))
91
+ result.inbox = f.path;
92
+ if (!result.sent && flags.includes("\\sent"))
93
+ result.sent = f.path;
94
+ if (!result.trash && flags.includes("\\trash"))
95
+ result.trash = f.path;
96
+ if (!result.drafts && flags.includes("\\drafts"))
97
+ result.drafts = f.path;
98
+ if (!result.archive && flags.includes("\\archive"))
99
+ result.archive = f.path;
100
+ if (!result.junk && (flags.includes("\\junk") || flags.includes("\\spam"))) {
101
+ result.junk = f.path;
108
102
  if (!result.spam)
109
103
  result.spam = f.path;
110
104
  }
111
- else if (flags.includes("\\archive") || name === "archive" || name === "archives") {
112
- if (!result.archive)
113
- result.archive = f.path;
105
+ }
106
+ // Pass 2: exact leaf-name fallback for servers that don't advertise flags
107
+ for (const f of folders) {
108
+ const name = leafName(f);
109
+ if (!result.sent && (name === "sent" || name === "sent items" || name === "sent mail"))
110
+ result.sent = f.path;
111
+ if (!result.trash && (name === "trash" || name === "deleted items" || name === "deleted"))
112
+ result.trash = f.path;
113
+ if (!result.drafts && (name === "drafts" || name === "draft"))
114
+ result.drafts = f.path;
115
+ if (!result.archive && (name === "archive" || name === "archives"))
116
+ result.archive = f.path;
117
+ if (!result.junk && (name === "spam" || name === "junk" || name === "junk email" || name === "junk e-mail")) {
118
+ result.junk = f.path;
119
+ if (!result.spam)
120
+ result.spam = f.path;
114
121
  }
115
122
  }
116
123
  return result;
package/imap-native.d.ts CHANGED
@@ -121,9 +121,11 @@ export declare class NativeImapClient {
121
121
  * 60s accommodates Gmail which is slow on SEARCH for large folders.
122
122
  * Overridable via ImapClientConfig.inactivityTimeout — slow Dovecot servers need 180s+. */
123
123
  private inactivityTimeout;
124
- /** Fetch chunk sizes — start small for quick first paint, ramp up for throughput */
125
- private static INITIAL_CHUNK_SIZE;
126
- private static MAX_CHUNK_SIZE;
124
+ /** Fetch chunk sizes — start small for quick first paint, ramp up for throughput.
125
+ * Default 25 initial → 500 max. Overridable via ImapClientConfig.fetchChunkSize /
126
+ * fetchChunkSizeMax. Slow servers benefit from smaller chunks (fewer timeouts). */
127
+ private fetchChunkSize;
128
+ private fetchChunkSizeMax;
127
129
  /** Active command timer — reset by handleData on every data arrival */
128
130
  private commandTimer;
129
131
  private sendCommand;
package/imap-native.js CHANGED
@@ -29,6 +29,8 @@ export class NativeImapClient {
29
29
  this.transport = transportFactory();
30
30
  this.verbose = config.verbose || false;
31
31
  this.inactivityTimeout = config.inactivityTimeout ?? 60000;
32
+ this.fetchChunkSize = config.fetchChunkSize ?? 25;
33
+ this.fetchChunkSizeMax = config.fetchChunkSizeMax ?? 500;
32
34
  }
33
35
  get connected() { return this._connected; }
34
36
  // ── Connection ──
@@ -296,14 +298,14 @@ export class NativeImapClient {
296
298
  return [];
297
299
  uids.reverse(); // Newest first
298
300
  console.log(` [fetch] ${uids.length} UIDs since ${sinceUid} (newest first)`);
299
- if (uids.length <= NativeImapClient.INITIAL_CHUNK_SIZE) {
301
+ if (uids.length <= this.fetchChunkSize) {
300
302
  const msgs = await this.fetchMessages(uids.join(","), options);
301
303
  if (onChunk)
302
304
  onChunk(msgs);
303
305
  return msgs;
304
306
  }
305
307
  const allMessages = [];
306
- let chunkSize = NativeImapClient.INITIAL_CHUNK_SIZE;
308
+ let chunkSize = this.fetchChunkSize;
307
309
  for (let i = 0; i < uids.length; i += chunkSize) {
308
310
  const chunk = uids.slice(i, i + chunkSize);
309
311
  const msgs = await this.fetchMessages(chunk.join(","), options);
@@ -311,8 +313,8 @@ export class NativeImapClient {
311
313
  console.log(` [fetch] ${allMessages.length}/${uids.length} (chunk of ${chunk.length})`);
312
314
  if (onChunk)
313
315
  onChunk(msgs);
314
- if (chunkSize < NativeImapClient.MAX_CHUNK_SIZE)
315
- chunkSize = Math.min(chunkSize * 4, NativeImapClient.MAX_CHUNK_SIZE);
316
+ if (chunkSize < this.fetchChunkSizeMax)
317
+ chunkSize = Math.min(chunkSize * 4, this.fetchChunkSizeMax);
316
318
  }
317
319
  return allMessages;
318
320
  }
@@ -329,7 +331,7 @@ export class NativeImapClient {
329
331
  uids.reverse();
330
332
  console.log(` [fetch] ${uids.length} UIDs to fetch (newest first)`);
331
333
  const allMessages = [];
332
- let chunkSize = NativeImapClient.INITIAL_CHUNK_SIZE;
334
+ let chunkSize = this.fetchChunkSize;
333
335
  for (let i = 0; i < uids.length; i += chunkSize) {
334
336
  const chunk = uids.slice(i, i + chunkSize);
335
337
  const msgs = await this.fetchMessages(chunk.join(","), options);
@@ -337,8 +339,8 @@ export class NativeImapClient {
337
339
  console.log(` [fetch] ${allMessages.length}/${uids.length} (chunk of ${chunk.length})`);
338
340
  if (onChunk)
339
341
  onChunk(msgs);
340
- if (chunkSize < NativeImapClient.MAX_CHUNK_SIZE)
341
- chunkSize = Math.min(chunkSize * 4, NativeImapClient.MAX_CHUNK_SIZE);
342
+ if (chunkSize < this.fetchChunkSizeMax)
343
+ chunkSize = Math.min(chunkSize * 4, this.fetchChunkSizeMax);
342
344
  }
343
345
  return allMessages;
344
346
  }
@@ -461,9 +463,11 @@ export class NativeImapClient {
461
463
  * 60s accommodates Gmail which is slow on SEARCH for large folders.
462
464
  * Overridable via ImapClientConfig.inactivityTimeout — slow Dovecot servers need 180s+. */
463
465
  inactivityTimeout;
464
- /** Fetch chunk sizes — start small for quick first paint, ramp up for throughput */
465
- static INITIAL_CHUNK_SIZE = 25;
466
- static MAX_CHUNK_SIZE = 500;
466
+ /** Fetch chunk sizes — start small for quick first paint, ramp up for throughput.
467
+ * Default 25 initial → 500 max. Overridable via ImapClientConfig.fetchChunkSize /
468
+ * fetchChunkSizeMax. Slow servers benefit from smaller chunks (fewer timeouts). */
469
+ fetchChunkSize;
470
+ fetchChunkSizeMax;
467
471
  /** Active command timer — reset by handleData on every data arrival */
468
472
  commandTimer = null;
469
473
  sendCommand(tag, command) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bobfrankston/iflow-direct",
3
- "version": "0.1.8",
3
+ "version": "0.1.10",
4
4
  "description": "Direct IMAP client — transport-agnostic, no Node.js dependencies, browser-ready",
5
5
  "main": "index.js",
6
6
  "types": "index.ts",
package/types.d.ts CHANGED
@@ -11,5 +11,7 @@ export interface ImapClientConfig {
11
11
  verbose?: boolean;
12
12
  rejectUnauthorized?: boolean;
13
13
  inactivityTimeout?: number;
14
+ fetchChunkSize?: number;
15
+ fetchChunkSizeMax?: number;
14
16
  }
15
17
  //# sourceMappingURL=types.d.ts.map