@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.
Files changed (205) hide show
  1. package/bin/mailx.js.map +1 -0
  2. package/bin/mailx.ts +1498 -0
  3. package/bin/postinstall.js.map +1 -0
  4. package/bin/postinstall.ts +41 -0
  5. package/bin/tsconfig.json +10 -0
  6. package/client/.gitattributes +10 -0
  7. package/client/app.js +51 -2
  8. package/client/app.js.map +1 -0
  9. package/client/app.ts +3112 -0
  10. package/client/components/address-book.js.map +1 -0
  11. package/client/components/address-book.ts +204 -0
  12. package/client/components/alarms.js.map +1 -0
  13. package/client/components/alarms.ts +276 -0
  14. package/client/components/calendar-sidebar.js.map +1 -0
  15. package/client/components/calendar-sidebar.ts +474 -0
  16. package/client/components/calendar.js.map +1 -0
  17. package/client/components/calendar.ts +211 -0
  18. package/client/components/context-menu.js.map +1 -0
  19. package/client/components/context-menu.ts +95 -0
  20. package/client/components/folder-picker.js.map +1 -0
  21. package/client/components/folder-picker.ts +127 -0
  22. package/client/components/folder-tree.js.map +1 -0
  23. package/client/components/folder-tree.ts +1069 -0
  24. package/client/components/message-list.js.map +1 -0
  25. package/client/components/message-list.ts +1129 -0
  26. package/client/components/message-viewer.js.map +1 -0
  27. package/client/components/message-viewer.ts +1257 -0
  28. package/client/components/outbox-view.js.map +1 -0
  29. package/client/components/outbox-view.ts +102 -0
  30. package/client/components/tasks.js.map +1 -0
  31. package/client/components/tasks.ts +234 -0
  32. package/client/compose/compose.js.map +1 -0
  33. package/client/compose/compose.ts +1231 -0
  34. package/client/compose/editor.js.map +1 -0
  35. package/client/compose/editor.ts +599 -0
  36. package/client/compose/ghost-text.js.map +1 -0
  37. package/client/compose/ghost-text.ts +140 -0
  38. package/client/index.html +1 -0
  39. package/client/lib/android-bootstrap.js.map +1 -0
  40. package/client/lib/android-bootstrap.ts +9 -0
  41. package/client/lib/api-client.js.map +1 -0
  42. package/client/lib/api-client.ts +439 -0
  43. package/client/lib/local-service.js.map +1 -0
  44. package/client/lib/local-service.ts +646 -0
  45. package/client/lib/local-store.js.map +1 -0
  46. package/client/lib/local-store.ts +283 -0
  47. package/client/lib/message-state.js.map +1 -0
  48. package/client/lib/message-state.ts +140 -0
  49. package/client/tsconfig.json +19 -0
  50. package/package.json +18 -16
  51. package/packages/mailx-api/.gitattributes +10 -0
  52. package/packages/mailx-api/index.d.ts.map +1 -0
  53. package/packages/mailx-api/index.js.map +1 -0
  54. package/packages/mailx-api/index.ts +283 -0
  55. package/packages/mailx-api/package.json +1 -1
  56. package/packages/mailx-api/tsconfig.json +9 -0
  57. package/packages/mailx-compose/.gitattributes +10 -0
  58. package/packages/mailx-compose/index.d.ts.map +1 -0
  59. package/packages/mailx-compose/index.js.map +1 -0
  60. package/packages/mailx-compose/index.ts +85 -0
  61. package/packages/mailx-compose/tsconfig.json +9 -0
  62. package/packages/mailx-core/index.d.ts.map +1 -0
  63. package/packages/mailx-core/index.js.map +1 -0
  64. package/packages/mailx-core/index.ts +424 -0
  65. package/packages/mailx-core/ipc.d.ts.map +1 -0
  66. package/packages/mailx-core/ipc.js.map +1 -0
  67. package/packages/mailx-core/ipc.ts +62 -0
  68. package/packages/mailx-core/package.json +1 -1
  69. package/packages/mailx-core/tsconfig.json +9 -0
  70. package/packages/mailx-host/.gitattributes +10 -0
  71. package/packages/mailx-host/index.d.ts.map +1 -0
  72. package/packages/mailx-host/index.js.map +1 -0
  73. package/packages/mailx-host/index.ts +38 -0
  74. package/packages/mailx-host/package.json +10 -2
  75. package/packages/mailx-host/tsconfig.json +9 -0
  76. package/packages/mailx-send/.gitattributes +10 -0
  77. package/packages/mailx-send/cli-queue.d.ts.map +1 -0
  78. package/packages/mailx-send/cli-queue.js.map +1 -0
  79. package/packages/mailx-send/cli-queue.ts +62 -0
  80. package/packages/mailx-send/cli-send.d.ts.map +1 -0
  81. package/packages/mailx-send/cli-send.js.map +1 -0
  82. package/packages/mailx-send/cli-send.ts +83 -0
  83. package/packages/mailx-send/cli.d.ts.map +1 -0
  84. package/packages/mailx-send/cli.js.map +1 -0
  85. package/packages/mailx-send/cli.ts +126 -0
  86. package/packages/mailx-send/index.d.ts.map +1 -0
  87. package/packages/mailx-send/index.js.map +1 -0
  88. package/packages/mailx-send/index.ts +333 -0
  89. package/packages/mailx-send/mailsend/cli.d.ts.map +1 -0
  90. package/packages/mailx-send/mailsend/cli.js.map +1 -0
  91. package/packages/mailx-send/mailsend/cli.ts +81 -0
  92. package/packages/mailx-send/mailsend/index.d.ts.map +1 -0
  93. package/packages/mailx-send/mailsend/index.js.map +1 -0
  94. package/packages/mailx-send/mailsend/index.ts +333 -0
  95. package/packages/mailx-send/mailsend/package-lock.json +65 -0
  96. package/packages/mailx-send/mailsend/tsconfig.json +21 -0
  97. package/packages/mailx-send/package-lock.json +65 -0
  98. package/packages/mailx-send/package.json +1 -1
  99. package/packages/mailx-send/tsconfig.json +21 -0
  100. package/packages/mailx-server/.gitattributes +10 -0
  101. package/packages/mailx-server/index.d.ts.map +1 -0
  102. package/packages/mailx-server/index.js.map +1 -0
  103. package/packages/mailx-server/index.ts +429 -0
  104. package/packages/mailx-server/package.json +1 -1
  105. package/packages/mailx-server/tsconfig.json +9 -0
  106. package/packages/mailx-service/google-sync.d.ts.map +1 -0
  107. package/packages/mailx-service/google-sync.js.map +1 -0
  108. package/packages/mailx-service/google-sync.ts +238 -0
  109. package/packages/mailx-service/index.d.ts.map +1 -0
  110. package/packages/mailx-service/index.js.map +1 -0
  111. package/packages/mailx-service/index.ts +2461 -0
  112. package/packages/mailx-service/jsonrpc.d.ts.map +1 -0
  113. package/packages/mailx-service/jsonrpc.js.map +1 -0
  114. package/packages/mailx-service/jsonrpc.ts +268 -0
  115. package/packages/mailx-service/package.json +1 -1
  116. package/packages/mailx-service/tsconfig.json +9 -0
  117. package/packages/mailx-settings/.gitattributes +10 -0
  118. package/packages/mailx-settings/cloud.d.ts.map +1 -0
  119. package/packages/mailx-settings/cloud.js.map +1 -0
  120. package/packages/mailx-settings/cloud.ts +388 -0
  121. package/packages/mailx-settings/index.d.ts.map +1 -0
  122. package/packages/mailx-settings/index.js.map +1 -0
  123. package/packages/mailx-settings/index.ts +892 -0
  124. package/packages/mailx-settings/package.json +1 -1
  125. package/packages/mailx-settings/tsconfig.json +9 -0
  126. package/packages/mailx-store/.gitattributes +10 -0
  127. package/packages/mailx-store/db.d.ts.map +1 -0
  128. package/packages/mailx-store/db.js.map +1 -0
  129. package/packages/mailx-store/db.ts +2007 -0
  130. package/packages/mailx-store/file-store.d.ts.map +1 -0
  131. package/packages/mailx-store/file-store.js.map +1 -0
  132. package/packages/mailx-store/file-store.ts +82 -0
  133. package/packages/mailx-store/index.d.ts.map +1 -0
  134. package/packages/mailx-store/index.js.map +1 -0
  135. package/packages/mailx-store/index.ts +7 -0
  136. package/packages/mailx-store/package.json +1 -1
  137. package/packages/mailx-store/tsconfig.json +9 -0
  138. package/packages/mailx-store-web/android-bootstrap.d.ts.map +1 -0
  139. package/packages/mailx-store-web/android-bootstrap.js.map +1 -0
  140. package/packages/mailx-store-web/android-bootstrap.ts +1262 -0
  141. package/packages/mailx-store-web/db.d.ts.map +1 -0
  142. package/packages/mailx-store-web/db.js.map +1 -0
  143. package/packages/mailx-store-web/db.ts +756 -0
  144. package/packages/mailx-store-web/gmail-api-web.d.ts.map +1 -0
  145. package/packages/mailx-store-web/gmail-api-web.js.map +1 -0
  146. package/packages/mailx-store-web/gmail-api-web.ts +11 -0
  147. package/packages/mailx-store-web/imap-web-provider.d.ts.map +1 -0
  148. package/packages/mailx-store-web/imap-web-provider.js.map +1 -0
  149. package/packages/mailx-store-web/imap-web-provider.ts +156 -0
  150. package/packages/mailx-store-web/index.d.ts.map +1 -0
  151. package/packages/mailx-store-web/index.js.map +1 -0
  152. package/packages/mailx-store-web/index.ts +10 -0
  153. package/packages/mailx-store-web/main-thread-host.d.ts.map +1 -0
  154. package/packages/mailx-store-web/main-thread-host.js.map +1 -0
  155. package/packages/mailx-store-web/main-thread-host.ts +322 -0
  156. package/packages/mailx-store-web/package.json +4 -4
  157. package/packages/mailx-store-web/provider-types.d.ts.map +1 -0
  158. package/packages/mailx-store-web/provider-types.js.map +1 -0
  159. package/packages/mailx-store-web/provider-types.ts +7 -0
  160. package/packages/mailx-store-web/sync-manager.d.ts.map +1 -0
  161. package/packages/mailx-store-web/sync-manager.js.map +1 -0
  162. package/packages/mailx-store-web/sync-manager.ts +508 -0
  163. package/packages/mailx-store-web/tsconfig.json +10 -0
  164. package/packages/mailx-store-web/web-jsonrpc.d.ts.map +1 -0
  165. package/packages/mailx-store-web/web-jsonrpc.js.map +1 -0
  166. package/packages/mailx-store-web/web-jsonrpc.ts +116 -0
  167. package/packages/mailx-store-web/web-message-store.d.ts.map +1 -0
  168. package/packages/mailx-store-web/web-message-store.js.map +1 -0
  169. package/packages/mailx-store-web/web-message-store.ts +97 -0
  170. package/packages/mailx-store-web/web-service.d.ts.map +1 -0
  171. package/packages/mailx-store-web/web-service.js.map +1 -0
  172. package/packages/mailx-store-web/web-service.ts +616 -0
  173. package/packages/mailx-store-web/web-settings.d.ts.map +1 -0
  174. package/packages/mailx-store-web/web-settings.js.map +1 -0
  175. package/packages/mailx-store-web/web-settings.ts +522 -0
  176. package/packages/mailx-store-web/worker-entry.d.ts.map +1 -0
  177. package/packages/mailx-store-web/worker-entry.js.map +1 -0
  178. package/packages/mailx-store-web/worker-entry.ts +215 -0
  179. package/packages/mailx-store-web/worker-tcp-transport.d.ts.map +1 -0
  180. package/packages/mailx-store-web/worker-tcp-transport.js.map +1 -0
  181. package/packages/mailx-store-web/worker-tcp-transport.ts +101 -0
  182. package/packages/mailx-types/.gitattributes +10 -0
  183. package/packages/mailx-types/index.d.ts.map +1 -0
  184. package/packages/mailx-types/index.js.map +1 -0
  185. package/packages/mailx-types/index.ts +498 -0
  186. package/packages/mailx-types/package.json +1 -1
  187. package/packages/mailx-types/tsconfig.json +9 -0
  188. package/tsconfig.base.json +2 -1
  189. package/tsconfig.json +9 -0
  190. package/build-apk.cmd +0 -3
  191. package/npmg.bat +0 -6
  192. package/packages/mailx-imap/index.d.ts +0 -442
  193. package/packages/mailx-imap/index.js +0 -3684
  194. package/packages/mailx-imap/package.json +0 -25
  195. package/packages/mailx-imap/providers/gmail-api.d.ts +0 -8
  196. package/packages/mailx-imap/providers/gmail-api.js +0 -8
  197. package/packages/mailx-imap/providers/types.d.ts +0 -9
  198. package/packages/mailx-imap/providers/types.js +0 -9
  199. package/packages/mailx-imap/tsconfig.tsbuildinfo +0 -1
  200. package/rebuild.cmd +0 -23
  201. package/tdview.cmd +0 -2
  202. package/temp.ps1 +0 -10
  203. package/test-smtp-direct.mjs +0 -4
  204. package/unbash.cmd +0 -55
  205. package/unwedge.cmd +0 -1
