@bobfrankston/mailx 1.0.38 → 1.0.39

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.
@@ -317,7 +317,33 @@ async function loadFolderTree(container) {
317
317
  try {
318
318
  const accounts = await getAccounts();
319
319
  if (accounts.length === 0) {
320
- container.innerHTML = `<div class="folder-loading">No accounts configured.<br>Edit ~/.mailx/settings.jsonc</div>`;
320
+ container.innerHTML = `<div class="folder-loading" style="padding:1rem;line-height:1.8">
321
+ <strong>No accounts configured</strong><br>
322
+ Create <code>~/.mailx/settings.jsonc</code> with your email accounts.<br><br>
323
+ Minimal Gmail example:<br>
324
+ <code style="display:block;padding:0.5rem;background:var(--color-bg);border-radius:4px;margin:0.5rem 0;white-space:pre">{ "name": "Your Name",
325
+ "accounts": [
326
+ { "email": "you@gmail.com" }
327
+ ]
328
+ }</code>
329
+ Standard IMAP:<br>
330
+ <code style="display:block;padding:0.5rem;background:var(--color-bg);border-radius:4px;margin:0.5rem 0;white-space:pre">{ "name": "Your Name",
331
+ "accounts": [
332
+ { "email": "you@example.com",
333
+ "password": "secret",
334
+ "imap": { "host": "imap.example.com" },
335
+ "smtp": { "host": "smtp.example.com" }
336
+ }
337
+ ]
338
+ }</code>
339
+ <a href="https://github.com/BobFrankston/mailx#first-time-setup" target="_blank" style="color:var(--color-accent)">Full setup guide</a>
340
+ </div>`;
341
+ // Dismiss startup overlay
342
+ const overlay = document.getElementById("startup-overlay");
343
+ if (overlay) {
344
+ overlay.classList.add("hidden");
345
+ setTimeout(() => overlay.remove(), 400);
346
+ }
321
347
  return;
322
348
  }
323
349
  // Clear loading state now that we have data
@@ -30,7 +30,7 @@ async function api(path, options) {
30
30
  // Network error — server is down
31
31
  if (e.name === "AbortError")
32
32
  throw e;
33
- throw new Error("Server offline — restart with launch.ps1");
33
+ throw new Error("Server offline — run: mailx -server");
34
34
  }
35
35
  if (!res.ok) {
36
36
  const err = await res.json().catch(() => ({ error: res.statusText }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bobfrankston/mailx",
3
- "version": "1.0.38",
3
+ "version": "1.0.39",
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,7 +20,7 @@
20
20
  "postinstall": "node launcher/builder/postinstall.js"
21
21
  },
22
22
  "dependencies": {
23
- "@bobfrankston/iflow": "^1.0.9",
23
+ "@bobfrankston/iflow": "^1.0.10",
24
24
  "@bobfrankston/miscinfo": "^1.0.6",
25
25
  "@bobfrankston/oauthsupport": "^1.0.11",
26
26
  "@bobfrankston/rust-builder": "^0.1.2",
@@ -41,10 +41,10 @@ console.error = (...args) => {
41
41
  origErr(msg);
42
42
  logStream.write(msg + "\n");
43
43
  };
44
- const serverPkg = JSON.parse(fs.readFileSync(path.join(import.meta.dirname, "package.json"), "utf-8"));
45
- const clientPkg = JSON.parse(fs.readFileSync(path.join(import.meta.dirname, "..", "..", "client", "package.json"), "utf-8"));
46
- const SERVER_VERSION = serverPkg.version;
47
- const CLIENT_VERSION = clientPkg.version;
44
+ // Read version from root package.json (the published version)
45
+ const rootPkg = JSON.parse(fs.readFileSync(path.join(import.meta.dirname, "..", "..", "package.json"), "utf-8"));
46
+ const SERVER_VERSION = rootPkg.version;
47
+ const CLIENT_VERSION = rootPkg.version;
48
48
  // ── Initialize ──
49
49
  initLocalConfig();
50
50
  const settings = loadSettings();
@@ -23,6 +23,22 @@ const LOCAL_DIR = path.join(process.env.USERPROFILE || process.env.HOME || ".",
23
23
  const LOCAL_CONFIG_PATH = path.join(LOCAL_DIR, "config.jsonc");
24
24
  const LEGACY_CONFIG_PATH = path.join(LOCAL_DIR, "config.json");
25
25
  const DEFAULT_STORE_PATH = path.join(LOCAL_DIR, "mailxstore");
26
+ /** Resolve a path from config — relative to ~/.mailx/, ~ expands to home */
27
+ function resolvePath(p) {
28
+ if (!p)
29
+ return p;
30
+ const home = process.env.USERPROFILE || process.env.HOME || ".";
31
+ // Expand ~ to home directory
32
+ if (p.startsWith("~/") || p.startsWith("~\\"))
33
+ return path.join(home, p.slice(2));
34
+ if (p === "~")
35
+ return home;
36
+ // Absolute path — use as-is
37
+ if (path.isAbsolute(p))
38
+ return p;
39
+ // Relative — resolve from config directory (~/.mailx/)
40
+ return path.resolve(LOCAL_DIR, p);
41
+ }
26
42
  function readLocalConfig() {
27
43
  // Migrate config.json → config.jsonc
28
44
  if (!fs.existsSync(LOCAL_CONFIG_PATH) && fs.existsSync(LEGACY_CONFIG_PATH)) {
@@ -35,10 +51,10 @@ function readLocalConfig() {
35
51
  function getSharedDir() {
36
52
  const config = readLocalConfig();
37
53
  if (config.sharedDir)
38
- return config.sharedDir;
54
+ return resolvePath(config.sharedDir);
39
55
  // Legacy: derive from settingsPath
40
56
  if (config.settingsPath)
41
- return path.dirname(config.settingsPath);
57
+ return path.dirname(resolvePath(config.settingsPath));
42
58
  return LOCAL_DIR;
43
59
  }
44
60
  // ── File helpers ──
@@ -276,7 +292,7 @@ export function saveSettings(settings) {
276
292
  /** Get the local store base path */
277
293
  export function getStorePath() {
278
294
  const config = readLocalConfig();
279
- return config.storePath || DEFAULT_STORE_PATH;
295
+ return config.storePath ? resolvePath(config.storePath) : DEFAULT_STORE_PATH;
280
296
  }
281
297
  /** Get the local data directory (DB, store, etc.) */
282
298
  export function getConfigDir() {