@bobfrankston/mailx 1.0.159 → 1.0.160
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 +2 -2
- package/bin/mailx.js +7 -6
- package/client/lib/mailxapi.js +35 -28
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -200,10 +200,10 @@ Under **Settings** in the toolbar:
|
|
|
200
200
|
|
|
201
201
|
```
|
|
202
202
|
mailx Start the app (native window via IPC)
|
|
203
|
-
mailx --
|
|
204
|
-
mailx --no-browser Server mode without opening browser
|
|
203
|
+
mailx --email <addr> First-time setup with this email (skips prompt)
|
|
205
204
|
mailx --verbose Show log output in terminal (default: log file only)
|
|
206
205
|
mailx --import <file> Import accounts.jsonc into Google Drive
|
|
206
|
+
mailx --server Start HTTP server for dev/remote (http://localhost:9333)
|
|
207
207
|
|
|
208
208
|
mailx -kill Kill running mailx processes + clean up WAL files
|
|
209
209
|
mailx -repair Re-sync message metadata (fix garbled subjects)
|
package/bin/mailx.js
CHANGED
|
@@ -35,7 +35,7 @@ const rebuildMode = hasFlag("rebuild");
|
|
|
35
35
|
const repairMode = hasFlag("repair");
|
|
36
36
|
const importMode = hasFlag("import");
|
|
37
37
|
// Validate arguments
|
|
38
|
-
const knownFlags = ["server", "no-browser", "verbose", "external", "kill", "v", "version", "setup", "add", "test", "rebuild", "repair", "native-imap", "log", "import", "email"];
|
|
38
|
+
const knownFlags = ["server", "no-browser", "verbose", "external", "kill", "v", "version", "setup", "add", "test", "rebuild", "repair", "native-imap", "log", "import", "email", "mail"];
|
|
39
39
|
for (const arg of args) {
|
|
40
40
|
const flag = arg.replace(/^--?/, "");
|
|
41
41
|
if (arg.startsWith("-") && !knownFlags.includes(flag)) {
|
|
@@ -599,9 +599,11 @@ async function main() {
|
|
|
599
599
|
if (setupMode || !hasConfig()) {
|
|
600
600
|
if (!setupMode)
|
|
601
601
|
console.log("No mailx configuration found.");
|
|
602
|
-
// --email flag skips the interactive prompt
|
|
602
|
+
// --email (or -mail) flag skips the interactive prompt
|
|
603
603
|
const emailArg = args.find(a => a.startsWith("--email="))?.split("=")[1]
|
|
604
|
-
|| (
|
|
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);
|
|
605
607
|
await runSetup(emailArg);
|
|
606
608
|
}
|
|
607
609
|
// Redirect console to log file — keep terminal clean
|
|
@@ -708,9 +710,8 @@ async function main() {
|
|
|
708
710
|
imapManager.on("accountError", (accountId, error, hint, isOAuth) => {
|
|
709
711
|
handle.send({ _event: "accountError", type: "accountError", accountId, error, hint, isOAuth });
|
|
710
712
|
});
|
|
711
|
-
//
|
|
712
|
-
await new Promise(r => setTimeout(r,
|
|
713
|
-
handle.send({ _event: "ready", type: "ready" });
|
|
713
|
+
// Brief pause for WebView2 to initialize before starting IMAP (avoids stdin writes during init)
|
|
714
|
+
await new Promise(r => setTimeout(r, 500));
|
|
714
715
|
// Register all accounts (OAuth may open browser for Gmail — event loop stays free for IPC)
|
|
715
716
|
for (const account of settings.accounts) {
|
|
716
717
|
if (!account.enabled)
|
package/client/lib/mailxapi.js
CHANGED
|
@@ -12,9 +12,6 @@
|
|
|
12
12
|
var _callbacks = {};
|
|
13
13
|
var _callbackId = 0;
|
|
14
14
|
var _eventHandlers = [];
|
|
15
|
-
var _ready = false;
|
|
16
|
-
var _pendingCalls = []; // buffered until server sends "ready"
|
|
17
|
-
|
|
18
15
|
function callNode(action, params) {
|
|
19
16
|
var id = String(++_callbackId);
|
|
20
17
|
return new Promise(function(resolve, reject) {
|
|
@@ -24,11 +21,6 @@
|
|
|
24
21
|
}, 120000);
|
|
25
22
|
_callbacks[id] = { resolve: resolve, reject: reject, timer: timer };
|
|
26
23
|
var msg = Object.assign({ _action: action, _cbid: id }, params || {});
|
|
27
|
-
if (!_ready) {
|
|
28
|
-
// Buffer until server is ready (early calls are lost in the pipe)
|
|
29
|
-
_pendingCalls.push(msg);
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
24
|
if (window.ipc && window.ipc.postMessage) {
|
|
33
25
|
window.ipc.postMessage(JSON.stringify(msg));
|
|
34
26
|
} else {
|
|
@@ -39,20 +31,6 @@
|
|
|
39
31
|
});
|
|
40
32
|
}
|
|
41
33
|
|
|
42
|
-
function flushPending() {
|
|
43
|
-
_ready = true;
|
|
44
|
-
var pending = _pendingCalls.splice(0);
|
|
45
|
-
// Send diagnostic so it shows in Node.js IPC log
|
|
46
|
-
if (window.ipc && window.ipc.postMessage) {
|
|
47
|
-
window.ipc.postMessage(JSON.stringify({ _action: "_debug", _cbid: "0", info: "flush " + pending.length + " calls: " + pending.map(function(m) { return m._action; }).join(", ") }));
|
|
48
|
-
}
|
|
49
|
-
for (var i = 0; i < pending.length; i++) {
|
|
50
|
-
if (window.ipc && window.ipc.postMessage) {
|
|
51
|
-
window.ipc.postMessage(JSON.stringify(pending[i]));
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
34
|
// Called by Rust to resolve promises
|
|
57
35
|
window._mailxapiResolve = function(id, value) {
|
|
58
36
|
var cb = _callbacks[id];
|
|
@@ -73,11 +51,6 @@
|
|
|
73
51
|
|
|
74
52
|
// Called by Rust to push events (new mail, sync progress, etc.)
|
|
75
53
|
window._mailxapiEvent = function(event) {
|
|
76
|
-
// "ready" signal from server — flush buffered IPC calls
|
|
77
|
-
if (event && event.type === "ready") {
|
|
78
|
-
flushPending();
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
54
|
for (var i = 0; i < _eventHandlers.length; i++) {
|
|
82
55
|
try { _eventHandlers[i](event); } catch(e) { /* ignore */ }
|
|
83
56
|
}
|
|
@@ -132,13 +105,47 @@
|
|
|
132
105
|
syncAll: function() { return callNode("syncAll"); },
|
|
133
106
|
getSyncPending: function() { return callNode("getSyncPending"); },
|
|
134
107
|
|
|
108
|
+
// Bulk operations
|
|
109
|
+
deleteMessages: function(accountId, uids) {
|
|
110
|
+
return callNode("deleteMessages", { accountId: accountId, uids: uids });
|
|
111
|
+
},
|
|
112
|
+
moveMessage: function(accountId, uid, targetFolderId, targetAccountId) {
|
|
113
|
+
return callNode("moveMessage", { accountId: accountId, uid: uid, targetFolderId: targetFolderId, targetAccountId: targetAccountId });
|
|
114
|
+
},
|
|
115
|
+
moveMessages: function(accountId, uids, targetFolderId) {
|
|
116
|
+
return callNode("moveMessages", { accountId: accountId, uids: uids, targetFolderId: targetFolderId });
|
|
117
|
+
},
|
|
118
|
+
markFolderRead: function(accountId, folderId) {
|
|
119
|
+
return callNode("markFolderRead", { folderId: folderId });
|
|
120
|
+
},
|
|
121
|
+
createFolder: function(accountId, parentPath, name) {
|
|
122
|
+
return callNode("createFolder", { accountId: accountId, parentPath: parentPath, name: name });
|
|
123
|
+
},
|
|
124
|
+
renameFolder: function(accountId, folderId, newName) {
|
|
125
|
+
return callNode("renameFolder", { accountId: accountId, folderId: folderId, newName: newName });
|
|
126
|
+
},
|
|
127
|
+
deleteFolder: function(accountId, folderId) {
|
|
128
|
+
return callNode("deleteFolder", { accountId: accountId, folderId: folderId });
|
|
129
|
+
},
|
|
130
|
+
emptyFolder: function(accountId, folderId) {
|
|
131
|
+
return callNode("emptyFolder", { accountId: accountId, folderId: folderId });
|
|
132
|
+
},
|
|
133
|
+
|
|
135
134
|
// Settings
|
|
136
135
|
allowRemoteContent: function(type, value) {
|
|
137
136
|
return callNode("allowRemoteContent", { type: type, value: value });
|
|
138
137
|
},
|
|
139
138
|
getSettings: function() { return callNode("getSettings"); },
|
|
140
|
-
|
|
139
|
+
saveSettingsData: function(data) { return callNode("saveSettingsData", data); },
|
|
141
140
|
getVersion: function() { return callNode("getVersion"); },
|
|
141
|
+
getAutocompleteSettings: function() { return callNode("getAutocompleteSettings"); },
|
|
142
|
+
saveAutocompleteSettings: function(settings) { return callNode("saveAutocompleteSettings", settings); },
|
|
143
|
+
|
|
144
|
+
// Setup & Repair
|
|
145
|
+
setupAccount: function(name, email, password) {
|
|
146
|
+
return callNode("setupAccount", { name: name, email: email, password: password });
|
|
147
|
+
},
|
|
148
|
+
repairAccounts: function() { return callNode("repairAccounts"); },
|
|
142
149
|
|
|
143
150
|
// Events
|
|
144
151
|
onEvent: function(handler) { _eventHandlers.push(handler); },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bobfrankston/mailx",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.160",
|
|
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,10 @@
|
|
|
20
20
|
"postinstall": "node bin/postinstall.js"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@bobfrankston/iflow": "^1.0.
|
|
23
|
+
"@bobfrankston/iflow": "^1.0.55",
|
|
24
24
|
"@bobfrankston/miscinfo": "^1.0.7",
|
|
25
25
|
"@bobfrankston/oauthsupport": "^1.0.20",
|
|
26
|
-
"@bobfrankston/msger": "^0.1.
|
|
26
|
+
"@bobfrankston/msger": "^0.1.210",
|
|
27
27
|
"@capacitor/android": "^8.3.0",
|
|
28
28
|
"@capacitor/cli": "^8.3.0",
|
|
29
29
|
"@capacitor/core": "^8.3.0",
|