@bobfrankston/iflow 1.0.31 → 1.0.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.
@@ -3,6 +3,19 @@
3
3
  import { ImapFlow } from 'imapflow';
4
4
  import { FetchedMessage } from './types.js';
5
5
  import { styleText } from 'util';
6
+ // Removed dependencies on parent project - these should be passed in or handled differently
7
+ // TODO: Create our own range object and allow a nosource flag
8
+ /** Extract full error detail from imapflow errors (which hide response text in err.responseText) */
9
+ function imapError(err) {
10
+ const parts = [err.message || "Unknown error"];
11
+ if (err.responseText)
12
+ parts.push(err.responseText);
13
+ if (err.responseStatus)
14
+ parts.push(`[${err.responseStatus}]`);
15
+ if (err.executedCommand)
16
+ parts.push(`cmd: ${err.executedCommand.substring(0, 80)}`);
17
+ return parts.join(" — ");
18
+ }
6
19
  const defaultFetchOptions = {
7
20
  source: true
8
21
  };
@@ -34,7 +47,7 @@ export class ImapClient {
34
47
  });
35
48
  // Set up error handlers
36
49
  this.client.on('error', (err) => {
37
- console.error(`${new Date().toISOString()} ImapFlow socket error: ${err.message}`);
50
+ console.error(`${new Date().toISOString()} ImapFlow socket error: ${imapError(err)}`);
38
51
  if (!this.isDestroying) {
39
52
  this.handleReconnection();
40
53
  }
@@ -79,12 +92,12 @@ export class ImapClient {
79
92
  this.reconnectAttempts = 0; // Reset on success
80
93
  }
81
94
  catch (err) {
82
- console.error(`${new Date().toISOString()} Reconnection failed: ${err.message}`);
95
+ console.error(`${new Date().toISOString()} Reconnection failed: ${imapError(err)}`);
83
96
  // Will trigger another reconnection attempt via error handler
84
97
  }
85
98
  }
86
99
  catch (err) {
87
- console.error(`${new Date().toISOString()} Error during reconnection process: ${err.message}`);
100
+ console.error(`${new Date().toISOString()} Error during reconnection process: ${imapError(err)}`);
88
101
  }
89
102
  finally {
90
103
  this.connectionPromise = null;
@@ -106,7 +119,7 @@ export class ImapClient {
106
119
  return await operation();
107
120
  }
108
121
  catch (err) {
109
- console.error(`${new Date().toISOString()} Operation failed: ${err.message}`);
122
+ console.error(`${new Date().toISOString()} Operation failed: ${imapError(err)}`);
110
123
  // Check if it's a connection-related error
111
124
  if (err.code === 'ECONNRESET' || err.code === 'ENOTFOUND' ||
112
125
  err.code === 'ETIMEDOUT' || err.code === 'ECONNREFUSED' ||
@@ -147,7 +160,7 @@ export class ImapClient {
147
160
  return uids;
148
161
  }
149
162
  catch (error) {
150
- console.error(`Error getting UIDs: ${error.message}`);
163
+ console.error(`Error getting UIDs: ${imapError(error)}`);
151
164
  throw error;
152
165
  }
153
166
  finally {
@@ -180,7 +193,7 @@ export class ImapClient {
180
193
  return uids;
181
194
  }
182
195
  catch (error) {
183
- console.error(`Search error in ${mailbox}: ${error.message}`);
196
+ console.error(`Search error in ${mailbox}: ${imapError(error)}`);
184
197
  throw error;
185
198
  }
186
199
  finally {
@@ -248,7 +261,7 @@ export class ImapClient {
248
261
  return messages;
249
262
  }
250
263
  catch (error) {
251
- console.error(`Error fetching messages: ${error.message}`);
264
+ console.error(`Error fetching messages: ${imapError(error)}`);
252
265
  debugger;
253
266
  throw error; // rethrow to handle it outside
254
267
  }
@@ -279,7 +292,7 @@ export class ImapClient {
279
292
  // "Nothing to fetch" just means no new messages
280
293
  if (error.responseText?.includes("Nothing to fetch"))
281
294
  return [];
282
- console.error(`Error fetching messages since UID ${sinceUid}: ${error.message}`);
295
+ console.error(`Error fetching messages since UID ${sinceUid}: ${imapError(error)}`);
283
296
  throw error;
284
297
  }
285
298
  finally {
@@ -305,7 +318,7 @@ export class ImapClient {
305
318
  return new FetchedMessage(msg);
306
319
  }
307
320
  catch (error) {
308
- console.error(`Error fetching message UID ${uid}: ${error.message}`);
321
+ console.error(`Error fetching message UID ${uid}: ${imapError(error)}`);
309
322
  throw error;
310
323
  }
311
324
  finally {
@@ -351,7 +364,7 @@ export class ImapClient {
351
364
  return result;
352
365
  }
353
366
  catch (error) {
354
- console.error(`Error appending message to ${mailbox}: ${error.message}`);
367
+ console.error(`Error appending message to ${mailbox}: ${imapError(error)}`);
355
368
  throw error;
356
369
  }
357
370
  }
@@ -384,7 +397,7 @@ export class ImapClient {
384
397
  await targetClient.appendMessage(targetMailbox, msg.source, flags, date);
385
398
  }
386
399
  catch (error) {
387
- console.error(`Error copying message to another server: ${error.message}`);
400
+ console.error(`Error copying message to another server: ${imapError(error)}`);
388
401
  throw error;
389
402
  }
390
403
  }
@@ -406,7 +419,7 @@ export class ImapClient {
406
419
  await this.client.messageDelete([msg.uid], { uid: true });
407
420
  }
408
421
  catch (error) {
409
- console.error(`Error moving message to another server: ${error.message}`);
422
+ console.error(`Error moving message to another server: ${imapError(error)}`);
410
423
  throw error;
411
424
  }
412
425
  finally {
@@ -470,7 +483,7 @@ export class ImapClient {
470
483
  return specialFolders;
471
484
  }
472
485
  catch (error) {
473
- console.error(`Error getting special folders: ${error.message}`);
486
+ console.error(`Error getting special folders: ${imapError(error)}`);
474
487
  debugger;
475
488
  throw error;
476
489
  }
@@ -493,7 +506,7 @@ export class ImapClient {
493
506
  return await this.client.messageFlagsAdd([uid], flags, { uid: true });
494
507
  }
495
508
  catch (error) {
496
- console.error(`Error adding flags to UID ${uid}: ${error.message}`);
509
+ console.error(`Error adding flags to UID ${uid}: ${imapError(error)}`);
497
510
  throw error;
498
511
  }
499
512
  finally {
@@ -508,7 +521,7 @@ export class ImapClient {
508
521
  return await this.client.messageFlagsRemove([uid], flags, { uid: true });
509
522
  }
510
523
  catch (error) {
511
- console.error(`Error removing flags from UID ${uid}: ${error.message}`);
524
+ console.error(`Error removing flags from UID ${uid}: ${imapError(error)}`);
512
525
  throw error;
513
526
  }
514
527
  finally {
@@ -526,7 +539,7 @@ export class ImapClient {
526
539
  return [...msg.flags];
527
540
  }
528
541
  catch (error) {
529
- console.error(`Error getting flags for UID ${uid}: ${error.message}`);
542
+ console.error(`Error getting flags for UID ${uid}: ${imapError(error)}`);
530
543
  throw error;
531
544
  }
532
545
  finally {
@@ -541,7 +554,7 @@ export class ImapClient {
541
554
  await this.client.messageDelete([uid], { uid: true });
542
555
  }
543
556
  catch (error) {
544
- console.error(`Error deleting UID ${uid} from ${mailbox}: ${error.message}`);
557
+ console.error(`Error deleting UID ${uid} from ${mailbox}: ${imapError(error)}`);
545
558
  throw error;
546
559
  }
547
560
  finally {
package/imaplib/gmail.js CHANGED
@@ -48,10 +48,11 @@ export function createImapConfig(config) {
48
48
  const tokenDir = path.join(tokenDirectory, 'tokens', accountDir);
49
49
  const getToken = async () => {
50
50
  // Serialize concurrent OAuth attempts — only one flow at a time per user
51
- const existing = pendingAuth.get(username);
52
- if (existing)
53
- return existing;
54
- const attempt = (async () => {
51
+ // Check-and-set must be synchronous to avoid TOCTOU race
52
+ let pending = pendingAuth.get(username);
53
+ if (pending)
54
+ return pending;
55
+ pending = (async () => {
55
56
  const token = await authenticateOAuth(credentialsPath, {
56
57
  scope: GMAIL_SCOPE,
57
58
  tokenDirectory: tokenDir,
@@ -64,9 +65,10 @@ export function createImapConfig(config) {
64
65
  throw new Error('Failed to get Gmail access token');
65
66
  return token.access_token;
66
67
  })();
67
- pendingAuth.set(username, attempt);
68
+ // Set immediately (synchronously) before any await
69
+ pendingAuth.set(username, pending);
68
70
  try {
69
- return await attempt;
71
+ return await pending;
70
72
  }
71
73
  finally {
72
74
  pendingAuth.delete(username);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bobfrankston/iflow",
3
- "version": "1.0.31",
3
+ "version": "1.0.33",
4
4
  "description": "IMAP client wrapper library",
5
5
  "main": "index.js",
6
6
  "types": "index.ts",
@@ -23,7 +23,7 @@
23
23
  "author": "",
24
24
  "license": "ISC",
25
25
  "dependencies": {
26
- "@bobfrankston/oauthsupport": "^1.0.14",
26
+ "@bobfrankston/oauthsupport": "^1.0.17",
27
27
  "imapflow": "^1.0.187"
28
28
  },
29
29
  "exports": {