@@ -0,0 +1,424 @@
1
+ /**
2
+ * @bobfrankston/mailx-core
3
+ * Core mail functions — callable directly via IPC or wrapped by Express.
4
+ * No HTTP, no Express, no WebSocket. Just plain async functions.
5
+ */
6
+
7
+ import { MailxDB } from "@bobfrankston/mailx-store";
8
+ import { ImapManager } from "@bobfrankston/mailx-imap";
9
+ import { loadSettings, saveSettings, loadAllowlist, saveAllowlist, loadAccounts, getConfigDir, getStorePath, initLocalConfig } from "@bobfrankston/mailx-settings";
10
+ import { simpleParser } from "mailparser";
11
+ import type { ComposeMessage, AccountConfig } from "@bobfrankston/mailx-types";
12
+
13
+ // ── Initialization ──
14
+
15
+ let db: MailxDB;
16
+ let imapManager: ImapManager;
17
+ const eventHandlers: ((event: any) => void)[] = [];
18
+
19
+ export function onEvent(handler: (event: any) => void): void {
20
+ eventHandlers.push(handler);
21
+ }
22
+
23
+ function emit(event: any): void {
24
+ for (const h of eventHandlers) {
25
+ try { h(event); } catch { /* ignore handler errors */ }
26
+ }
27
+ }
28
+
29
+ export async function initialize(transportFactory?: any): Promise<void> {
30
+ initLocalConfig();
31
+ const dbDir = getConfigDir();
32
+ db = new MailxDB(dbDir);
33
+ imapManager = new ImapManager(db, transportFactory || (() => { throw new Error("No transport factory provided"); }));
34
+
35
+ // Seed contacts
36
+ const seeded = db.seedContactsFromMessages();
37
+ if (seeded > 0) console.log(` Seeded ${seeded} contacts`);
38
+
39
+ // Search index — only if empty
40
+ let ftsCount = 0;
41
+ try { ftsCount = (db as any).db.prepare("SELECT COUNT(*) as cnt FROM messages_fts").get()?.cnt || 0; } catch { /* */ }
42
+ if (ftsCount === 0) {
43
+ const indexed = db.rebuildSearchIndex();
44
+ if (indexed > 0) console.log(` Search index: ${indexed} messages`);
45
+ }
46
+
47
+ // Add accounts
48
+ const settings = loadSettings();
49
+ for (const account of settings.accounts) {
50
+ if (!account.enabled) continue;
51
+ try {
52
+ await imapManager.addAccount(account);
53
+ console.log(` Account added: ${account.name} (${account.id})`);
54
+ } catch (e: any) {
55
+ console.error(` Failed to add account ${account.id}: ${e.message}`);
56
+ }
57
+ }
58
+
59
+ // Wire events to push notifications
60
+ imapManager.on("syncProgress", (accountId: string, phase: string, progress: number) => {
61
+ emit({ type: "syncProgress", accountId, phase, progress });
62
+ });
63
+ imapManager.on("folderCountsChanged", (accountId: string, counts: any) => {
64
+ emit({ type: "folderCountsChanged", accountId, counts });
65
+ });
66
+
67
+ // Initial sync + IDLE
68
+ if (settings.accounts.some(a => a.enabled)) {
69
+ console.log(" Starting initial sync...");
70
+ imapManager.syncAll().then(async () => {
71
+ console.log(" Initial sync complete");
72
+ await imapManager.startWatching();
73
+ imapManager.syncAllContacts().catch(e =>
74
+ console.error(` Google Contacts sync error: ${e.message}`)
75
+ );
76
+ }).catch(e => {
77
+ console.error(` Initial sync error: ${e.message}`);
78
+ });
79
+ }
80
+
81
+ imapManager.startPeriodicSync(settings.sync.intervalMinutes);
82
+ imapManager.startOutboxWorker();
83
+ }
84
+
85
+ export async function shutdown(): Promise<void> {
86
+ imapManager?.stopPeriodicSync();
87
+ imapManager?.stopOutboxWorker();
88
+ await imapManager?.shutdown();
89
+ db?.close();
90
+ }
91
+
92
+ // ── HTML Sanitization ──
93
+
94
+ function sanitizeHtml(html: string): { html: string; hasRemoteContent: boolean } {
95
+ let hasRemoteContent = false;
96
+ let clean = html.replace(/<script\b[^>]*>[\s\S]*?<\/script>/gi, "");
97
+ clean = clean.replace(/\s+on\w+\s*=\s*("[^"]*"|'[^']*'|[^\s>]+)/gi, "");
98
+ clean = clean.replace(/<img\b([^>]*)\bsrc\s*=\s*("[^"]*"|'[^']*')/gi, (match, before, src) => {
99
+ const url = src.slice(1, -1);
100
+ if (url.startsWith("data:") || url.startsWith("cid:")) return match;
101
+ hasRemoteContent = true;
102
+ return `<img${before}src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20'%3E%3Crect fill='%23888' width='20' height='20' rx='3'/%3E%3Ctext x='10' y='14' text-anchor='middle' fill='white' font-size='12'%3E⊘%3C/text%3E%3C/svg%3E" data-blocked-src=${src} title="Remote image blocked"`;
103
+ });
104
+ clean = clean.replace(/<link\b[^>]*rel\s*=\s*["']stylesheet["'][^>]*>/gi, (match) => {
105
+ hasRemoteContent = true;
106
+ return `<!-- blocked: ${match.replace(/--/g, "")} -->`;
107
+ });
108
+ clean = clean.replace(/url\s*\(\s*(['"]?)(https?:\/\/[^)]+)\1\s*\)/gi, (_match, _q, url) => {
109
+ hasRemoteContent = true;
110
+ return `url("") /* blocked: ${url} */`;
111
+ });
112
+ clean = clean.replace(/<\/?form\b[^>]*>/gi, "");
113
+ clean = clean.replace(/<iframe\b[^>]*>[\s\S]*?<\/iframe>/gi, "");
114
+ return { html: clean, hasRemoteContent };
115
+ }
116
+
117
+ // ── API Functions ──
118
+
119
+ export function getAccounts() {
120
+ return db.getAccounts();
121
+ }
122
+
123
+ export function getFolders(params: { accountId: string }) {
124
+ return db.getFolders(params.accountId);
125
+ }
126
+
127
+ export function getMessages(params: { accountId: string; folderId: number; page?: number; pageSize?: number; sort?: string; sortDir?: string; search?: string; flaggedOnly?: boolean }) {
128
+ return db.getMessages({
129
+ accountId: params.accountId,
130
+ folderId: params.folderId,
131
+ page: params.page || 1,
132
+ pageSize: params.pageSize || 50,
133
+ sort: (params.sort as any) || "date",
134
+ sortDir: (params.sortDir as any) || "desc",
135
+ search: params.search,
136
+ flaggedOnly: params.flaggedOnly,
137
+ });
138
+ }
139
+
140
+ export function getUnifiedInbox(params: { page?: number; pageSize?: number }) {
141
+ return db.getUnifiedInbox(params.page, params.pageSize);
142
+ }
143
+
144
+ export async function getMessage(params: { accountId: string; uid: number; allowRemote?: boolean; folderId?: number }) {
145
+ const { accountId, uid } = params;
146
+ let allowRemote = params.allowRemote || false;
147
+ const envelope = db.getMessageByUid(accountId, uid, params.folderId);
148
+ if (!envelope) throw new Error("Message not found");
149
+
150
+ let bodyHtml = "";
151
+ let bodyText = "";
152
+ let hasRemoteContent = false;
153
+ let attachments: any[] = [];
154
+
155
+ let deliveredTo = "";
156
+ let returnPath = "";
157
+ let listUnsubscribe = "";
158
+ let listUnsubscribeMail = "";
159
+ let listUnsubscribeHttp = "";
160
+ let listUnsubscribeOneClick = false;
161
+
162
+ const raw = await imapManager.fetchMessageBody(accountId, envelope.folderId, envelope.uid);
163
+ if (raw) {
164
+ const parsed = await simpleParser(raw);
165
+ bodyHtml = parsed.html || "";
166
+ bodyText = parsed.text || "";
167
+ attachments = (parsed.attachments || []).map((a, i) => ({
168
+ id: i,
169
+ filename: a.filename || `attachment-${i}`,
170
+ mimeType: a.contentType || "application/octet-stream",
171
+ size: a.size || 0,
172
+ contentId: a.contentId || "",
173
+ }));
174
+ // Extract useful headers for the UI
175
+ const hdr = (key: string): string => {
176
+ let v = parsed.headers.get(key);
177
+ if (!v) return "";
178
+ if (Array.isArray(v)) v = v[0];
179
+ if (typeof v === "string") return v;
180
+ if (typeof v === "object" && v !== null) {
181
+ if ("text" in v) return (v as any).text || "";
182
+ if ("value" in v) return String((v as any).value);
183
+ if ("address" in v) return (v as any).address || "";
184
+ }
185
+ return String(v);
186
+ };
187
+ // Get the real Delivered-To, skipping relay domains from account config
188
+ const settings = loadSettings();
189
+ const acctConfig = settings.accounts.find(a => a.id === accountId);
190
+ const relayDomains = acctConfig?.relayDomains || [];
191
+ const prefixes: string[] = acctConfig?.deliveredToPrefix || [];
192
+ const rawDelivered = parsed.headers.get("delivered-to");
193
+ if (rawDelivered) {
194
+ const deliveredList = Array.isArray(rawDelivered) ? rawDelivered : [rawDelivered];
195
+ for (let i = deliveredList.length - 1; i >= 0; i--) {
196
+ const d = deliveredList[i];
197
+ const addr = typeof d === "string" ? d : (d as any)?.text || (d as any)?.address || String(d);
198
+ if (!relayDomains.some((rd: string) => addr.includes(`@${rd}`))) {
199
+ deliveredTo = addr;
200
+ break;
201
+ }
202
+ }
203
+ if (!deliveredTo && deliveredList.length > 0) {
204
+ const d = deliveredList[deliveredList.length - 1];
205
+ deliveredTo = typeof d === "string" ? d : (d as any)?.text || (d as any)?.address || String(d);
206
+ }
207
+ // Strip prefix from local part to get clean alias
208
+ if (deliveredTo && prefixes.length > 0) {
209
+ const [local, domain] = deliveredTo.split("@");
210
+ for (const prefix of prefixes) {
211
+ if (local.startsWith(prefix)) {
212
+ deliveredTo = `${local.slice(prefix.length)}@${domain}`;
213
+ break;
214
+ }
215
+ }
216
+ }
217
+ }
218
+ returnPath = hdr("return-path").replace(/[<>]/g, "");
219
+ ({ listUnsubscribeMail, listUnsubscribeHttp, listUnsubscribeOneClick } =
220
+ parseListUnsubscribe(parsed.headers));
221
+ listUnsubscribe = listUnsubscribeHttp || listUnsubscribeMail;
222
+ }
223
+
224
+ if (bodyHtml && !allowRemote) {
225
+ const allowList = loadAllowlist();
226
+ const senderAddr = envelope.from?.address || "";
227
+ const senderDomain = senderAddr.split("@")[1] || "";
228
+ const toAddrs = (envelope.to || []).map((a: any) => a.address);
229
+ const isAllowed = allowList.senders.includes(senderAddr) ||
230
+ allowList.domains.includes(senderDomain) ||
231
+ toAddrs.some((a: string) => allowList.recipients?.includes(a));
232
+
233
+ if (isAllowed) {
234
+ allowRemote = true;
235
+ } else {
236
+ const result = sanitizeHtml(bodyHtml);
237
+ bodyHtml = result.html;
238
+ hasRemoteContent = result.hasRemoteContent;
239
+ }
240
+ }
241
+
242
+ // Build .eml file path for "View Source"
243
+ const storePath = getStorePath();
244
+ const emlPath = `${storePath}/${accountId}/${envelope.folderId}/${envelope.uid}.eml`;
245
+
246
+ return { ...envelope, bodyHtml, bodyText, hasRemoteContent, remoteAllowed: allowRemote, attachments, deliveredTo, returnPath, listUnsubscribe, listUnsubscribeMail, listUnsubscribeHttp, listUnsubscribeOneClick, emlPath };
247
+ }
248
+
249
+ /** Parse `List-Unsubscribe` (RFC 2369) and `List-Unsubscribe-Post` (RFC 8058).
250
+ * Returns mailto URL, HTTPS URL, and whether one-click POST is allowed.
251
+ * mailparser only exposes ONE of mail/url even when both are present, so we
252
+ * also scan the raw header text for the full set of angle-bracketed URIs. */
253
+ function parseListUnsubscribe(headers: any): { listUnsubscribeMail: string; listUnsubscribeHttp: string; listUnsubscribeOneClick: boolean } {
254
+ let mail = "";
255
+ let http = "";
256
+ let oneClick = false;
257
+
258
+ // Raw header scan — most reliable.
259
+ const raw = headers.get("list-unsubscribe");
260
+ const rawStr = typeof raw === "string" ? raw : (raw && typeof (raw as any).text === "string" ? (raw as any).text : "");
261
+ if (rawStr) {
262
+ const matches = rawStr.match(/<([^>]+)>/g) || [];
263
+ for (const m of matches) {
264
+ const url = m.slice(1, -1).trim();
265
+ if (!mail && /^mailto:/i.test(url)) mail = url;
266
+ else if (!http && /^https?:/i.test(url)) http = url;
267
+ }
268
+ }
269
+ // mailparser fallback — for builds where headers.get returns the parsed object.
270
+ if (!mail && !http) {
271
+ const listHeaders = headers.get("list");
272
+ if (listHeaders?.unsubscribe) {
273
+ const unsub = listHeaders.unsubscribe;
274
+ if (unsub.url) http = Array.isArray(unsub.url) ? unsub.url[0] : unsub.url;
275
+ if (unsub.mail) mail = `mailto:${Array.isArray(unsub.mail) ? unsub.mail[0] : unsub.mail}`;
276
+ }
277
+ }
278
+
279
+ const post = headers.get("list-unsubscribe-post");
280
+ const postStr = typeof post === "string" ? post : (post && typeof (post as any).text === "string" ? (post as any).text : "");
281
+ if (postStr && /one-?click/i.test(postStr)) oneClick = true;
282
+
283
+ return { listUnsubscribeMail: mail, listUnsubscribeHttp: http, listUnsubscribeOneClick: oneClick };
284
+ }
285
+
286
+ export async function updateFlags(params: { accountId: string; uid: number; flags: string[] }) {
287
+ const envelope = db.getMessageByUid(params.accountId, params.uid);
288
+ await imapManager.updateFlagsLocal(params.accountId, params.uid, envelope?.folderId || 0, params.flags);
289
+ }
290
+
291
+ export async function deleteMessage(params: { accountId: string; uid: number }) {
292
+ const envelope = db.getMessageByUid(params.accountId, params.uid);
293
+ if (!envelope) throw new Error("Message not found");
294
+ await imapManager.trashMessage(params.accountId, envelope.folderId, envelope.uid);
295
+ }
296
+
297
+ export async function undeleteMessage(params: { accountId: string; uid: number; folderId: number }) {
298
+ await imapManager.undeleteMessage(params.accountId, params.uid, params.folderId);
299
+ }
300
+
301
+ export async function sendMessage(params: ComposeMessage) {
302
+ const settings = loadSettings();
303
+ const account = settings.accounts.find(a => a.id === params.from);
304
+ if (!account) throw new Error(`Unknown account: ${params.from}`);
305
+
306
+ const to = params.to.map(a => a.name ? `${a.name} <${a.address}>` : a.address).join(", ");
307
+ const cc = params.cc?.map(a => a.name ? `${a.name} <${a.address}>` : a.address).join(", ");
308
+ const bcc = params.bcc?.map(a => a.name ? `${a.name} <${a.address}>` : a.address).join(", ");
309
+
310
+ const headers = [
311
+ `From: ${account.name} <${account.email}>`,
312
+ `To: ${to}`,
313
+ cc ? `Cc: ${cc}` : null,
314
+ bcc ? `Bcc: ${bcc}` : null,
315
+ `Subject: ${params.subject}`,
316
+ `Date: ${new Date().toUTCString()}`,
317
+ params.inReplyTo ? `In-Reply-To: ${params.inReplyTo}` : null,
318
+ params.references?.length ? `References: ${params.references.join(" ")}` : null,
319
+ `MIME-Version: 1.0`,
320
+ `Content-Type: text/html; charset=UTF-8`,
321
+ ].filter(h => h !== null).join("\r\n");
322
+ const rawMessage = `${headers}\r\n\r\n${params.bodyHtml || params.bodyText || ""}`;
323
+
324
+ imapManager.queueOutgoingLocal(account.id, rawMessage);
325
+ for (const addr of params.to) db.recordSentAddress(addr.name, addr.address);
326
+ if (params.cc) for (const addr of params.cc) db.recordSentAddress(addr.name, addr.address);
327
+ if (params.bcc) for (const addr of params.bcc) db.recordSentAddress(addr.name, addr.address);
328
+ }
329
+
330
+ export async function saveDraft(params: { accountId: string; subject: string; bodyHtml: string; bodyText: string; to: string; cc: string; previousDraftUid?: number }) {
331
+ const settings = loadSettings();
332
+ const account = settings.accounts.find(a => a.id === params.accountId);
333
+ if (!account) throw new Error(`Unknown account: ${params.accountId}`);
334
+
335
+ const headers = [
336
+ `From: ${account.name} <${account.email}>`,
337
+ params.to ? `To: ${params.to}` : null,
338
+ params.cc ? `Cc: ${params.cc}` : null,
339
+ `Subject: ${params.subject || "(no subject)"}`,
340
+ `Date: ${new Date().toUTCString()}`,
341
+ `MIME-Version: 1.0`,
342
+ `Content-Type: text/html; charset=UTF-8`,
343
+ ].filter(h => h !== null).join("\r\n");
344
+ const raw = `${headers}\r\n\r\n${params.bodyHtml || params.bodyText || ""}`;
345
+
346
+ return await imapManager.saveDraft(params.accountId, raw, params.previousDraftUid);
347
+ }
348
+
349
+ export async function deleteDraft(params: { accountId: string; draftUid: number }) {
350
+ await imapManager.deleteDraft(params.accountId, params.draftUid);
351
+ }
352
+
353
+ export function searchMessages(params: { query: string; page?: number; pageSize?: number }) {
354
+ if (!params.query.trim()) return { items: [], total: 0, page: 1, pageSize: 50 };
355
+ return db.searchMessages(params.query, params.page || 1, params.pageSize || 50);
356
+ }
357
+
358
+ export function searchContacts(params: { query: string }) {
359
+ if (params.query.length < 1) return [];
360
+ return db.searchContacts(params.query);
361
+ }
362
+
363
+ export async function syncAll() {
364
+ await imapManager.syncAll();
365
+ }
366
+
367
+ export function getSyncPending() {
368
+ return { pending: db.getTotalPendingSyncCount() };
369
+ }
370
+
371
+ export async function allowRemoteContent(params: { type: string; value: string }) {
372
+ const list = loadAllowlist();
373
+ if (params.type === "sender" && !list.senders.includes(params.value)) list.senders.push(params.value);
374
+ else if (params.type === "domain" && !list.domains.includes(params.value)) list.domains.push(params.value);
375
+ else if (params.type === "recipient") {
376
+ if (!list.recipients) list.recipients = [];
377
+ if (!list.recipients.includes(params.value)) list.recipients.push(params.value);
378
+ }
379
+ await saveAllowlist(list);
380
+ }
381
+
382
+ export function getSettings() {
383
+ return loadSettings();
384
+ }
385
+
386
+ export function saveSettingsData(data: any) {
387
+ saveSettings(data);
388
+ }
389
+
390
+ export function rebuildSearchIndex() {
391
+ return db.rebuildSearchIndex();
392
+ }
393
+
394
+ export function seedContacts() {
395
+ return db.seedContactsFromMessages();
396
+ }
397
+
398
+ export async function syncGoogleContacts() {
399
+ await imapManager.syncAllContacts();
400
+ }
401
+
402
+ export function getVersion() {
403
+ return { server: "1.0.0", client: "1.0.0" }; // Updated by build
404
+ }
405
+
406
+ // ── Action dispatcher for IPC ──
407
+
408
+ const actions: Record<string, (params: any) => any> = {
409
+ getAccounts, getFolders, getMessages, getUnifiedInbox, getMessage,
410
+ updateFlags, deleteMessage, undeleteMessage, sendMessage,
411
+ saveDraft, deleteDraft, searchMessages, searchContacts,
412
+ syncAll, getSyncPending, allowRemoteContent,
413
+ getSettings, saveSettingsData, rebuildSearchIndex,
414
+ seedContacts, syncGoogleContacts, getVersion,
415
+ };
416
+
417
+ /** Dispatch an action by name — used by IPC and Express wrapper */
418
+ export async function dispatch(action: string, params: any = {}): Promise<any> {
419
+ const fn = actions[action];
420
+ if (!fn) throw new Error(`Unknown action: ${action}`);
421
+ return await fn(params);
422
+ }
423
+
424
+ export { db, imapManager };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ipc.d.ts","sourceRoot":"","sources":["ipc.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,wBAAsB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAsC9C"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ipc.js","sourceRoot":"","sources":["ipc.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE3D,MAAM,CAAC,KAAK,UAAU,QAAQ;IAC1B,kBAAkB;IAClB,MAAM,UAAU,EAAE,CAAC;IAEnB,wBAAwB;IACxB,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;QACd,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAC7D,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,6BAA6B;IAC7B,MAAM,EAAE,GAAG,QAAQ,CAAC,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;IAE/E,EAAE,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QACzB,IAAI,GAAQ,CAAC;QACb,IAAI,CAAC;YACD,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC3B,CAAC;QAAC,MAAM,CAAC;YACL,OAAO,CAAC,sBAAsB;QAClC,CAAC;QAED,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,MAAM,EAAE,GAAG,GAAG,CAAC;QAC1C,IAAI,CAAC,OAAO,IAAI,CAAC,KAAK;YAAE,OAAO;QAE/B,IAAI,CAAC;YACD,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAC/C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;QACtF,CAAC;QAAC,OAAO,CAAM,EAAE,CAAC;YACd,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;QAC7F,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;QAChB,OAAO,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC;QACjD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;AAC/B,CAAC;AAED,kCAAkC;AAClC,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,UAAU,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;IACzF,QAAQ,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;QACjB,OAAO,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;QACjD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * IPC protocol — stdin/stdout JSON lines for Rust↔Node communication.
3
+ * Rust launcher sends JSON requests, Node dispatches to core functions,
4
+ * sends JSON responses back. Events pushed to stdout as well.
5
+ *
6
+ * Protocol:
7
+ * Request: { "_action": "getMessages", "_cbid": "5", "accountId": "bobma", ... }
8
+ * Response: { "_type": "response", "_cbid": "5", "result": { ... } }
9
+ * Error: { "_type": "error", "_cbid": "5", "error": "message" }
10
+ * Event: { "_type": "event", "data": { "type": "folderCountsChanged", ... } }
11
+ */
12
+
13
+ import * as readline from "node:readline";
14
+ import { dispatch, initialize, onEvent } from "./index.js";
15
+
16
+ export async function startIPC(): Promise<void> {
17
+ // Initialize core
18
+ await initialize();
19
+
20
+ // Push events to stdout
21
+ onEvent((event) => {
22
+ const line = JSON.stringify({ _type: "event", data: event });
23
+ process.stdout.write(line + "\n");
24
+ });
25
+
26
+ // Read JSON lines from stdin
27
+ const rl = readline.createInterface({ input: process.stdin, terminal: false });
28
+
29
+ rl.on("line", async (line) => {
30
+ let msg: any;
31
+ try {
32
+ msg = JSON.parse(line);
33
+ } catch {
34
+ return; // Skip malformed JSON
35
+ }
36
+
37
+ const { _action, _cbid, ...params } = msg;
38
+ if (!_action || !_cbid) return;
39
+
40
+ try {
41
+ const result = await dispatch(_action, params);
42
+ process.stdout.write(JSON.stringify({ _type: "response", _cbid, result }) + "\n");
43
+ } catch (e: any) {
44
+ process.stdout.write(JSON.stringify({ _type: "error", _cbid, error: e.message }) + "\n");
45
+ }
46
+ });
47
+
48
+ rl.on("close", () => {
49
+ console.error("IPC stdin closed, shutting down");
50
+ process.exit(0);
51
+ });
52
+
53
+ console.error("IPC ready");
54
+ }
55
+
56
+ // If run directly, start IPC mode
57
+ if (import.meta.url === `file://${process.argv[1]}` || process.argv[1]?.endsWith("ipc.js")) {
58
+ startIPC().catch(e => {
59
+ console.error(`IPC startup error: ${e.message}`);
60
+ process.exit(1);
61
+ });
62
+ }
@@ -11,7 +11,7 @@
11
11
  "dependencies": {
12
12
  "@bobfrankston/mailx-types": "file:../mailx-types",
13
13
  "@bobfrankston/mailx-store": "file:../mailx-store",
14
- "@bobfrankston/mailx-imap": "file:../mailx-imap",
14
+ "@bobfrankston/mailx-imap": "file:../../../packages/mailx-imap",
15
15
  "@bobfrankston/mailx-settings": "file:../mailx-settings",
16
16
  "mailparser": "^3.7.2"
17
17
  }
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "outDir": ".",
5
+ "rootDir": "."
6
+ },
7
+ "include": ["*.ts"],
8
+ "exclude": ["node_modules", "prev", "cruft", "tests"]
9
+ }
@@ -0,0 +1,10 @@
1
+ # Force LF line endings for all text files
2
+ * text=auto eol=lf
3
+
4
+ # Ensure these are always LF
5
+ *.ts text eol=lf
6
+ *.js text eol=lf
7
+ *.json text eol=lf
8
+ *.md text eol=lf
9
+ *.yml text eol=lf
10
+ *.yaml text eol=lf
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,KAAK,MAAM,qBAAqB,CAAC;AAE7C,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAE9F,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,SAAS,CAAC;AAE3C,wBAAgB,UAAU,IAAI,QAAQ,CAIrC;AAWD,eAAO,MAAM,cAAc,6BAAuB,CAAC;AACnD,eAAO,MAAM,WAAW,0BAAoB,CAAC;AAC7C,eAAO,MAAM,UAAU,yBAAmB,CAAC;AAC3C,eAAO,MAAM,UAAU,yBAAmB,CAAC;AAC3C,eAAO,MAAM,QAAQ,EAAE,QAAoB,CAAC"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,KAAK,MAAM,qBAAqB,CAAC;AAM7C,MAAM,UAAU,UAAU;IACtB,MAAM,SAAS,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;IAC/D,IAAI,SAAS,KAAK,OAAO,IAAI,SAAS,KAAK,SAAS;QAAE,OAAO,SAAqB,CAAC;IACnF,OAAO,OAAO,CAAC;AACnB,CAAC;AAED,MAAM,SAAS,GAAa,UAAU,EAAE,CAAC;AAEzC,IAAI,SAAS,KAAK,OAAO,EAAE,CAAC;IACxB,MAAM,IAAI,KAAK,CACX,gBAAgB,SAAS,qEAAqE;QAC9F,oFAAoF,CACvF,CAAC;AACN,CAAC;AAED,MAAM,CAAC,MAAM,cAAc,GAAG,KAAK,CAAC,cAAc,CAAC;AACnD,MAAM,CAAC,MAAM,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC;AAC7C,MAAM,CAAC,MAAM,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC;AAC3C,MAAM,CAAC,MAAM,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC;AAC3C,MAAM,CAAC,MAAM,QAAQ,GAAa,SAAS,CAAC"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * mailx-host — runtime WebView host selector.
3
+ *
4
+ * Today: msger on every platform.
5
+ * Future: lazy-load @bobfrankston/mailx-host-msgview for Mac and niche
6
+ * Linux systems that can't get webkit2gtk-4.1.
7
+ *
8
+ * Callers (bin/mailx.ts) import showMessageBox / showService / setAppName
9
+ * from here instead of @bobfrankston/msger directly, so the swap is a
10
+ * one-line change when msgview arrives.
11
+ */
12
+
13
+ import * as msger from "@bobfrankston/msger";
14
+
15
+ export type { MessageBoxOptions, MessageBoxResult, ServiceHandle } from "@bobfrankston/msger";
16
+
17
+ export type HostName = "msger" | "msgview";
18
+
19
+ export function selectHost(): HostName {
20
+ const requested = (process.env.MAILX_HOST || "").toLowerCase();
21
+ if (requested === "msger" || requested === "msgview") return requested as HostName;
22
+ return "msger";
23
+ }
24
+
25
+ const _hostName: HostName = selectHost();
26
+
27
+ if (_hostName !== "msger") {
28
+ throw new Error(
29
+ `mailx-host: "${_hostName}" adapter not implemented yet — set MAILX_HOST=msger to fall back, ` +
30
+ `or implement @bobfrankston/mailx-host-msgview (see docs/host-abstraction-plan.md).`
31
+ );
32
+ }
33
+
34
+ export const showMessageBox = msger.showMessageBox;
35
+ export const showService = msger.showService;
36
+ export const setAppName = msger.setAppName;
37
+ export const setAppIcon = msger.setAppIcon;
38
+ export const hostName: HostName = _hostName;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bobfrankston/mailx-host",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "Host abstraction for mailx — dispatches to msger or msgview",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -11,7 +11,7 @@
11
11
  },
