@bobfrankston/mailx 1.0.451 → 1.0.453
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.map +1 -0
- package/bin/mailx.ts +1498 -0
- package/bin/postinstall.js.map +1 -0
- package/bin/postinstall.ts +41 -0
- package/bin/tsconfig.json +10 -0
- package/client/.gitattributes +10 -0
- package/client/app.js +51 -2
- package/client/app.js.map +1 -0
- package/client/app.ts +3112 -0
- package/client/components/address-book.js.map +1 -0
- package/client/components/address-book.ts +204 -0
- package/client/components/alarms.js.map +1 -0
- package/client/components/alarms.ts +276 -0
- package/client/components/calendar-sidebar.js.map +1 -0
- package/client/components/calendar-sidebar.ts +474 -0
- package/client/components/calendar.js.map +1 -0
- package/client/components/calendar.ts +211 -0
- package/client/components/context-menu.js.map +1 -0
- package/client/components/context-menu.ts +95 -0
- package/client/components/folder-picker.js.map +1 -0
- package/client/components/folder-picker.ts +127 -0
- package/client/components/folder-tree.js.map +1 -0
- package/client/components/folder-tree.ts +1069 -0
- package/client/components/message-list.js.map +1 -0
- package/client/components/message-list.ts +1129 -0
- package/client/components/message-viewer.js.map +1 -0
- package/client/components/message-viewer.ts +1257 -0
- package/client/components/outbox-view.js.map +1 -0
- package/client/components/outbox-view.ts +102 -0
- package/client/components/tasks.js.map +1 -0
- package/client/components/tasks.ts +234 -0
- package/client/compose/compose.js.map +1 -0
- package/client/compose/compose.ts +1231 -0
- package/client/compose/editor.js.map +1 -0
- package/client/compose/editor.ts +599 -0
- package/client/compose/ghost-text.js.map +1 -0
- package/client/compose/ghost-text.ts +140 -0
- package/client/index.html +1 -0
- package/client/lib/android-bootstrap.js.map +1 -0
- package/client/lib/android-bootstrap.ts +9 -0
- package/client/lib/api-client.js.map +1 -0
- package/client/lib/api-client.ts +439 -0
- package/client/lib/local-service.js.map +1 -0
- package/client/lib/local-service.ts +646 -0
- package/client/lib/local-store.js.map +1 -0
- package/client/lib/local-store.ts +283 -0
- package/client/lib/message-state.js.map +1 -0
- package/client/lib/message-state.ts +140 -0
- package/client/tsconfig.json +19 -0
- package/package.json +18 -16
- package/packages/mailx-api/.gitattributes +10 -0
- package/packages/mailx-api/index.d.ts.map +1 -0
- package/packages/mailx-api/index.js.map +1 -0
- package/packages/mailx-api/index.ts +283 -0
- package/packages/mailx-api/package.json +1 -1
- package/packages/mailx-api/tsconfig.json +9 -0
- package/packages/mailx-compose/.gitattributes +10 -0
- package/packages/mailx-compose/index.d.ts.map +1 -0
- package/packages/mailx-compose/index.js.map +1 -0
- package/packages/mailx-compose/index.ts +85 -0
- package/packages/mailx-compose/tsconfig.json +9 -0
- package/packages/mailx-core/index.d.ts.map +1 -0
- package/packages/mailx-core/index.js.map +1 -0
- package/packages/mailx-core/index.ts +424 -0
- package/packages/mailx-core/ipc.d.ts.map +1 -0
- package/packages/mailx-core/ipc.js.map +1 -0
- package/packages/mailx-core/ipc.ts +62 -0
- package/packages/mailx-core/package.json +1 -1
- package/packages/mailx-core/tsconfig.json +9 -0
- package/packages/mailx-host/.gitattributes +10 -0
- package/packages/mailx-host/index.d.ts.map +1 -0
- package/packages/mailx-host/index.js.map +1 -0
- package/packages/mailx-host/index.ts +38 -0
- package/packages/mailx-host/package.json +10 -2
- package/packages/mailx-host/tsconfig.json +9 -0
- package/packages/mailx-send/.gitattributes +10 -0
- package/packages/mailx-send/cli-queue.d.ts.map +1 -0
- package/packages/mailx-send/cli-queue.js.map +1 -0
- package/packages/mailx-send/cli-queue.ts +62 -0
- package/packages/mailx-send/cli-send.d.ts.map +1 -0
- package/packages/mailx-send/cli-send.js.map +1 -0
- package/packages/mailx-send/cli-send.ts +83 -0
- package/packages/mailx-send/cli.d.ts.map +1 -0
- package/packages/mailx-send/cli.js.map +1 -0
- package/packages/mailx-send/cli.ts +126 -0
- package/packages/mailx-send/index.d.ts.map +1 -0
- package/packages/mailx-send/index.js.map +1 -0
- package/packages/mailx-send/index.ts +333 -0
- package/packages/mailx-send/mailsend/cli.d.ts.map +1 -0
- package/packages/mailx-send/mailsend/cli.js.map +1 -0
- package/packages/mailx-send/mailsend/cli.ts +81 -0
- package/packages/mailx-send/mailsend/index.d.ts.map +1 -0
- package/packages/mailx-send/mailsend/index.js.map +1 -0
- package/packages/mailx-send/mailsend/index.ts +333 -0
- package/packages/mailx-send/mailsend/package-lock.json +65 -0
- package/packages/mailx-send/mailsend/tsconfig.json +21 -0
- package/packages/mailx-send/package-lock.json +65 -0
- package/packages/mailx-send/package.json +1 -1
- package/packages/mailx-send/tsconfig.json +21 -0
- package/packages/mailx-server/.gitattributes +10 -0
- package/packages/mailx-server/index.d.ts.map +1 -0
- package/packages/mailx-server/index.js.map +1 -0
- package/packages/mailx-server/index.ts +429 -0
- package/packages/mailx-server/package.json +1 -1
- package/packages/mailx-server/tsconfig.json +9 -0
- package/packages/mailx-service/google-sync.d.ts.map +1 -0
- package/packages/mailx-service/google-sync.js.map +1 -0
- package/packages/mailx-service/google-sync.ts +238 -0
- package/packages/mailx-service/index.d.ts.map +1 -0
- package/packages/mailx-service/index.js.map +1 -0
- package/packages/mailx-service/index.ts +2461 -0
- package/packages/mailx-service/jsonrpc.d.ts.map +1 -0
- package/packages/mailx-service/jsonrpc.js.map +1 -0
- package/packages/mailx-service/jsonrpc.ts +268 -0
- package/packages/mailx-service/package.json +1 -1
- package/packages/mailx-service/tsconfig.json +9 -0
- package/packages/mailx-settings/.gitattributes +10 -0
- package/packages/mailx-settings/cloud.d.ts.map +1 -0
- package/packages/mailx-settings/cloud.js.map +1 -0
- package/packages/mailx-settings/cloud.ts +388 -0
- package/packages/mailx-settings/index.d.ts.map +1 -0
- package/packages/mailx-settings/index.js.map +1 -0
- package/packages/mailx-settings/index.ts +892 -0
- package/packages/mailx-settings/package.json +1 -1
- package/packages/mailx-settings/tsconfig.json +9 -0
- package/packages/mailx-store/.gitattributes +10 -0
- package/packages/mailx-store/db.d.ts.map +1 -0
- package/packages/mailx-store/db.js.map +1 -0
- package/packages/mailx-store/db.ts +2007 -0
- package/packages/mailx-store/file-store.d.ts.map +1 -0
- package/packages/mailx-store/file-store.js.map +1 -0
- package/packages/mailx-store/file-store.ts +82 -0
- package/packages/mailx-store/index.d.ts.map +1 -0
- package/packages/mailx-store/index.js.map +1 -0
- package/packages/mailx-store/index.ts +7 -0
- package/packages/mailx-store/package.json +1 -1
- package/packages/mailx-store/tsconfig.json +9 -0
- package/packages/mailx-store-web/android-bootstrap.d.ts.map +1 -0
- package/packages/mailx-store-web/android-bootstrap.js.map +1 -0
- package/packages/mailx-store-web/android-bootstrap.ts +1262 -0
- package/packages/mailx-store-web/db.d.ts.map +1 -0
- package/packages/mailx-store-web/db.js.map +1 -0
- package/packages/mailx-store-web/db.ts +756 -0
- package/packages/mailx-store-web/gmail-api-web.d.ts.map +1 -0
- package/packages/mailx-store-web/gmail-api-web.js.map +1 -0
- package/packages/mailx-store-web/gmail-api-web.ts +11 -0
- package/packages/mailx-store-web/imap-web-provider.d.ts.map +1 -0
- package/packages/mailx-store-web/imap-web-provider.js.map +1 -0
- package/packages/mailx-store-web/imap-web-provider.ts +156 -0
- package/packages/mailx-store-web/index.d.ts.map +1 -0
- package/packages/mailx-store-web/index.js.map +1 -0
- package/packages/mailx-store-web/index.ts +10 -0
- package/packages/mailx-store-web/main-thread-host.d.ts.map +1 -0
- package/packages/mailx-store-web/main-thread-host.js.map +1 -0
- package/packages/mailx-store-web/main-thread-host.ts +322 -0
- package/packages/mailx-store-web/package.json +4 -4
- package/packages/mailx-store-web/provider-types.d.ts.map +1 -0
- package/packages/mailx-store-web/provider-types.js.map +1 -0
- package/packages/mailx-store-web/provider-types.ts +7 -0
- package/packages/mailx-store-web/sync-manager.d.ts.map +1 -0
- package/packages/mailx-store-web/sync-manager.js.map +1 -0
- package/packages/mailx-store-web/sync-manager.ts +508 -0
- package/packages/mailx-store-web/tsconfig.json +10 -0
- package/packages/mailx-store-web/web-jsonrpc.d.ts.map +1 -0
- package/packages/mailx-store-web/web-jsonrpc.js.map +1 -0
- package/packages/mailx-store-web/web-jsonrpc.ts +116 -0
- package/packages/mailx-store-web/web-message-store.d.ts.map +1 -0
- package/packages/mailx-store-web/web-message-store.js.map +1 -0
- package/packages/mailx-store-web/web-message-store.ts +97 -0
- package/packages/mailx-store-web/web-service.d.ts.map +1 -0
- package/packages/mailx-store-web/web-service.js.map +1 -0
- package/packages/mailx-store-web/web-service.ts +616 -0
- package/packages/mailx-store-web/web-settings.d.ts.map +1 -0
- package/packages/mailx-store-web/web-settings.js.map +1 -0
- package/packages/mailx-store-web/web-settings.ts +522 -0
- package/packages/mailx-store-web/worker-entry.d.ts.map +1 -0
- package/packages/mailx-store-web/worker-entry.js.map +1 -0
- package/packages/mailx-store-web/worker-entry.ts +215 -0
- package/packages/mailx-store-web/worker-tcp-transport.d.ts.map +1 -0
- package/packages/mailx-store-web/worker-tcp-transport.js.map +1 -0
- package/packages/mailx-store-web/worker-tcp-transport.ts +101 -0
- package/packages/mailx-types/.gitattributes +10 -0
- package/packages/mailx-types/index.d.ts.map +1 -0
- package/packages/mailx-types/index.js.map +1 -0
- package/packages/mailx-types/index.ts +498 -0
- package/packages/mailx-types/package.json +1 -1
- package/packages/mailx-types/tsconfig.json +9 -0
- package/tsconfig.base.json +2 -1
- package/tsconfig.json +9 -0
- package/build-apk.cmd +0 -3
- package/npmg.bat +0 -6
- package/packages/mailx-imap/index.d.ts +0 -442
- package/packages/mailx-imap/index.js +0 -3684
- package/packages/mailx-imap/package.json +0 -25
- package/packages/mailx-imap/providers/gmail-api.d.ts +0 -8
- package/packages/mailx-imap/providers/gmail-api.js +0 -8
- package/packages/mailx-imap/providers/types.d.ts +0 -9
- package/packages/mailx-imap/providers/types.js +0 -9
- package/packages/mailx-imap/tsconfig.tsbuildinfo +0 -1
- package/rebuild.cmd +0 -23
- package/tdview.cmd +0 -2
- package/temp.ps1 +0 -10
- package/test-smtp-direct.mjs +0 -4
- package/unbash.cmd +0 -55
- package/unwedge.cmd +0 -1
|
@@ -0,0 +1,522 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser-compatible settings for Android/WebView.
|
|
3
|
+
* Replaces @bobfrankston/mailx-settings which depends on node:fs.
|
|
4
|
+
*
|
|
5
|
+
* Settings are stored in IndexedDB and synced to Google Drive
|
|
6
|
+
* via the GDrive API (same API as desktop cloud mode).
|
|
7
|
+
*
|
|
8
|
+
* On first run, settings are fetched from GDrive. Subsequent reads
|
|
9
|
+
* use the local IndexedDB cache. Writes go to both.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import type { AccountConfig, MailxSettings, AutocompleteSettings } from "@bobfrankston/mailx-types";
|
|
13
|
+
|
|
14
|
+
const IDB_NAME = "mailx-settings";
|
|
15
|
+
const IDB_VERSION = 1;
|
|
16
|
+
const STORE_NAME = "files";
|
|
17
|
+
|
|
18
|
+
// ── IndexedDB helpers ──
|
|
19
|
+
|
|
20
|
+
function openSettingsDb(): Promise<IDBDatabase> {
|
|
21
|
+
return new Promise((resolve, reject) => {
|
|
22
|
+
const req = indexedDB.open(IDB_NAME, IDB_VERSION);
|
|
23
|
+
req.onupgradeneeded = () => {
|
|
24
|
+
const db = req.result;
|
|
25
|
+
if (!db.objectStoreNames.contains(STORE_NAME)) {
|
|
26
|
+
db.createObjectStore(STORE_NAME);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
req.onsuccess = () => resolve(req.result);
|
|
30
|
+
req.onerror = () => reject(req.error);
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function idbRead(key: string): Promise<string | null> {
|
|
35
|
+
const db = await openSettingsDb();
|
|
36
|
+
return new Promise((resolve, reject) => {
|
|
37
|
+
const tx = db.transaction(STORE_NAME, "readonly");
|
|
38
|
+
const req = tx.objectStore(STORE_NAME).get(key);
|
|
39
|
+
req.onsuccess = () => resolve(req.result as string | null);
|
|
40
|
+
req.onerror = () => reject(req.error);
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function idbWrite(key: string, value: string): Promise<void> {
|
|
45
|
+
const db = await openSettingsDb();
|
|
46
|
+
return new Promise((resolve, reject) => {
|
|
47
|
+
const tx = db.transaction(STORE_NAME, "readwrite");
|
|
48
|
+
tx.objectStore(STORE_NAME).put(value, key);
|
|
49
|
+
tx.oncomplete = () => resolve();
|
|
50
|
+
tx.onerror = () => reject(tx.error);
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async function idbDelete(key: string): Promise<void> {
|
|
55
|
+
const db = await openSettingsDb();
|
|
56
|
+
return new Promise((resolve, reject) => {
|
|
57
|
+
const tx = db.transaction(STORE_NAME, "readwrite");
|
|
58
|
+
tx.objectStore(STORE_NAME).delete(key);
|
|
59
|
+
tx.oncomplete = () => resolve();
|
|
60
|
+
tx.onerror = () => reject(tx.error);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// ── GDrive API ──
|
|
65
|
+
|
|
66
|
+
/** GDrive folder ID for the "mailx" app folder */
|
|
67
|
+
let gDriveFolderId: string | null = null;
|
|
68
|
+
/** OAuth token provider — set by bootstrap */
|
|
69
|
+
let tokenProvider: (() => Promise<string>) | null = null;
|
|
70
|
+
|
|
71
|
+
export function setGDriveTokenProvider(provider: () => Promise<string>): void {
|
|
72
|
+
tokenProvider = provider;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function setGDriveFolderId(folderId: string): void {
|
|
76
|
+
gDriveFolderId = folderId;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async function gDriveRead(filename: string): Promise<string | null> {
|
|
80
|
+
if (!tokenProvider || !gDriveFolderId) return null;
|
|
81
|
+
try {
|
|
82
|
+
const token = await tokenProvider();
|
|
83
|
+
// Find file by name in folder
|
|
84
|
+
const q = encodeURIComponent(`name='${filename}' and '${gDriveFolderId}' in parents and trashed=false`);
|
|
85
|
+
const listRes = await globalThis.fetch(
|
|
86
|
+
`https://www.googleapis.com/drive/v3/files?q=${q}&fields=files(id)`,
|
|
87
|
+
{ headers: { "Authorization": `Bearer ${token}` } }
|
|
88
|
+
);
|
|
89
|
+
if (!listRes.ok) return null;
|
|
90
|
+
const listData = await listRes.json() as any;
|
|
91
|
+
const fileId = listData.files?.[0]?.id;
|
|
92
|
+
if (!fileId) return null;
|
|
93
|
+
// Download content
|
|
94
|
+
const res = await globalThis.fetch(
|
|
95
|
+
`https://www.googleapis.com/drive/v3/files/${fileId}?alt=media`,
|
|
96
|
+
{ headers: { "Authorization": `Bearer ${token}` } }
|
|
97
|
+
);
|
|
98
|
+
if (!res.ok) return null;
|
|
99
|
+
return res.text();
|
|
100
|
+
} catch (e: any) {
|
|
101
|
+
console.error(`[settings] GDrive read ${filename}: ${e.message}`);
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async function gDriveWrite(filename: string, content: string): Promise<boolean> {
|
|
107
|
+
if (!tokenProvider || !gDriveFolderId) return false;
|
|
108
|
+
try {
|
|
109
|
+
const token = await tokenProvider();
|
|
110
|
+
// Check if file exists
|
|
111
|
+
const q = encodeURIComponent(`name='${filename}' and '${gDriveFolderId}' in parents and trashed=false`);
|
|
112
|
+
const listRes = await globalThis.fetch(
|
|
113
|
+
`https://www.googleapis.com/drive/v3/files?q=${q}&fields=files(id)`,
|
|
114
|
+
{ headers: { "Authorization": `Bearer ${token}` } }
|
|
115
|
+
);
|
|
116
|
+
if (!listRes.ok) return false;
|
|
117
|
+
const listData = await listRes.json() as any;
|
|
118
|
+
const fileId = listData.files?.[0]?.id;
|
|
119
|
+
|
|
120
|
+
if (fileId) {
|
|
121
|
+
// Update existing
|
|
122
|
+
const res = await globalThis.fetch(
|
|
123
|
+
`https://www.googleapis.com/upload/drive/v3/files/${fileId}?uploadType=media`,
|
|
124
|
+
{
|
|
125
|
+
method: "PATCH",
|
|
126
|
+
headers: {
|
|
127
|
+
"Authorization": `Bearer ${token}`,
|
|
128
|
+
"Content-Type": "application/json",
|
|
129
|
+
},
|
|
130
|
+
body: content,
|
|
131
|
+
}
|
|
132
|
+
);
|
|
133
|
+
return res.ok;
|
|
134
|
+
} else {
|
|
135
|
+
// Create new
|
|
136
|
+
const metadata = JSON.stringify({
|
|
137
|
+
name: filename,
|
|
138
|
+
parents: [gDriveFolderId],
|
|
139
|
+
mimeType: "application/json",
|
|
140
|
+
});
|
|
141
|
+
const boundary = "----mailx" + Date.now();
|
|
142
|
+
const body = `--${boundary}\r\nContent-Type: application/json; charset=UTF-8\r\n\r\n${metadata}\r\n--${boundary}\r\nContent-Type: application/json\r\n\r\n${content}\r\n--${boundary}--`;
|
|
143
|
+
const res = await globalThis.fetch(
|
|
144
|
+
"https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart",
|
|
145
|
+
{
|
|
146
|
+
method: "POST",
|
|
147
|
+
headers: {
|
|
148
|
+
"Authorization": `Bearer ${token}`,
|
|
149
|
+
"Content-Type": `multipart/related; boundary=${boundary}`,
|
|
150
|
+
},
|
|
151
|
+
body,
|
|
152
|
+
}
|
|
153
|
+
);
|
|
154
|
+
return res.ok;
|
|
155
|
+
}
|
|
156
|
+
} catch (e: any) {
|
|
157
|
+
console.error(`[settings] GDrive write ${filename}: ${e.message}`);
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// ── Provider defaults (same as desktop mailx-settings) ──
|
|
163
|
+
|
|
164
|
+
interface ProviderDefaults {
|
|
165
|
+
label: string;
|
|
166
|
+
imap: { host: string; port: number; tls: boolean; auth: "password" | "oauth2" };
|
|
167
|
+
smtp: { host: string; port: number; tls: boolean; auth: "password" | "oauth2" };
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const PROVIDERS: Record<string, ProviderDefaults> = {
|
|
171
|
+
"gmail.com": {
|
|
172
|
+
label: "Gmail",
|
|
173
|
+
imap: { host: "imap.gmail.com", port: 993, tls: true, auth: "oauth2" },
|
|
174
|
+
smtp: { host: "smtp.gmail.com", port: 587, tls: true, auth: "oauth2" },
|
|
175
|
+
},
|
|
176
|
+
"googlemail.com": {
|
|
177
|
+
label: "Gmail",
|
|
178
|
+
imap: { host: "imap.gmail.com", port: 993, tls: true, auth: "oauth2" },
|
|
179
|
+
smtp: { host: "smtp.gmail.com", port: 587, tls: true, auth: "oauth2" },
|
|
180
|
+
},
|
|
181
|
+
"outlook.com": {
|
|
182
|
+
label: "Outlook",
|
|
183
|
+
imap: { host: "outlook.office365.com", port: 993, tls: true, auth: "oauth2" },
|
|
184
|
+
smtp: { host: "smtp.office365.com", port: 587, tls: true, auth: "oauth2" },
|
|
185
|
+
},
|
|
186
|
+
"hotmail.com": {
|
|
187
|
+
label: "Hotmail",
|
|
188
|
+
imap: { host: "outlook.office365.com", port: 993, tls: true, auth: "oauth2" },
|
|
189
|
+
smtp: { host: "smtp.office365.com", port: 587, tls: true, auth: "oauth2" },
|
|
190
|
+
},
|
|
191
|
+
"yahoo.com": {
|
|
192
|
+
label: "Yahoo",
|
|
193
|
+
imap: { host: "imap.mail.yahoo.com", port: 993, tls: true, auth: "password" },
|
|
194
|
+
smtp: { host: "smtp.mail.yahoo.com", port: 587, tls: true, auth: "password" },
|
|
195
|
+
},
|
|
196
|
+
"icloud.com": {
|
|
197
|
+
label: "iCloud",
|
|
198
|
+
imap: { host: "imap.mail.me.com", port: 993, tls: true, auth: "password" },
|
|
199
|
+
smtp: { host: "smtp.mail.me.com", port: 587, tls: true, auth: "password" },
|
|
200
|
+
},
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
function normalizeAccount(acct: any, globalName?: string): AccountConfig {
|
|
204
|
+
const email = acct.email || "";
|
|
205
|
+
const domain = email.split("@")[1]?.toLowerCase() || "";
|
|
206
|
+
const provider = PROVIDERS[domain];
|
|
207
|
+
const user = acct.imap?.user || acct.user || email;
|
|
208
|
+
|
|
209
|
+
return {
|
|
210
|
+
id: acct.id || domain.split(".")[0] || "account",
|
|
211
|
+
name: acct.name || globalName || email.split("@")[0],
|
|
212
|
+
label: acct.label || provider?.label,
|
|
213
|
+
email,
|
|
214
|
+
imap: {
|
|
215
|
+
host: acct.imap?.host || provider?.imap.host || `imap.${domain}`,
|
|
216
|
+
port: acct.imap?.port || provider?.imap.port || 993,
|
|
217
|
+
tls: acct.imap?.tls ?? provider?.imap.tls ?? true,
|
|
218
|
+
auth: acct.imap?.auth || provider?.imap.auth || "password",
|
|
219
|
+
user: acct.imap?.user || user,
|
|
220
|
+
password: acct.imap?.password || acct.password,
|
|
221
|
+
},
|
|
222
|
+
smtp: {
|
|
223
|
+
host: acct.smtp?.host || provider?.smtp.host || `smtp.${domain}`,
|
|
224
|
+
port: acct.smtp?.port || provider?.smtp.port || 587,
|
|
225
|
+
tls: acct.smtp?.tls ?? provider?.smtp.tls ?? true,
|
|
226
|
+
auth: acct.smtp?.auth || provider?.smtp.auth || "password",
|
|
227
|
+
user: acct.smtp?.user || user,
|
|
228
|
+
password: acct.smtp?.password || acct.password,
|
|
229
|
+
},
|
|
230
|
+
enabled: acct.enabled ?? true,
|
|
231
|
+
defaultSend: acct.defaultSend,
|
|
232
|
+
syncContacts: acct.syncContacts ?? (provider?.imap.auth === "oauth2"),
|
|
233
|
+
relayDomains: acct.relayDomains,
|
|
234
|
+
deliveredToPrefix: acct.deliveredToPrefix,
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// ── Default settings ──
|
|
239
|
+
|
|
240
|
+
const DEFAULT_PREFERENCES = {
|
|
241
|
+
ui: {
|
|
242
|
+
theme: "system" as const,
|
|
243
|
+
editor: "quill" as const,
|
|
244
|
+
folderWidth: 220,
|
|
245
|
+
listViewerSplit: 40,
|
|
246
|
+
fontSize: 15,
|
|
247
|
+
},
|
|
248
|
+
sync: {
|
|
249
|
+
intervalMinutes: 5,
|
|
250
|
+
historyDays: 30,
|
|
251
|
+
prefetch: true,
|
|
252
|
+
},
|
|
253
|
+
autocomplete: {
|
|
254
|
+
enabled: false,
|
|
255
|
+
provider: "off" as const,
|
|
256
|
+
ollamaUrl: "",
|
|
257
|
+
ollamaModel: "",
|
|
258
|
+
cloudApiKey: "",
|
|
259
|
+
cloudModel: "",
|
|
260
|
+
debounceMs: 600,
|
|
261
|
+
maxTokens: 60,
|
|
262
|
+
},
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
const DEFAULT_ALLOWLIST = {
|
|
266
|
+
senders: [] as string[],
|
|
267
|
+
domains: [] as string[],
|
|
268
|
+
recipients: [] as string[],
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
// ── JSONC parser (strips comments and trailing commas) ──
|
|
272
|
+
|
|
273
|
+
function parseJsonc(text: string): any {
|
|
274
|
+
// Strip /* block comments */ and // line comments, but preserve content inside strings
|
|
275
|
+
let stripped = "";
|
|
276
|
+
let i = 0;
|
|
277
|
+
let inString = false;
|
|
278
|
+
let stringChar = "";
|
|
279
|
+
while (i < text.length) {
|
|
280
|
+
const c = text[i];
|
|
281
|
+
const next = text[i + 1];
|
|
282
|
+
if (inString) {
|
|
283
|
+
stripped += c;
|
|
284
|
+
if (c === "\\" && i + 1 < text.length) {
|
|
285
|
+
stripped += text[i + 1];
|
|
286
|
+
i += 2;
|
|
287
|
+
continue;
|
|
288
|
+
}
|
|
289
|
+
if (c === stringChar) inString = false;
|
|
290
|
+
i++;
|
|
291
|
+
continue;
|
|
292
|
+
}
|
|
293
|
+
if (c === '"' || c === "'") {
|
|
294
|
+
inString = true;
|
|
295
|
+
stringChar = c;
|
|
296
|
+
stripped += c;
|
|
297
|
+
i++;
|
|
298
|
+
continue;
|
|
299
|
+
}
|
|
300
|
+
if (c === "/" && next === "/") {
|
|
301
|
+
// Line comment — skip to end of line
|
|
302
|
+
while (i < text.length && text[i] !== "\n") i++;
|
|
303
|
+
continue;
|
|
304
|
+
}
|
|
305
|
+
if (c === "/" && next === "*") {
|
|
306
|
+
// Block comment — skip to */
|
|
307
|
+
i += 2;
|
|
308
|
+
while (i < text.length - 1 && !(text[i] === "*" && text[i + 1] === "/")) i++;
|
|
309
|
+
i += 2;
|
|
310
|
+
continue;
|
|
311
|
+
}
|
|
312
|
+
stripped += c;
|
|
313
|
+
i++;
|
|
314
|
+
}
|
|
315
|
+
// Strip trailing commas before } or ]
|
|
316
|
+
stripped = stripped.replace(/,(\s*[}\]])/g, "$1");
|
|
317
|
+
return JSON.parse(stripped);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// ── Public API ──
|
|
321
|
+
|
|
322
|
+
/** Load accounts — first from IndexedDB cache, then GDrive */
|
|
323
|
+
export async function loadAccounts(): Promise<AccountConfig[]> {
|
|
324
|
+
// Try local cache first
|
|
325
|
+
const cached = await idbRead("accounts.jsonc");
|
|
326
|
+
if (cached) {
|
|
327
|
+
try {
|
|
328
|
+
const data = parseJsonc(cached);
|
|
329
|
+
const raw: any[] = data.accounts || (Array.isArray(data) ? data : []);
|
|
330
|
+
if (raw.length > 0) {
|
|
331
|
+
return raw.map((a: any) => normalizeAccount(a, data.name));
|
|
332
|
+
}
|
|
333
|
+
} catch (e: any) { console.warn(`[settings] Cached accounts.jsonc parse failed: ${e.message}`); }
|
|
334
|
+
}
|
|
335
|
+
// Try GDrive
|
|
336
|
+
const content = await gDriveRead("accounts.jsonc");
|
|
337
|
+
if (content) {
|
|
338
|
+
await idbWrite("accounts.jsonc", content);
|
|
339
|
+
try {
|
|
340
|
+
const data = parseJsonc(content);
|
|
341
|
+
const raw: any[] = data.accounts || (Array.isArray(data) ? data : []);
|
|
342
|
+
return raw.map((a: any) => normalizeAccount(a, data.name));
|
|
343
|
+
} catch (e: any) { console.warn(`[settings] GDrive accounts.jsonc parse failed: ${e.message}`); }
|
|
344
|
+
}
|
|
345
|
+
return [];
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/** Load accounts directly from GDrive, bypassing local cache */
|
|
349
|
+
export async function loadAccountsFromCloud(): Promise<AccountConfig[]> {
|
|
350
|
+
const content = await gDriveRead("accounts.jsonc");
|
|
351
|
+
if (content) {
|
|
352
|
+
await idbWrite("accounts.jsonc", content);
|
|
353
|
+
try {
|
|
354
|
+
const data = parseJsonc(content);
|
|
355
|
+
const raw: any[] = data.accounts || (Array.isArray(data) ? data : []);
|
|
356
|
+
return raw.map((a: any) => normalizeAccount(a, data.name));
|
|
357
|
+
} catch (e: any) { console.warn(`[settings] loadAccountsFromCloud parse failed: ${e.message}`); }
|
|
358
|
+
}
|
|
359
|
+
return [];
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/** Save accounts to IndexedDB and GDrive */
|
|
363
|
+
export async function saveAccounts(accounts: AccountConfig[]): Promise<void> {
|
|
364
|
+
const content = JSON.stringify({ accounts }, null, 2);
|
|
365
|
+
await idbWrite("accounts.jsonc", content);
|
|
366
|
+
await gDriveWrite("accounts.jsonc", content);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/** Load preferences */
|
|
370
|
+
export async function loadPreferences(): Promise<typeof DEFAULT_PREFERENCES> {
|
|
371
|
+
const cached = await idbRead("preferences.jsonc");
|
|
372
|
+
if (cached) {
|
|
373
|
+
try {
|
|
374
|
+
const data = parseJsonc(cached);
|
|
375
|
+
return {
|
|
376
|
+
ui: { ...DEFAULT_PREFERENCES.ui, ...data.ui },
|
|
377
|
+
sync: { ...DEFAULT_PREFERENCES.sync, ...data.sync },
|
|
378
|
+
autocomplete: { ...DEFAULT_PREFERENCES.autocomplete, ...data.autocomplete },
|
|
379
|
+
};
|
|
380
|
+
} catch { /* parse error */ }
|
|
381
|
+
}
|
|
382
|
+
// Try GDrive
|
|
383
|
+
const content = await gDriveRead("preferences.jsonc");
|
|
384
|
+
if (content) {
|
|
385
|
+
await idbWrite("preferences.jsonc", content);
|
|
386
|
+
try {
|
|
387
|
+
const data = parseJsonc(content);
|
|
388
|
+
return {
|
|
389
|
+
ui: { ...DEFAULT_PREFERENCES.ui, ...data.ui },
|
|
390
|
+
sync: { ...DEFAULT_PREFERENCES.sync, ...data.sync },
|
|
391
|
+
autocomplete: { ...DEFAULT_PREFERENCES.autocomplete, ...data.autocomplete },
|
|
392
|
+
};
|
|
393
|
+
} catch { /* parse error */ }
|
|
394
|
+
}
|
|
395
|
+
return { ...DEFAULT_PREFERENCES };
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/** Save preferences */
|
|
399
|
+
export async function savePreferences(prefs: any): Promise<void> {
|
|
400
|
+
const content = JSON.stringify(prefs, null, 2);
|
|
401
|
+
await idbWrite("preferences.jsonc", content);
|
|
402
|
+
await gDriveWrite("preferences.jsonc", content);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/** Load full settings (accounts + preferences combined) */
|
|
406
|
+
export async function loadSettings(): Promise<MailxSettings> {
|
|
407
|
+
const accounts = await loadAccounts();
|
|
408
|
+
const prefs = await loadPreferences();
|
|
409
|
+
return {
|
|
410
|
+
accounts,
|
|
411
|
+
ui: prefs.ui,
|
|
412
|
+
sync: prefs.sync,
|
|
413
|
+
autocomplete: prefs.autocomplete as AutocompleteSettings,
|
|
414
|
+
store: {
|
|
415
|
+
basePath: "indexeddb",
|
|
416
|
+
compressionBoundaryDays: 365,
|
|
417
|
+
},
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
/** Save full settings */
|
|
422
|
+
export async function saveSettings(settings: MailxSettings): Promise<void> {
|
|
423
|
+
await saveAccounts(settings.accounts);
|
|
424
|
+
await savePreferences({ ui: settings.ui, sync: settings.sync, autocomplete: settings.autocomplete });
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/** Load allowlist */
|
|
428
|
+
export async function loadAllowlist(): Promise<typeof DEFAULT_ALLOWLIST> {
|
|
429
|
+
const cached = await idbRead("allowlist.jsonc");
|
|
430
|
+
if (cached) {
|
|
431
|
+
try { return parseJsonc(cached); } catch { /* */ }
|
|
432
|
+
}
|
|
433
|
+
const content = await gDriveRead("allowlist.jsonc");
|
|
434
|
+
if (content) {
|
|
435
|
+
await idbWrite("allowlist.jsonc", content);
|
|
436
|
+
try { return parseJsonc(content); } catch { /* */ }
|
|
437
|
+
}
|
|
438
|
+
return { ...DEFAULT_ALLOWLIST };
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/** Save allowlist */
|
|
442
|
+
export async function saveAllowlist(list: typeof DEFAULT_ALLOWLIST): Promise<void> {
|
|
443
|
+
const content = JSON.stringify(list, null, 2);
|
|
444
|
+
await idbWrite("allowlist.jsonc", content);
|
|
445
|
+
await gDriveWrite("allowlist.jsonc", content);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/** Load autocomplete settings */
|
|
449
|
+
export async function loadAutocomplete(): Promise<AutocompleteSettings> {
|
|
450
|
+
const prefs = await loadPreferences();
|
|
451
|
+
return prefs.autocomplete as AutocompleteSettings;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/** Save autocomplete settings */
|
|
455
|
+
export async function saveAutocomplete(settings: AutocompleteSettings): Promise<void> {
|
|
456
|
+
const prefs = await loadPreferences();
|
|
457
|
+
(prefs as any).autocomplete = settings;
|
|
458
|
+
await savePreferences(prefs);
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/** Get history days — read from preferences */
|
|
462
|
+
export async function getHistoryDays(): Promise<number> {
|
|
463
|
+
const prefs = await loadPreferences();
|
|
464
|
+
return prefs.sync.historyDays || 30;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
/** Get prefetch setting */
|
|
468
|
+
export async function getPrefetch(): Promise<boolean> {
|
|
469
|
+
const prefs = await loadPreferences();
|
|
470
|
+
return prefs.sync.prefetch !== false;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/** Get storage info */
|
|
474
|
+
export function getStorageInfo(): { provider: string; mode: string } {
|
|
475
|
+
return { provider: gDriveFolderId ? "gdrive" : "local", mode: gDriveFolderId ? "api" : "local" };
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/** Clear all cached settings — used for "Reset Store" */
|
|
479
|
+
export async function clearSettings(): Promise<void> {
|
|
480
|
+
await idbDelete("accounts.jsonc");
|
|
481
|
+
await idbDelete("preferences.jsonc");
|
|
482
|
+
await idbDelete("allowlist.jsonc");
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
// ── Per-device settings ──
|
|
486
|
+
|
|
487
|
+
const DEVICE_ID_KEY = "mailx-device-id";
|
|
488
|
+
|
|
489
|
+
/** Get or create a stable device ID (UUID stored in localStorage) */
|
|
490
|
+
export function getDeviceId(): string {
|
|
491
|
+
let id = localStorage.getItem(DEVICE_ID_KEY);
|
|
492
|
+
if (!id) {
|
|
493
|
+
id = crypto.randomUUID();
|
|
494
|
+
localStorage.setItem(DEVICE_ID_KEY, id);
|
|
495
|
+
}
|
|
496
|
+
return id;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/** Save device-specific settings to GDrive (devices/<deviceId>/state.json) */
|
|
500
|
+
export async function saveDeviceState(state: any): Promise<void> {
|
|
501
|
+
const deviceId = getDeviceId();
|
|
502
|
+
const filename = `devices/${deviceId}/state.json`;
|
|
503
|
+
const content = JSON.stringify(state, null, 2);
|
|
504
|
+
await idbWrite(filename, content);
|
|
505
|
+
await gDriveWrite(filename, content);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
/** Load device-specific settings */
|
|
509
|
+
export async function loadDeviceState(): Promise<any> {
|
|
510
|
+
const deviceId = getDeviceId();
|
|
511
|
+
const filename = `devices/${deviceId}/state.json`;
|
|
512
|
+
const cached = await idbRead(filename);
|
|
513
|
+
if (cached) {
|
|
514
|
+
try { return parseJsonc(cached); } catch { /* */ }
|
|
515
|
+
}
|
|
516
|
+
const content = await gDriveRead(filename);
|
|
517
|
+
if (content) {
|
|
518
|
+
await idbWrite(filename, content);
|
|
519
|
+
try { return parseJsonc(content); } catch { /* */ }
|
|
520
|
+
}
|
|
521
|
+
return {};
|
|
522
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker-entry.d.ts","sourceRoot":"","sources":["worker-entry.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker-entry.js","sourceRoot":"","sources":["worker-entry.ts"],"names":[],"mappings":"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"}
|