@bobfrankston/mailx 1.0.200 → 1.0.202

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.
@@ -1 +1 @@
1
- {"height":1344,"width":2151,"x":587,"y":80}
1
+ {"height":1344,"width":2151,"x":469,"y":64}
package/client/app.js CHANGED
@@ -310,12 +310,15 @@ async function openCompose(mode) {
310
310
  if (!msg || identityDomains.length === 0)
311
311
  return undefined;
312
312
  const candidates = [msg.deliveredTo, ...(msg.to || []).map((a) => a.address)].filter(Boolean);
313
+ console.log(`[compose] detectReplyFrom: deliveredTo=${msg.deliveredTo}, to=${msg.to?.map((a) => a.address)}, domains=${identityDomains}`);
313
314
  for (const addr of candidates) {
314
315
  const domain = addr.split("@")[1]?.toLowerCase();
315
316
  if (domain && identityDomains.some((d) => domain === d.toLowerCase())) {
317
+ console.log(`[compose] matched: ${addr}`);
316
318
  return addr;
317
319
  }
318
320
  }
321
+ console.log(`[compose] no identity match`);
319
322
  return undefined;
320
323
  }
321
324
  if (msg && mode === "reply") {
@@ -415,7 +418,16 @@ function showComposeOverlay() {
415
418
  function quoteBody(msg) {
416
419
  const date = new Date(msg.date).toLocaleString();
417
420
  const from = msg.from.name ? `${msg.from.name} <${msg.from.address}>` : msg.from.address;
418
- const body = msg.bodyHtml || `<pre>${msg.bodyText || ""}</pre>`;
421
+ // Simplify complex HTML (tables, inline styles) for Quill compatibility
422
+ let body = msg.bodyHtml || `<pre>${msg.bodyText || ""}</pre>`;
423
+ // Strip style tags and attributes
424
+ body = body.replace(/<style[^>]*>[\s\S]*?<\/style>/gi, "");
425
+ body = body.replace(/\s+style="[^"]*"/gi, "");
426
+ body = body.replace(/\s+class="[^"]*"/gi, "");
427
+ // Convert tables to simple divs
428
+ body = body.replace(/<table[^>]*>/gi, "<div>").replace(/<\/table>/gi, "</div>");
429
+ body = body.replace(/<t[rdh][^>]*>/gi, "").replace(/<\/t[rdh]>/gi, " ");
430
+ body = body.replace(/<thead[^>]*>|<\/thead>|<tbody[^>]*>|<\/tbody>/gi, "");
419
431
  return `<br><div class="reply"><p>On ${date}, ${from} wrote:</p><blockquote>${body}</blockquote></div>`;
420
432
  }
421
433
  function forwardBody(msg) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bobfrankston/mailx",
3
- "version": "1.0.200",
3
+ "version": "1.0.202",
4
4
  "description": "Local-first email client with IMAP sync and standalone native app",
5
5
  "type": "module",
6
6
  "main": "bin/mailx.js",
@@ -24,7 +24,7 @@
24
24
  "@bobfrankston/iflow-node": "^0.1.2",
25
25
  "@bobfrankston/miscinfo": "^1.0.8",
26
26
  "@bobfrankston/oauthsupport": "^1.0.22",
27
- "@bobfrankston/msger": "^0.1.252",
27
+ "@bobfrankston/msger": "^0.1.254",
28
28
  "@capacitor/android": "^8.3.0",
29
29
  "@capacitor/cli": "^8.3.0",
30
30
  "@capacitor/core": "^8.3.0",
@@ -128,7 +128,8 @@ export declare class ImapManager extends EventEmitter {
128
128
  private fetchQueues;
129
129
  /** Serialize body fetch operations per account — prevents concurrent IMAP commands on same connection */
130
130
  private enqueueFetch;
131
- /** Fetch a single message body on demand, caching in the store */
131
+ /** Fetch a single message body on demand, caching in the store.
132
+ * Uses its own fresh connection — never blocked by background prefetch. */
132
133
  fetchMessageBody(accountId: string, folderId: number, uid: number): Promise<Buffer | null>;
133
134
  /** Fetch message body via Gmail/Outlook API */
134
135
  private fetchMessageBodyViaApi;
@@ -1218,7 +1218,8 @@ export class ImapManager extends EventEmitter {
1218
1218
  return next;
1219
1219
  }
1220
1220
  // Body fetch uses withConnection — no separate client needed
1221
- /** Fetch a single message body on demand, caching in the store */
1221
+ /** Fetch a single message body on demand, caching in the store.
1222
+ * Uses its own fresh connection — never blocked by background prefetch. */
1222
1223
  async fetchMessageBody(accountId, folderId, uid) {
1223
1224
  // Already cached?
1224
1225
  if (await this.bodyStore.hasMessage(accountId, folderId, uid)) {
@@ -1233,36 +1234,30 @@ export class ImapManager extends EventEmitter {
1233
1234
  if (this.isGmailAccount(accountId)) {
1234
1235
  return this.fetchMessageBodyViaApi(accountId, folderId, uid, folder.path);
1235
1236
  }
1236
- // IMAP: serialize only one body fetch per account at a time
1237
- return this.enqueueFetch(accountId, async () => {
1238
- // Re-check cache — may have been fetched while queued
1239
- if (await this.bodyStore.hasMessage(accountId, folderId, uid)) {
1240
- return this.bodyStore.getMessage(accountId, folderId, uid);
1241
- }
1242
- let client = null;
1243
- try {
1244
- client = this.newClient(accountId);
1245
- const msg = await client.fetchMessageByUid(folder.path, uid, { source: true });
1246
- await client.logout();
1247
- client = null;
1248
- if (!msg?.source)
1249
- return null;
1250
- const raw = Buffer.from(msg.source, "utf-8");
1251
- const bodyPath = await this.bodyStore.putMessage(accountId, folderId, uid, raw);
1252
- this.db.updateBodyPath(accountId, uid, bodyPath);
1253
- return raw;
1254
- }
1255
- catch (e) {
1256
- console.error(` Body fetch error (${accountId}/${uid}): ${e.message}`);
1257
- if (client) {
1258
- try {
1259
- await client.logout();
1260
- }
1261
- catch { /* */ }
1262
- }
1237
+ // IMAP: fresh connection per on-demand fetch never queued behind prefetch
1238
+ let client = null;
1239
+ try {
1240
+ client = this.newClient(accountId);
1241
+ const msg = await client.fetchMessageByUid(folder.path, uid, { source: true });
1242
+ await client.logout();
1243
+ client = null;
1244
+ if (!msg?.source)
1263
1245
  return null;
1246
+ const raw = Buffer.from(msg.source, "utf-8");
1247
+ const bodyPath = await this.bodyStore.putMessage(accountId, folderId, uid, raw);
1248
+ this.db.updateBodyPath(accountId, uid, bodyPath);
1249
+ return raw;
1250
+ }
1251
+ catch (e) {
1252
+ console.error(` Body fetch error (${accountId}/${uid}): ${e.message}`);
1253
+ if (client) {
1254
+ try {
1255
+ await client.logout();
1256
+ }
1257
+ catch { /* */ }
1264
1258
  }
1265
- });
1259
+ return null;
1260
+ }
1266
1261
  }
1267
1262
  /** Fetch message body via Gmail/Outlook API */
1268
1263
  async fetchMessageBodyViaApi(accountId, folderId, uid, folderPath) {
@@ -114,9 +114,7 @@ export async function cloudRead(filename) {
114
114
  }
115
115
  catch { /* ignore cache write failure */ }
116
116
  }
117
- else {
118
- lastCloudError = `Could not read ${filename} from ${pendingCloudConfig.provider} (check credentials)`;
119
- }
117
+ // Don't set error for missing files — they may not exist yet (e.g., clients.jsonc on first run)
120
118
  return content;
121
119
  }
122
120
  /** Write a file via cloud API */