12
12
  "license": "ISC",
13
13
  "dependencies": {
14
- "@bobfrankston/msger": "file:../../../../utils/msgx/msger"
14
+ "@bobfrankston/msger": "^0.1.367"
15
15
  },
16
16
  "repository": {
17
17
  "type": "git",
@@ -19,5 +19,13 @@
19
19
  },
20
20
  "publishConfig": {
21
21
  "access": "public"
22
+ },
23
+ ".dependencies": {
24
+ "@bobfrankston/msger": "file:../../../../../utils/msgx/msger"
25
+ },
26
+ ".transformedSnapshot": {
27
+ "dependencies": {
28
+ "@bobfrankston/msger": "^0.1.367"
29
+ }
22
30
  }
23
31
  }
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "outDir": ".",
5
+ "rootDir": "."
6
+ },
7
+ "include": ["*.ts", "*.d.ts"],
8
+ "exclude": ["node_modules", "prev", "cruft", "tests"]
9
+ }
@@ -0,0 +1,10 @@
1
+ # Force LF line endings for all text files
2
+ * text=auto eol=lf
3
+
4
+ # Ensure these are always LF
5
+ *.ts text eol=lf
6
+ *.js text eol=lf
7
+ *.json text eol=lf
8
+ *.md text eol=lf
9
+ *.yml text eol=lf
10
+ *.yaml text eol=lf
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-queue.d.ts","sourceRoot":"","sources":["cli-queue.ts"],"names":[],"mappings":";AACA;;;;;;;GAOG"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-queue.js","sourceRoot":"","sources":["cli-queue.ts"],"names":[],"mappings":"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"}