@bobfrankston/mailx 1.0.2 → 1.0.4

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/README.md CHANGED
@@ -76,11 +76,12 @@ If `config.json` doesn't exist, settings default to `~/.mailx/settings.jsonc`.
76
76
  "intervalMinutes": 5, // Full sync interval
77
77
  "historyDays": 30 // Days of history (0 = all)
78
78
  },
79
+ // UI preferences
79
80
  "ui": {
80
- "theme": "dark",
81
+ "theme": "system", // "system" (follows OS), "dark", or "light"
81
82
  "folderWidth": 220,
82
83
  "listViewerSplit": 40,
83
- "fontSize": 14
84
+ "fontSize": 15
84
85
  },
85
86
  // Auto-populated when you click "Always allow from sender/domain"
86
87
  "remoteAllowList": {
package/bin/mailx.js CHANGED
@@ -1,17 +1,21 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * mailx launcher starts the server and opens the browser.
4
- * Usage: mailx [--external] [--no-browser]
3
+ * mailx — email client launcher
4
+ *
5
+ * Usage:
6
+ * mailx Start unified (in-process server + open browser)
7
+ * mailx --server Start as a standalone server only (no browser)
8
+ * mailx --no-browser Start server in-process, don't open browser
9
+ * mailx --external Bind to all interfaces (default: localhost only)
5
10
  */
6
11
 
7
- import { spawn } from "node:child_process";
8
12
  import { fileURLToPath } from "node:url";
9
13
  import path from "node:path";
10
14
  import net from "node:net";
11
15
 
12
16
  const PORT = 9333;
13
17
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
14
- const serverScript = path.join(__dirname, "..", "packages", "mailx-server", "index.js");
18
+ const args = process.argv.slice(2);
15
19
 
16
20
  function isPortInUse(port) {
17
21
  return new Promise((resolve) => {
@@ -22,36 +26,45 @@ function isPortInUse(port) {
22
26
  });
23
27
  }
24
28
 
29
+ function openBrowser(url) {
30
+ import("node:child_process").then(({ exec }) => {
31
+ if (process.platform === "win32") exec(`start "" "${url}"`);
32
+ else if (process.platform === "darwin") exec(`open "${url}"`);
33
+ else exec(`xdg-open "${url}"`);
34
+ });
35
+ }
36
+
25
37
  async function main() {
26
- const args = process.argv.slice(2);
27
- const noBrowser = args.includes("--no-browser");
28
- const inUse = await isPortInUse(PORT);
38
+ const serverOnly = args.includes("--server");
39
+ const noBrowser = args.includes("--no-browser") || serverOnly;
29
40
 
41
+ const inUse = await isPortInUse(PORT);
30
42
  if (inUse) {
31
43
  console.log(`mailx server already running on port ${PORT}`);
32
- } else {
33
- console.log(`Starting mailx server on port ${PORT}...`);
34
- const serverArgs = [serverScript, ...args.filter(a => a === "--external")];
35
- const child = spawn(process.execPath, serverArgs, {
36
- stdio: "inherit",
37
- detached: false,
38
- });
39
- child.unref();
40
-
41
- // Wait for server to be ready
42
- for (let i = 0; i < 60; i++) {
43
- await new Promise(r => setTimeout(r, 500));
44
- if (await isPortInUse(PORT)) break;
44
+ if (!noBrowser) {
45
+ openBrowser(`http://localhost:${PORT}`);
46
+ console.log(`Opened http://localhost:${PORT}`);
45
47
  }
48
+ return;
46
49
  }
47
50
 
51
+ // Start server in-process (unified mode)
52
+ console.log(`Starting mailx on port ${PORT}...`);
53
+
54
+ // Pass --external to server if requested
55
+ if (args.includes("--external")) process.argv.push("--external");
56
+
57
+ // Import and start the server directly — no subprocess
58
+ await import(path.join(__dirname, "..", "packages", "mailx-server", "index.js"));
59
+
48
60
  if (!noBrowser) {
49
- const url = `http://localhost:${PORT}`;
50
- const { exec } = await import("node:child_process");
51
- if (process.platform === "win32") exec(`start "" "${url}"`);
52
- else if (process.platform === "darwin") exec(`open "${url}"`);
53
- else exec(`xdg-open "${url}"`);
54
- console.log(`Opened ${url}`);
61
+ // Wait a moment for server to be ready
62
+ for (let i = 0; i < 30; i++) {
63
+ await new Promise(r => setTimeout(r, 200));
64
+ if (await isPortInUse(PORT)) break;
65
+ }
66
+ openBrowser(`http://localhost:${PORT}`);
67
+ console.log(`Opened http://localhost:${PORT}`);
55
68
  }
56
69
  }
57
70
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bobfrankston/mailx",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "Local-first email client with IMAP sync and standalone native app",
5
5
  "type": "module",
6
6
  "main": "bin/mailx.js",
@@ -22,6 +22,7 @@
22
22
  "@bobfrankston/iflow": "^1.0.2",
23
23
  "@bobfrankston/miscinfo": "^1.0.5",
24
24
  "@bobfrankston/oauthsupport": "^1.0.10",
25
+ "@bobfrankston/certsupport": "^1.0.35",
25
26
  "mailparser": "^3.7.2",
26
27
  "quill": "^2.0.3"
27
28
  },
@@ -45,6 +46,7 @@
45
46
  "@bobfrankston/iflow": "file:../MailApps/iflow",
46
47
  "@bobfrankston/miscinfo": "file:../../projects/npm/miscinfo",
47
48
  "@bobfrankston/oauthsupport": "file:../../projects/oauth/oauthsupport",
49
+ "@bobfrankston/certsupport": "file:../../projects/nodejs/certsupport",
48
50
  "mailparser": "^3.7.2",
49
51
  "quill": "^2.0.3"
50
52
  }
@@ -14,8 +14,19 @@ import { ports } from "@bobfrankston/miscinfo";
14
14
  import { InitServerAsync, InitServerOptions } from "@bobfrankston/certsupport";
15
15
  const PORT = ports.mailx;
16
16
  // ── File logging ──
17
- const logDir = path.join(import.meta.dirname, "..", "..");
18
- const logPath = path.join(logDir, "mailx.log");
17
+ const logDir = path.join(process.env.USERPROFILE || process.env.HOME || ".", ".mailx");
18
+ fs.mkdirSync(logDir, { recursive: true });
19
+ // Rotate: delete logs older than 7 days
20
+ try {
21
+ for (const f of fs.readdirSync(logDir).filter(f => f.startsWith("mailx-") && f.endsWith(".log"))) {
22
+ const stat = fs.statSync(path.join(logDir, f));
23
+ if (Date.now() - stat.mtimeMs > 7 * 86400000)
24
+ fs.unlinkSync(path.join(logDir, f));
25
+ }
26
+ }
27
+ catch { /* ignore cleanup errors */ }
28
+ const logDate = new Date().toISOString().slice(0, 10);
29
+ const logPath = path.join(logDir, `mailx-${logDate}.log`);
19
30
  const logStream = fs.createWriteStream(logPath, { flags: "a" });
20
31
  const origLog = console.log;
21
32
  const origErr = console.error;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bobfrankston/mailx-server",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "type": "module",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",