@bobfrankston/mailx 1.0.163 → 1.0.164

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/bin/mailx.js CHANGED
@@ -231,7 +231,7 @@ if (hasFlag("v") || hasFlag("version")) {
231
231
  console.log("mailx (version unknown)");
232
232
  }
233
233
  console.log(` node ${process.version}`);
234
- console.log(` iflow ${ver("@bobfrankston/iflow")}`);
234
+ console.log(` iflow-direct ${ver("@bobfrankston/iflow-direct")}`);
235
235
  console.log(` miscinfo ${ver("@bobfrankston/miscinfo")}`);
236
236
  console.log(` oauth ${ver("@bobfrankston/oauthsupport")}`);
237
237
  console.log(` store ${ver("@bobfrankston/mailx-store")}`);
@@ -500,14 +500,15 @@ async function runTest() {
500
500
  console.log(`Testing ${account.label || account.id} (${account.email}):`);
501
501
  // Test IMAP
502
502
  try {
503
- const { ImapClient, createAutoImapConfig } = await import("@bobfrankston/iflow");
503
+ const { createAutoImapConfig, CompatImapClient } = await import("@bobfrankston/iflow-direct");
504
+ const { NodeTransport } = await import("@bobfrankston/iflow-node");
504
505
  const config = createAutoImapConfig({
505
506
  server: account.imap.host,
506
507
  port: account.imap.port,
507
508
  username: account.imap.user,
508
509
  password: account.imap.password
509
510
  });
510
- const client = new ImapClient(config);
511
+ const client = new CompatImapClient(config, () => new NodeTransport());
511
512
  const folders = await client.getFolderList();
512
513
  await client.logout();
513
514
  console.log(` IMAP: OK (${folders.length} folders)`);
@@ -524,7 +525,7 @@ async function runTest() {
524
525
  }
525
526
  else if (account.smtp.auth === "oauth2") {
526
527
  // Try to get OAuth token
527
- const { createAutoImapConfig } = await import("@bobfrankston/iflow");
528
+ const { createAutoImapConfig } = await import("@bobfrankston/iflow-direct");
528
529
  const config = createAutoImapConfig({
529
530
  server: account.imap.host,
530
531
  port: account.imap.port,
@@ -599,11 +600,10 @@ async function main() {
599
600
  if (setupMode || !hasConfig()) {
600
601
  if (!setupMode)
601
602
  console.log("No mailx configuration found.");
602
- // --email (or -mail) flag skips the interactive prompt
603
- const emailArg = args.find(a => a.startsWith("--email="))?.split("=")[1]
604
- || args.find(a => a.startsWith("-mail="))?.split("=")[1]
605
- || (hasFlag("email") ? args[args.indexOf("--email") + 1] || args[args.indexOf("-email") + 1] : undefined)
606
- || (hasFlag("mail") ? args[args.indexOf("--mail") + 1] || args[args.indexOf("-mail") + 1] : undefined);
603
+ // -email or -mail flag skips the interactive prompt
604
+ const emailFlag = args.findIndex(a => a === "-email" || a === "--email" || a === "-mail" || a === "--mail");
605
+ const emailArg = args.find(a => a.startsWith("-email=") || a.startsWith("--email=") || a.startsWith("-mail=") || a.startsWith("--mail="))?.split("=")[1]
606
+ || (emailFlag >= 0 ? args[emailFlag + 1] : undefined);
607
607
  await runSetup(emailArg);
608
608
  }
609
609
  // Redirect console to log file — keep terminal clean
@@ -646,7 +646,7 @@ async function main() {
646
646
  }
647
647
  const db = new MailxDB(getConfigDir());
648
648
  const imapManager = new ImapManager(db);
649
- imapManager.useNativeClient = true;
649
+ // Native client is the only option (iflow-direct)
650
650
  const svc = new MailxService(db, imapManager);
651
651
  // Open msger in service mode — custom protocol serves files from client dir
652
652
  const clientDir = path.join(import.meta.dirname, "..", "client");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bobfrankston/mailx",
3
- "version": "1.0.163",
3
+ "version": "1.0.164",
4
4
  "description": "Local-first email client with IMAP sync and standalone native app",
5
5
  "type": "module",
6
6
  "main": "bin/mailx.js",
@@ -20,10 +20,11 @@
20
20
  "postinstall": "node bin/postinstall.js"
21
21
  },
22
22
  "dependencies": {
23
- "@bobfrankston/iflow": "^1.0.56",
23
+ "@bobfrankston/iflow-direct": "^0.1.0",
24
+ "@bobfrankston/iflow-node": "^0.1.0",
24
25
  "@bobfrankston/miscinfo": "^1.0.7",
25
26
  "@bobfrankston/oauthsupport": "^1.0.20",
26
- "@bobfrankston/msger": "^0.1.213",
27
+ "@bobfrankston/msger": "^0.1.214",
27
28
  "@capacitor/android": "^8.3.0",
28
29
  "@capacitor/cli": "^8.3.0",
29
30
  "@capacitor/core": "^8.3.0",
@@ -54,7 +55,8 @@
54
55
  "url": "https://github.com/BobFrankston/mailx.git"
55
56
  },
56
57
  ".dependencies": {
57
- "@bobfrankston/iflow": "file:../MailApps/iflow",
58
+ "@bobfrankston/iflow-direct": "file:../MailApps/iflow-direct",
59
+ "@bobfrankston/iflow-node": "file:../MailApps/iflow-node",
58
60
  "@bobfrankston/miscinfo": "file:../../projects/npm/miscinfo",
59
61
  "@bobfrankston/oauthsupport": "file:../../projects/oauth/oauthsupport",
60
62
  "@bobfrankston/msger": "file:../../utils/msgx/msger",
@@ -3,7 +3,6 @@
3
3
  * Multi-account IMAP management wrapping iflow.
4
4
  * Syncs messages to local store, emits events for new mail.
5
5
  */
6
- import { ImapClient } from "@bobfrankston/iflow";
7
6
  import { MailxDB, FileMessageStore } from "@bobfrankston/mailx-store";
8
7
  import type { AccountConfig, MessageEnvelope, Folder } from "@bobfrankston/mailx-types";
9
8
  import { EventEmitter } from "node:events";
@@ -73,11 +72,11 @@ export declare class ImapManager extends EventEmitter {
73
72
  /** Register an account */
74
73
  addAccount(account: AccountConfig): Promise<void>;
75
74
  /** Sync folder list for an account */
76
- syncFolders(accountId: string, client?: ImapClient): Promise<Folder[]>;
75
+ syncFolders(accountId: string, client?: any): Promise<Folder[]>;
77
76
  /** Store a batch of messages to DB immediately — used by onChunk for incremental sync */
78
77
  private storeMessages;
79
78
  /** Sync messages for a specific folder */
80
- syncFolder(accountId: string, folderId: number, client?: ImapClient): Promise<number>;
79
+ syncFolder(accountId: string, folderId: number, client?: any): Promise<number>;
81
80
  /** Sync all folders for all accounts */
82
81
  syncAll(): Promise<void>;
83
82
  private _syncAll;
@@ -3,7 +3,8 @@
3
3
  * Multi-account IMAP management wrapping iflow.
4
4
  * Syncs messages to local store, emits events for new mail.
5
5
  */
6
- import { ImapClient, createAutoImapConfig, CompatImapClient, NodeTransport } from "@bobfrankston/iflow";
6
+ import { createAutoImapConfig, CompatImapClient } from "@bobfrankston/iflow-direct";
7
+ import { NodeTransport } from "@bobfrankston/iflow-node";
7
8
  import { FileMessageStore } from "@bobfrankston/mailx-store";
8
9
  import { loadSettings, getStorePath, getConfigDir, getHistoryDays } from "@bobfrankston/mailx-settings";
9
10
  import { EventEmitter } from "node:events";
@@ -280,10 +281,7 @@ export class ImapManager extends EventEmitter {
280
281
  const config = this.configs.get(accountId);
281
282
  if (!config)
282
283
  throw new Error(`No config for account ${accountId}`);
283
- if (this.useNativeClient) {
284
- return new CompatImapClient(config, () => new NodeTransport({ rejectUnauthorized: config.rejectUnauthorized !== false }));
285
- }
286
- return new ImapClient(config);
284
+ return new CompatImapClient(config, () => new NodeTransport({ rejectUnauthorized: config.rejectUnauthorized !== false }));
287
285
  }
288
286
  /** Disconnect the persistent operational connection for an account */
289
287
  async disconnectOps(accountId) {
@@ -321,7 +319,7 @@ export class ImapManager extends EventEmitter {
321
319
  port: account.imap.port,
322
320
  username: account.imap.user,
323
321
  password: account.imap.password,
324
- tokenDirectory: getConfigDir()
322
+ // tokenDirectory is handled by oauthsupport, not iflow-direct
325
323
  });
326
324
  this.configs.set(account.id, config);
327
325
  // Register account in DB
@@ -447,7 +445,7 @@ export class ImapManager extends EventEmitter {
447
445
  // Incremental: fetch new messages — metadata only for speed, bodies on demand
448
446
  const fetched = await client.fetchMessagesSinceUid(folder.path, highestUid, { source: false });
449
447
  // Filter out the last known message (IMAP * always returns at least one)
450
- messages = fetched.filter(m => m.uid > highestUid);
448
+ messages = fetched.filter((m) => m.uid > highestUid);
451
449
  // Gap detection: check for missing UIDs within the range we've already synced
452
450
  // Only reconcile between our lowest and highest UID — don't try to fetch the entire folder history
453
451
  const existingUids = this.db.getUidsForFolder(accountId, folderId);
@@ -483,7 +481,7 @@ export class ImapManager extends EventEmitter {
483
481
  if (oldestDate > 0 && startDate.getTime() < oldestDate) {
484
482
  const existingUids = new Set(this.db.getUidsForFolder(accountId, folderId));
485
483
  const backfill = await client.fetchMessageByDate(folder.path, startDate, new Date(oldestDate), { source: false });
486
- const newBackfill = backfill.filter(m => !existingUids.has(m.uid));
484
+ const newBackfill = backfill.filter((m) => !existingUids.has(m.uid));
487
485
  if (newBackfill.length > 0) {
488
486
  console.log(` ${folder.path}: backfilling ${newBackfill.length} older messages`);
489
487
  messages.push(...newBackfill);
@@ -12,7 +12,7 @@
12
12
  "@bobfrankston/mailx-types": "file:../mailx-types",
13
13
  "@bobfrankston/mailx-settings": "file:../mailx-settings",
14
14
  "@bobfrankston/mailx-store": "file:../mailx-store",
15
- "@bobfrankston/iflow": "file:../../../MailApps/iflow",
15
+ "@bobfrankston/iflow-direct": "file:../../../MailApps/iflow-direct",
16
16
  "@bobfrankston/oauthsupport": "file:../../../../projects/oauth/oauthsupport",
17
17
  "nodemailer": "^7.0.0"
18
18
  },
@@ -30,10 +30,12 @@ function findGoogleCredentials() {
30
30
  try {
31
31
  let dir = import.meta.dirname;
32
32
  for (let i = 0; i < 5; i++) {
33
- for (const name of ["iflow-credentials.json", "credentials.json"]) {
34
- const p = path.join(dir, "node_modules", "@bobfrankston", "iflow", name);
35
- if (fs.existsSync(p))
36
- return p;
33
+ for (const pkg of ["iflow-direct", "iflow"]) {
34
+ for (const name of ["iflow-credentials.json", "credentials.json"]) {
35
+ const p = path.join(dir, "node_modules", "@bobfrankston", pkg, name);
36
+ if (fs.existsSync(p))
37
+ return p;
38
+ }
37
39
  }
38
40
  const parent = path.dirname(dir);
39
41
  if (parent === dir)