@bobfrankston/mailx 1.0.12 → 1.0.14
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 +52 -28
- package/client/app.js +113 -30
- package/client/components/folder-tree.js +84 -3
- package/client/components/message-list.js +164 -10
- package/client/components/message-viewer.js +130 -13
- package/client/compose/compose.html +4 -4
- package/client/compose/compose.js +53 -34
- package/client/index.html +50 -21
- package/client/lib/api-client.js +112 -31
- package/client/lib/mailxapi.js +123 -0
- package/client/package.json +1 -1
- package/client/styles/components.css +206 -16
- package/client/styles/layout.css +2 -1
- package/killmail.cmd +6 -0
- package/launch.ps1 +47 -5
- package/launcher/bin/mailx-app-linux +0 -0
- package/launcher/bin/mailx-app.exe +0 -0
- package/launcher/builder/build-config.json +11 -0
- package/launcher/builder/postinstall.js +81 -0
- package/package.json +2 -4
- package/packages/mailx-api/index.js +125 -29
- package/packages/mailx-core/index.d.ts +129 -0
- package/packages/mailx-core/index.js +323 -0
- package/packages/mailx-core/ipc.d.ts +13 -0
- package/packages/mailx-core/ipc.js +56 -0
- package/packages/mailx-core/package.json +18 -0
- package/packages/mailx-imap/index.d.ts +7 -1
- package/packages/mailx-imap/index.js +89 -14
- package/packages/mailx-server/index.js +42 -31
- package/packages/mailx-server/package.json +1 -2
- package/packages/mailx-settings/index.d.ts +1 -1
- package/packages/mailx-settings/index.js +21 -12
- package/packages/mailx-store/db.d.ts +6 -2
- package/packages/mailx-store/db.js +78 -16
- package/packages/mailx-store/file-store.d.ts +2 -8
- package/packages/mailx-store/file-store.js +7 -31
- package/packages/mailx-types/index.d.ts +3 -1
- package/.tswalk.json +0 -7396
- package/launcher/release.cmd +0 -4
- package/mailx.json +0 -9
- package/packages/mailx-api/node_modules/nodemailer/.ncurc.js +0 -9
- package/packages/mailx-api/node_modules/nodemailer/.prettierignore +0 -8
- package/packages/mailx-api/node_modules/nodemailer/.prettierrc +0 -12
- package/packages/mailx-api/node_modules/nodemailer/.prettierrc.js +0 -10
- package/packages/mailx-api/node_modules/nodemailer/.release-please-config.json +0 -9
- package/packages/mailx-api/node_modules/nodemailer/LICENSE +0 -16
- package/packages/mailx-api/node_modules/nodemailer/README.md +0 -86
- package/packages/mailx-api/node_modules/nodemailer/SECURITY.txt +0 -22
- package/packages/mailx-api/node_modules/nodemailer/eslint.config.js +0 -88
- package/packages/mailx-api/node_modules/nodemailer/lib/addressparser/index.js +0 -383
- package/packages/mailx-api/node_modules/nodemailer/lib/base64/index.js +0 -139
- package/packages/mailx-api/node_modules/nodemailer/lib/dkim/index.js +0 -253
- package/packages/mailx-api/node_modules/nodemailer/lib/dkim/message-parser.js +0 -155
- package/packages/mailx-api/node_modules/nodemailer/lib/dkim/relaxed-body.js +0 -154
- package/packages/mailx-api/node_modules/nodemailer/lib/dkim/sign.js +0 -117
- package/packages/mailx-api/node_modules/nodemailer/lib/fetch/cookies.js +0 -281
- package/packages/mailx-api/node_modules/nodemailer/lib/fetch/index.js +0 -280
- package/packages/mailx-api/node_modules/nodemailer/lib/json-transport/index.js +0 -82
- package/packages/mailx-api/node_modules/nodemailer/lib/mail-composer/index.js +0 -629
- package/packages/mailx-api/node_modules/nodemailer/lib/mailer/index.js +0 -441
- package/packages/mailx-api/node_modules/nodemailer/lib/mailer/mail-message.js +0 -316
- package/packages/mailx-api/node_modules/nodemailer/lib/mime-funcs/index.js +0 -625
- package/packages/mailx-api/node_modules/nodemailer/lib/mime-funcs/mime-types.js +0 -2113
- package/packages/mailx-api/node_modules/nodemailer/lib/mime-node/index.js +0 -1316
- package/packages/mailx-api/node_modules/nodemailer/lib/mime-node/last-newline.js +0 -33
- package/packages/mailx-api/node_modules/nodemailer/lib/mime-node/le-unix.js +0 -43
- package/packages/mailx-api/node_modules/nodemailer/lib/mime-node/le-windows.js +0 -52
- package/packages/mailx-api/node_modules/nodemailer/lib/nodemailer.js +0 -157
- package/packages/mailx-api/node_modules/nodemailer/lib/punycode/index.js +0 -460
- package/packages/mailx-api/node_modules/nodemailer/lib/qp/index.js +0 -227
- package/packages/mailx-api/node_modules/nodemailer/lib/sendmail-transport/index.js +0 -210
- package/packages/mailx-api/node_modules/nodemailer/lib/ses-transport/index.js +0 -234
- package/packages/mailx-api/node_modules/nodemailer/lib/shared/index.js +0 -754
- package/packages/mailx-api/node_modules/nodemailer/lib/smtp-connection/data-stream.js +0 -108
- package/packages/mailx-api/node_modules/nodemailer/lib/smtp-connection/http-proxy-client.js +0 -143
- package/packages/mailx-api/node_modules/nodemailer/lib/smtp-connection/index.js +0 -1870
- package/packages/mailx-api/node_modules/nodemailer/lib/smtp-pool/index.js +0 -652
- package/packages/mailx-api/node_modules/nodemailer/lib/smtp-pool/pool-resource.js +0 -259
- package/packages/mailx-api/node_modules/nodemailer/lib/smtp-transport/index.js +0 -421
- package/packages/mailx-api/node_modules/nodemailer/lib/stream-transport/index.js +0 -135
- package/packages/mailx-api/node_modules/nodemailer/lib/well-known/index.js +0 -47
- package/packages/mailx-api/node_modules/nodemailer/lib/well-known/services.json +0 -611
- package/packages/mailx-api/node_modules/nodemailer/lib/xoauth2/index.js +0 -427
- package/packages/mailx-api/node_modules/nodemailer/package.json +0 -47
- package/packages/mailx-imap/node_modules/nodemailer/.ncurc.js +0 -9
- package/packages/mailx-imap/node_modules/nodemailer/.prettierignore +0 -8
- package/packages/mailx-imap/node_modules/nodemailer/.prettierrc +0 -12
- package/packages/mailx-imap/node_modules/nodemailer/.prettierrc.js +0 -10
- package/packages/mailx-imap/node_modules/nodemailer/.release-please-config.json +0 -9
- package/packages/mailx-imap/node_modules/nodemailer/LICENSE +0 -16
- package/packages/mailx-imap/node_modules/nodemailer/README.md +0 -86
- package/packages/mailx-imap/node_modules/nodemailer/SECURITY.txt +0 -22
- package/packages/mailx-imap/node_modules/nodemailer/eslint.config.js +0 -88
- package/packages/mailx-imap/node_modules/nodemailer/lib/addressparser/index.js +0 -383
- package/packages/mailx-imap/node_modules/nodemailer/lib/base64/index.js +0 -139
- package/packages/mailx-imap/node_modules/nodemailer/lib/dkim/index.js +0 -253
- package/packages/mailx-imap/node_modules/nodemailer/lib/dkim/message-parser.js +0 -155
- package/packages/mailx-imap/node_modules/nodemailer/lib/dkim/relaxed-body.js +0 -154
- package/packages/mailx-imap/node_modules/nodemailer/lib/dkim/sign.js +0 -117
- package/packages/mailx-imap/node_modules/nodemailer/lib/fetch/cookies.js +0 -281
- package/packages/mailx-imap/node_modules/nodemailer/lib/fetch/index.js +0 -280
- package/packages/mailx-imap/node_modules/nodemailer/lib/json-transport/index.js +0 -82
- package/packages/mailx-imap/node_modules/nodemailer/lib/mail-composer/index.js +0 -629
- package/packages/mailx-imap/node_modules/nodemailer/lib/mailer/index.js +0 -441
- package/packages/mailx-imap/node_modules/nodemailer/lib/mailer/mail-message.js +0 -316
- package/packages/mailx-imap/node_modules/nodemailer/lib/mime-funcs/index.js +0 -625
- package/packages/mailx-imap/node_modules/nodemailer/lib/mime-funcs/mime-types.js +0 -2113
- package/packages/mailx-imap/node_modules/nodemailer/lib/mime-node/index.js +0 -1316
- package/packages/mailx-imap/node_modules/nodemailer/lib/mime-node/last-newline.js +0 -33
- package/packages/mailx-imap/node_modules/nodemailer/lib/mime-node/le-unix.js +0 -43
- package/packages/mailx-imap/node_modules/nodemailer/lib/mime-node/le-windows.js +0 -52
- package/packages/mailx-imap/node_modules/nodemailer/lib/nodemailer.js +0 -157
- package/packages/mailx-imap/node_modules/nodemailer/lib/punycode/index.js +0 -460
- package/packages/mailx-imap/node_modules/nodemailer/lib/qp/index.js +0 -227
- package/packages/mailx-imap/node_modules/nodemailer/lib/sendmail-transport/index.js +0 -210
- package/packages/mailx-imap/node_modules/nodemailer/lib/ses-transport/index.js +0 -234
- package/packages/mailx-imap/node_modules/nodemailer/lib/shared/index.js +0 -754
- package/packages/mailx-imap/node_modules/nodemailer/lib/smtp-connection/data-stream.js +0 -108
- package/packages/mailx-imap/node_modules/nodemailer/lib/smtp-connection/http-proxy-client.js +0 -143
- package/packages/mailx-imap/node_modules/nodemailer/lib/smtp-connection/index.js +0 -1870
- package/packages/mailx-imap/node_modules/nodemailer/lib/smtp-pool/index.js +0 -652
- package/packages/mailx-imap/node_modules/nodemailer/lib/smtp-pool/pool-resource.js +0 -259
- package/packages/mailx-imap/node_modules/nodemailer/lib/smtp-transport/index.js +0 -421
- package/packages/mailx-imap/node_modules/nodemailer/lib/stream-transport/index.js +0 -135
- package/packages/mailx-imap/node_modules/nodemailer/lib/well-known/index.js +0 -47
- package/packages/mailx-imap/node_modules/nodemailer/lib/well-known/services.json +0 -611
- package/packages/mailx-imap/node_modules/nodemailer/lib/xoauth2/index.js +0 -427
- package/packages/mailx-imap/node_modules/nodemailer/package.json +0 -47
- package/packages/mailx-send/node_modules/nodemailer/.ncurc.js +0 -9
- package/packages/mailx-send/node_modules/nodemailer/.prettierignore +0 -8
- package/packages/mailx-send/node_modules/nodemailer/.prettierrc +0 -12
- package/packages/mailx-send/node_modules/nodemailer/.prettierrc.js +0 -10
- package/packages/mailx-send/node_modules/nodemailer/.release-please-config.json +0 -9
- package/packages/mailx-send/node_modules/nodemailer/LICENSE +0 -16
- package/packages/mailx-send/node_modules/nodemailer/README.md +0 -86
- package/packages/mailx-send/node_modules/nodemailer/SECURITY.txt +0 -22
- package/packages/mailx-send/node_modules/nodemailer/eslint.config.js +0 -88
- package/packages/mailx-send/node_modules/nodemailer/lib/addressparser/index.js +0 -383
- package/packages/mailx-send/node_modules/nodemailer/lib/base64/index.js +0 -139
- package/packages/mailx-send/node_modules/nodemailer/lib/dkim/index.js +0 -253
- package/packages/mailx-send/node_modules/nodemailer/lib/dkim/message-parser.js +0 -155
- package/packages/mailx-send/node_modules/nodemailer/lib/dkim/relaxed-body.js +0 -154
- package/packages/mailx-send/node_modules/nodemailer/lib/dkim/sign.js +0 -117
- package/packages/mailx-send/node_modules/nodemailer/lib/fetch/cookies.js +0 -281
- package/packages/mailx-send/node_modules/nodemailer/lib/fetch/index.js +0 -280
- package/packages/mailx-send/node_modules/nodemailer/lib/json-transport/index.js +0 -82
- package/packages/mailx-send/node_modules/nodemailer/lib/mail-composer/index.js +0 -629
- package/packages/mailx-send/node_modules/nodemailer/lib/mailer/index.js +0 -441
- package/packages/mailx-send/node_modules/nodemailer/lib/mailer/mail-message.js +0 -316
- package/packages/mailx-send/node_modules/nodemailer/lib/mime-funcs/index.js +0 -625
- package/packages/mailx-send/node_modules/nodemailer/lib/mime-funcs/mime-types.js +0 -2113
- package/packages/mailx-send/node_modules/nodemailer/lib/mime-node/index.js +0 -1316
- package/packages/mailx-send/node_modules/nodemailer/lib/mime-node/last-newline.js +0 -33
- package/packages/mailx-send/node_modules/nodemailer/lib/mime-node/le-unix.js +0 -43
- package/packages/mailx-send/node_modules/nodemailer/lib/mime-node/le-windows.js +0 -52
- package/packages/mailx-send/node_modules/nodemailer/lib/nodemailer.js +0 -157
- package/packages/mailx-send/node_modules/nodemailer/lib/punycode/index.js +0 -460
- package/packages/mailx-send/node_modules/nodemailer/lib/qp/index.js +0 -227
- package/packages/mailx-send/node_modules/nodemailer/lib/sendmail-transport/index.js +0 -210
- package/packages/mailx-send/node_modules/nodemailer/lib/ses-transport/index.js +0 -234
- package/packages/mailx-send/node_modules/nodemailer/lib/shared/index.js +0 -754
- package/packages/mailx-send/node_modules/nodemailer/lib/smtp-connection/data-stream.js +0 -108
- package/packages/mailx-send/node_modules/nodemailer/lib/smtp-connection/http-proxy-client.js +0 -143
- package/packages/mailx-send/node_modules/nodemailer/lib/smtp-connection/index.js +0 -1870
- package/packages/mailx-send/node_modules/nodemailer/lib/smtp-pool/index.js +0 -652
- package/packages/mailx-send/node_modules/nodemailer/lib/smtp-pool/pool-resource.js +0 -259
- package/packages/mailx-send/node_modules/nodemailer/lib/smtp-transport/index.js +0 -421
- package/packages/mailx-send/node_modules/nodemailer/lib/stream-transport/index.js +0 -135
- package/packages/mailx-send/node_modules/nodemailer/lib/well-known/index.js +0 -47
- package/packages/mailx-send/node_modules/nodemailer/lib/well-known/services.json +0 -611
- package/packages/mailx-send/node_modules/nodemailer/lib/xoauth2/index.js +0 -427
- package/packages/mailx-send/node_modules/nodemailer/package.json +0 -47
|
@@ -241,8 +241,43 @@ export class MailxDB {
|
|
|
241
241
|
}));
|
|
242
242
|
return { items, total, page, pageSize };
|
|
243
243
|
}
|
|
244
|
-
|
|
245
|
-
|
|
244
|
+
/** Unified inbox: all inbox folders across accounts, sorted by date, paginated in SQL */
|
|
245
|
+
getUnifiedInbox(page = 1, pageSize = 50) {
|
|
246
|
+
const offset = (page - 1) * pageSize;
|
|
247
|
+
// Find all inbox folder IDs
|
|
248
|
+
const inboxRows = this.db.prepare("SELECT id FROM folders WHERE special_use = 'inbox'").all();
|
|
249
|
+
if (inboxRows.length === 0)
|
|
250
|
+
return { items: [], total: 0, page, pageSize };
|
|
251
|
+
const placeholders = inboxRows.map(() => "?").join(",");
|
|
252
|
+
const folderIds = inboxRows.map((r) => r.id);
|
|
253
|
+
const total = this.db.prepare(`SELECT COUNT(*) as cnt FROM messages WHERE folder_id IN (${placeholders})`).get(...folderIds).cnt;
|
|
254
|
+
const rows = this.db.prepare(`SELECT * FROM messages WHERE folder_id IN (${placeholders}) ORDER BY date DESC LIMIT ? OFFSET ?`).all(...folderIds, pageSize, offset);
|
|
255
|
+
const items = rows.map(r => ({
|
|
256
|
+
id: r.id,
|
|
257
|
+
accountId: r.account_id,
|
|
258
|
+
folderId: r.folder_id,
|
|
259
|
+
uid: r.uid,
|
|
260
|
+
messageId: r.message_id || "",
|
|
261
|
+
inReplyTo: r.in_reply_to || "",
|
|
262
|
+
references: JSON.parse(r.refs || "[]"),
|
|
263
|
+
date: r.date,
|
|
264
|
+
subject: r.subject,
|
|
265
|
+
from: { name: r.from_name, address: r.from_address },
|
|
266
|
+
to: JSON.parse(r.to_json),
|
|
267
|
+
cc: JSON.parse(r.cc_json),
|
|
268
|
+
flags: JSON.parse(r.flags_json),
|
|
269
|
+
size: r.size,
|
|
270
|
+
hasAttachments: !!r.has_attachments,
|
|
271
|
+
preview: r.preview
|
|
272
|
+
}));
|
|
273
|
+
return { items, total, page, pageSize };
|
|
274
|
+
}
|
|
275
|
+
getMessageByUid(accountId, uid, folderId) {
|
|
276
|
+
const sql = folderId != null
|
|
277
|
+
? "SELECT * FROM messages WHERE account_id = ? AND uid = ? AND folder_id = ?"
|
|
278
|
+
: "SELECT * FROM messages WHERE account_id = ? AND uid = ?";
|
|
279
|
+
const params = folderId != null ? [accountId, uid, folderId] : [accountId, uid];
|
|
280
|
+
const r = this.db.prepare(sql).get(...params);
|
|
246
281
|
if (!r)
|
|
247
282
|
return null;
|
|
248
283
|
return {
|
|
@@ -282,7 +317,19 @@ export class MailxDB {
|
|
|
282
317
|
}
|
|
283
318
|
/** Delete a message by account + UID */
|
|
284
319
|
deleteMessage(accountId, uid) {
|
|
320
|
+
// Get folderId before deleting so we can update counts
|
|
321
|
+
const msg = this.db.prepare("SELECT folder_id FROM messages WHERE account_id = ? AND uid = ?").get(accountId, uid);
|
|
285
322
|
this.db.prepare("DELETE FROM messages WHERE account_id = ? AND uid = ?").run(accountId, uid);
|
|
323
|
+
// Refresh folder counts
|
|
324
|
+
if (msg)
|
|
325
|
+
this.recalcFolderCounts(msg.folder_id);
|
|
326
|
+
}
|
|
327
|
+
/** Recalculate folder total/unread counts from actual messages */
|
|
328
|
+
recalcFolderCounts(folderId) {
|
|
329
|
+
const counts = this.db.prepare(`SELECT COUNT(*) as total,
|
|
330
|
+
SUM(CASE WHEN flags_json NOT LIKE '%\\\\Seen%' THEN 1 ELSE 0 END) as unread
|
|
331
|
+
FROM messages WHERE folder_id = ?`).get(folderId);
|
|
332
|
+
this.updateFolderCounts(folderId, counts?.total || 0, counts?.unread || 0);
|
|
286
333
|
}
|
|
287
334
|
/** Bulk insert within a transaction for sync performance */
|
|
288
335
|
beginTransaction() { this.db.exec("BEGIN"); }
|
|
@@ -328,7 +375,7 @@ export class MailxDB {
|
|
|
328
375
|
}
|
|
329
376
|
// ── Search ──
|
|
330
377
|
/** Full-text search across all messages. Supports qualifiers: from:, to:, subject: */
|
|
331
|
-
searchMessages(query, page = 1, pageSize = 50) {
|
|
378
|
+
searchMessages(query, page = 1, pageSize = 50, accountId, folderId) {
|
|
332
379
|
// Parse qualifiers
|
|
333
380
|
let ftsQuery = "";
|
|
334
381
|
const parts = query.match(/(?:[^\s"]+|"[^"]*")+/g) || [];
|
|
@@ -358,13 +405,23 @@ export class MailxDB {
|
|
|
358
405
|
return { items: [], total: 0, page, pageSize };
|
|
359
406
|
const offset = (page - 1) * pageSize;
|
|
360
407
|
try {
|
|
361
|
-
|
|
408
|
+
let scopeWhere = "";
|
|
409
|
+
const scopeParams = [];
|
|
410
|
+
if (accountId && folderId) {
|
|
411
|
+
scopeWhere = " AND m.account_id = ? AND m.folder_id = ?";
|
|
412
|
+
scopeParams.push(accountId, folderId);
|
|
413
|
+
}
|
|
414
|
+
else if (accountId) {
|
|
415
|
+
scopeWhere = " AND m.account_id = ?";
|
|
416
|
+
scopeParams.push(accountId);
|
|
417
|
+
}
|
|
418
|
+
const countRow = this.db.prepare(`SELECT COUNT(*) as cnt FROM messages m JOIN messages_fts fts ON m.id = fts.rowid WHERE messages_fts MATCH ?${scopeWhere}`).get(ftsQuery, ...scopeParams);
|
|
362
419
|
const total = countRow?.cnt || 0;
|
|
363
420
|
const rows = this.db.prepare(`SELECT m.* FROM messages m
|
|
364
421
|
JOIN messages_fts fts ON m.id = fts.rowid
|
|
365
|
-
WHERE messages_fts MATCH
|
|
422
|
+
WHERE messages_fts MATCH ?${scopeWhere}
|
|
366
423
|
ORDER BY m.date DESC
|
|
367
|
-
LIMIT ? OFFSET ?`).all(ftsQuery, pageSize, offset);
|
|
424
|
+
LIMIT ? OFFSET ?`).all(ftsQuery, ...scopeParams, pageSize, offset);
|
|
368
425
|
const items = rows.map(r => ({
|
|
369
426
|
id: r.id,
|
|
370
427
|
accountId: r.account_id,
|
|
@@ -401,19 +458,24 @@ export class MailxDB {
|
|
|
401
458
|
subject, from_name, from_address, to_text, cc_text, body_text,
|
|
402
459
|
content=messages, content_rowid=id
|
|
403
460
|
)`);
|
|
461
|
+
// Use a single transaction + prepared statement for speed (~50x faster than individual inserts)
|
|
462
|
+
const insert = this.db.prepare("INSERT INTO messages_fts (rowid, subject, from_name, from_address, to_text, cc_text, body_text) VALUES (?, ?, ?, ?, ?, ?, ?)");
|
|
404
463
|
const rows = this.db.prepare("SELECT id, subject, from_name, from_address, to_json, cc_json, preview FROM messages").all();
|
|
405
464
|
let count = 0;
|
|
406
|
-
|
|
407
|
-
const
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
465
|
+
const batchInsert = this.db.transaction(() => {
|
|
466
|
+
for (const r of rows) {
|
|
467
|
+
const to = JSON.parse(r.to_json || "[]");
|
|
468
|
+
const cc = JSON.parse(r.cc_json || "[]");
|
|
469
|
+
const toText = to.map((a) => `${a.name} ${a.address}`).join(" ");
|
|
470
|
+
const ccText = cc.map((a) => `${a.name} ${a.address}`).join(" ");
|
|
471
|
+
try {
|
|
472
|
+
insert.run(r.id, r.subject, r.from_name, r.from_address, toText, ccText, r.preview);
|
|
473
|
+
count++;
|
|
474
|
+
}
|
|
475
|
+
catch { /* skip duplicates */ }
|
|
414
476
|
}
|
|
415
|
-
|
|
416
|
-
|
|
477
|
+
});
|
|
478
|
+
batchInsert();
|
|
417
479
|
return count;
|
|
418
480
|
}
|
|
419
481
|
// ── Sync Actions ──
|
|
@@ -1,19 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* File-per-message body storage backend.
|
|
3
|
-
* Messages stored as: {basePath}/{accountId}/{
|
|
4
|
-
*
|
|
3
|
+
* Messages stored as: {basePath}/{accountId}/{folderId}/{uid}.eml
|
|
4
|
+
* Folder IDs are numeric (from SQLite), not names.
|
|
5
5
|
*/
|
|
6
6
|
import type { MessageStore } from "@bobfrankston/mailx-types";
|
|
7
7
|
export declare class FileMessageStore implements MessageStore {
|
|
8
8
|
private basePath;
|
|
9
|
-
private folderNames;
|
|
10
9
|
constructor(basePath: string);
|
|
11
|
-
/** Register folder ID → path mapping for human-readable directory names */
|
|
12
|
-
registerFolder(folderId: number, folderPath: string): void;
|
|
13
|
-
private folderDir;
|
|
14
10
|
private messagePath;
|
|
15
|
-
/** Check legacy path (numeric folder ID) */
|
|
16
|
-
private legacyPath;
|
|
17
11
|
putMessage(accountId: string, folderId: number, uid: number, raw: Buffer): Promise<string>;
|
|
18
12
|
getMessage(accountId: string, folderId: number, uid: number): Promise<Buffer>;
|
|
19
13
|
deleteMessage(accountId: string, folderId: number, uid: number): Promise<void>;
|
|
@@ -1,34 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* File-per-message body storage backend.
|
|
3
|
-
* Messages stored as: {basePath}/{accountId}/{
|
|
4
|
-
*
|
|
3
|
+
* Messages stored as: {basePath}/{accountId}/{folderId}/{uid}.eml
|
|
4
|
+
* Folder IDs are numeric (from SQLite), not names.
|
|
5
5
|
*/
|
|
6
6
|
import * as fs from "node:fs";
|
|
7
7
|
import * as path from "node:path";
|
|
8
|
-
/** Sanitize folder path for use as directory name — replace delimiters with _ */
|
|
9
|
-
function sanitizeFolderName(folderPath) {
|
|
10
|
-
return folderPath.replace(/[\/\\.:]/g, "_");
|
|
11
|
-
}
|
|
12
8
|
export class FileMessageStore {
|
|
13
9
|
basePath;
|
|
14
|
-
folderNames = new Map();
|
|
15
10
|
constructor(basePath) {
|
|
16
11
|
this.basePath = basePath;
|
|
17
12
|
fs.mkdirSync(basePath, { recursive: true });
|
|
18
13
|
}
|
|
19
|
-
/** Register folder ID → path mapping for human-readable directory names */
|
|
20
|
-
registerFolder(folderId, folderPath) {
|
|
21
|
-
this.folderNames.set(folderId, sanitizeFolderName(folderPath));
|
|
22
|
-
}
|
|
23
|
-
folderDir(accountId, folderId) {
|
|
24
|
-
const name = this.folderNames.get(folderId) || String(folderId);
|
|
25
|
-
return path.join(this.basePath, accountId, name);
|
|
26
|
-
}
|
|
27
14
|
messagePath(accountId, folderId, uid) {
|
|
28
|
-
return path.join(this.folderDir(accountId, folderId), `${uid}.eml`);
|
|
29
|
-
}
|
|
30
|
-
/** Check legacy path (numeric folder ID) */
|
|
31
|
-
legacyPath(accountId, folderId, uid) {
|
|
32
15
|
return path.join(this.basePath, accountId, String(folderId), `${uid}.eml`);
|
|
33
16
|
}
|
|
34
17
|
async putMessage(accountId, folderId, uid, raw) {
|
|
@@ -38,22 +21,15 @@ export class FileMessageStore {
|
|
|
38
21
|
return filePath;
|
|
39
22
|
}
|
|
40
23
|
async getMessage(accountId, folderId, uid) {
|
|
41
|
-
|
|
42
|
-
if (fs.existsSync(filePath))
|
|
43
|
-
return fs.readFileSync(filePath);
|
|
44
|
-
// Fallback to legacy path
|
|
45
|
-
const legacy = this.legacyPath(accountId, folderId, uid);
|
|
46
|
-
return fs.readFileSync(legacy);
|
|
24
|
+
return fs.readFileSync(this.messagePath(accountId, folderId, uid));
|
|
47
25
|
}
|
|
48
26
|
async deleteMessage(accountId, folderId, uid) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}
|
|
27
|
+
const filePath = this.messagePath(accountId, folderId, uid);
|
|
28
|
+
if (fs.existsSync(filePath))
|
|
29
|
+
fs.unlinkSync(filePath);
|
|
53
30
|
}
|
|
54
31
|
async hasMessage(accountId, folderId, uid) {
|
|
55
|
-
return fs.existsSync(this.messagePath(accountId, folderId, uid))
|
|
56
|
-
fs.existsSync(this.legacyPath(accountId, folderId, uid));
|
|
32
|
+
return fs.existsSync(this.messagePath(accountId, folderId, uid));
|
|
57
33
|
}
|
|
58
34
|
}
|
|
59
35
|
//# sourceMappingURL=file-store.js.map
|
|
@@ -8,7 +8,8 @@ export type AuthMethod = "password" | "oauth2";
|
|
|
8
8
|
/** Mail account configuration */
|
|
9
9
|
export interface AccountConfig {
|
|
10
10
|
id: string; /** Unique account identifier (e.g., "iecc", "gmail-bob") */
|
|
11
|
-
name: string; /**
|
|
11
|
+
name: string; /** Sender name for From header (e.g., "Bob Frankston") */
|
|
12
|
+
label?: string; /** UI label for account list (e.g., "Gmail"). Falls back to name if not set */
|
|
12
13
|
email: string; /** Email address */
|
|
13
14
|
imap: {
|
|
14
15
|
host: string;
|
|
@@ -28,6 +29,7 @@ export interface AccountConfig {
|
|
|
28
29
|
password?: string;
|
|
29
30
|
};
|
|
30
31
|
enabled: boolean;
|
|
32
|
+
defaultSend?: boolean; /** Use this account's SMTP when From doesn't match any account */
|
|
31
33
|
}
|
|
32
34
|
/** Standard IMAP special-use folder types */
|
|
33
35
|
export type SpecialUse = "inbox" | "sent" | "drafts" | "trash" | "junk" | "archive" | "all";
|