@bobfrankston/mailx 1.0.12 → 1.0.13

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 (237) hide show
  1. package/bin/mailx.js +47 -29
  2. package/client/app.js +93 -13
  3. package/client/components/folder-tree.js +84 -3
  4. package/client/components/message-list.js +134 -8
  5. package/client/components/message-viewer.js +130 -13
  6. package/client/compose/compose.html +4 -4
  7. package/client/compose/compose.js +53 -34
  8. package/client/index.html +33 -9
  9. package/client/lib/api-client.js +102 -30
  10. package/client/lib/mailxapi.js +123 -0
  11. package/client/package.json +1 -1
  12. package/client/styles/components.css +188 -15
  13. package/client/styles/layout.css +2 -1
  14. package/killmail.cmd +6 -0
  15. package/launch.ps1 +47 -5
  16. package/launcher/bin/mailx-app.exe +0 -0
  17. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Breadcrumbs +0 -0
  18. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Crashpad/metadata +0 -0
  19. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Crashpad/settings.dat +0 -0
  20. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Crashpad/throttle_store.dat +1 -0
  21. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/CrashpadMetrics-active.pma +0 -0
  22. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/BrowsingTopicsSiteData +0 -0
  23. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Cache/No_Vary_Search/journal.baj +1 -0
  24. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/DIPS +0 -0
  25. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/DashTrackerDatabase +0 -0
  26. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/EdgeJourneys/EdgeJourneys.db +0 -0
  27. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Extension Rules/LOCK +0 -0
  28. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Extension Rules/LOG +3 -0
  29. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Extension Rules/MANIFEST-000001 +0 -0
  30. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Extension Scripts/LOCK +0 -0
  31. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Extension Scripts/LOG +3 -0
  32. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Extension Scripts/MANIFEST-000001 +0 -0
  33. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Extension State/LOCK +0 -0
  34. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Extension State/LOG +3 -0
  35. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Extension State/MANIFEST-000001 +0 -0
  36. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/ExtensionActivityComp +0 -0
  37. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/ExtensionActivityEdge +0 -0
  38. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Favicons +0 -0
  39. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/History +0 -0
  40. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/History-journal +0 -0
  41. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/IndexedDB/devtools_devtools_0.indexeddb.leveldb/LOCK +0 -0
  42. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/IndexedDB/devtools_devtools_0.indexeddb.leveldb/LOG +3 -0
  43. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/IndexedDB/devtools_devtools_0.indexeddb.leveldb/MANIFEST-000001 +0 -0
  44. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Local Storage/leveldb/LOCK +0 -0
  45. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Local Storage/leveldb/LOG +3 -0
  46. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Local Storage/leveldb/MANIFEST-000001 +0 -0
  47. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Login Data +0 -0
  48. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Login Data For Account +0 -0
  49. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Network/Cookies +0 -0
  50. NEL +0 -0
  51. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Network/Trust Tokens +0 -0
  52. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Network Action Predictor +0 -0
  53. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Preferences +1 -0
  54. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Safe Browsing Network/Safe Browsing Cookies +0 -0
  55. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/ServerCertificate +0 -0
  56. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Session Storage/LOCK +0 -0
  57. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Session Storage/LOG +3 -0
  58. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Session Storage/MANIFEST-000001 +0 -0
  59. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Shared Dictionary/db +0 -0
  60. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/SharedStorage +0 -0
  61. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Shortcuts +0 -0
  62. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Site Characteristics Database/LOCK +0 -0
  63. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Site Characteristics Database/LOG +3 -0
  64. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Site Characteristics Database/MANIFEST-000001 +0 -0
  65. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Sync Data/LevelDB/LOCK +0 -0
  66. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Sync Data/LevelDB/LOG +3 -0
  67. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Sync Data/LevelDB/MANIFEST-000001 +0 -0
  68. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Top Sites +0 -0
  69. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Vpn Tokens +0 -0
  70. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Web Data +0 -0
  71. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/Web Data-journal +0 -0
  72. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/WebStorage/QuotaManager +0 -0
  73. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/WebStorage/QuotaManager-journal +0 -0
  74. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/heavy_ad_intervention_opt_out.db +0 -0
  75. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/shared_proto_db/LOCK +0 -0
  76. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/shared_proto_db/LOG +3 -0
  77. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/shared_proto_db/MANIFEST-000001 +0 -0
  78. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/shared_proto_db/metadata/LOCK +0 -0
  79. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/shared_proto_db/metadata/LOG +3 -0
  80. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Default/shared_proto_db/metadata/MANIFEST-000001 +0 -0
  81. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/DeferredBrowserMetrics/BrowserMetrics-69CAD063-BE24.pma +0 -0
  82. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Local State +1 -0
  83. package/launcher/bin/mailx-app.exe.WebView2/EBWebView/Variations +1 -0
  84. package/launcher/bin/mailx-app.old.exe +0 -0
  85. package/package.json +1 -1
  86. package/packages/mailx-api/index.js +79 -26
  87. package/packages/mailx-core/index.d.ts +129 -0
  88. package/packages/mailx-core/index.js +323 -0
  89. package/packages/mailx-core/ipc.d.ts +13 -0
  90. package/packages/mailx-core/ipc.js +56 -0
  91. package/packages/mailx-core/package.json +18 -0
  92. package/packages/mailx-imap/index.d.ts +5 -1
  93. package/packages/mailx-imap/index.js +76 -14
  94. package/packages/mailx-server/index.js +42 -31
  95. package/packages/mailx-server/package.json +1 -2
  96. package/packages/mailx-settings/index.d.ts +1 -1
  97. package/packages/mailx-settings/index.js +21 -12
  98. package/packages/mailx-store/db.d.ts +5 -1
  99. package/packages/mailx-store/db.js +64 -12
  100. package/packages/mailx-store/file-store.d.ts +2 -8
  101. package/packages/mailx-store/file-store.js +7 -31
  102. package/packages/mailx-types/index.d.ts +3 -1
  103. package/.tswalk.json +0 -7396
  104. package/launcher/release.cmd +0 -4
  105. package/mailx.json +0 -9
  106. package/packages/mailx-api/node_modules/nodemailer/.ncurc.js +0 -9
  107. package/packages/mailx-api/node_modules/nodemailer/.prettierignore +0 -8
  108. package/packages/mailx-api/node_modules/nodemailer/.prettierrc +0 -12
  109. package/packages/mailx-api/node_modules/nodemailer/.prettierrc.js +0 -10
  110. package/packages/mailx-api/node_modules/nodemailer/.release-please-config.json +0 -9
  111. package/packages/mailx-api/node_modules/nodemailer/LICENSE +0 -16
  112. package/packages/mailx-api/node_modules/nodemailer/README.md +0 -86
  113. package/packages/mailx-api/node_modules/nodemailer/SECURITY.txt +0 -22
  114. package/packages/mailx-api/node_modules/nodemailer/eslint.config.js +0 -88
  115. package/packages/mailx-api/node_modules/nodemailer/lib/addressparser/index.js +0 -383
  116. package/packages/mailx-api/node_modules/nodemailer/lib/base64/index.js +0 -139
  117. package/packages/mailx-api/node_modules/nodemailer/lib/dkim/index.js +0 -253
  118. package/packages/mailx-api/node_modules/nodemailer/lib/dkim/message-parser.js +0 -155
  119. package/packages/mailx-api/node_modules/nodemailer/lib/dkim/relaxed-body.js +0 -154
  120. package/packages/mailx-api/node_modules/nodemailer/lib/dkim/sign.js +0 -117
  121. package/packages/mailx-api/node_modules/nodemailer/lib/fetch/cookies.js +0 -281
  122. package/packages/mailx-api/node_modules/nodemailer/lib/fetch/index.js +0 -280
  123. package/packages/mailx-api/node_modules/nodemailer/lib/json-transport/index.js +0 -82
  124. package/packages/mailx-api/node_modules/nodemailer/lib/mail-composer/index.js +0 -629
  125. package/packages/mailx-api/node_modules/nodemailer/lib/mailer/index.js +0 -441
  126. package/packages/mailx-api/node_modules/nodemailer/lib/mailer/mail-message.js +0 -316
  127. package/packages/mailx-api/node_modules/nodemailer/lib/mime-funcs/index.js +0 -625
  128. package/packages/mailx-api/node_modules/nodemailer/lib/mime-funcs/mime-types.js +0 -2113
  129. package/packages/mailx-api/node_modules/nodemailer/lib/mime-node/index.js +0 -1316
  130. package/packages/mailx-api/node_modules/nodemailer/lib/mime-node/last-newline.js +0 -33
  131. package/packages/mailx-api/node_modules/nodemailer/lib/mime-node/le-unix.js +0 -43
  132. package/packages/mailx-api/node_modules/nodemailer/lib/mime-node/le-windows.js +0 -52
  133. package/packages/mailx-api/node_modules/nodemailer/lib/nodemailer.js +0 -157
  134. package/packages/mailx-api/node_modules/nodemailer/lib/punycode/index.js +0 -460
  135. package/packages/mailx-api/node_modules/nodemailer/lib/qp/index.js +0 -227
  136. package/packages/mailx-api/node_modules/nodemailer/lib/sendmail-transport/index.js +0 -210
  137. package/packages/mailx-api/node_modules/nodemailer/lib/ses-transport/index.js +0 -234
  138. package/packages/mailx-api/node_modules/nodemailer/lib/shared/index.js +0 -754
  139. package/packages/mailx-api/node_modules/nodemailer/lib/smtp-connection/data-stream.js +0 -108
  140. package/packages/mailx-api/node_modules/nodemailer/lib/smtp-connection/http-proxy-client.js +0 -143
  141. package/packages/mailx-api/node_modules/nodemailer/lib/smtp-connection/index.js +0 -1870
  142. package/packages/mailx-api/node_modules/nodemailer/lib/smtp-pool/index.js +0 -652
  143. package/packages/mailx-api/node_modules/nodemailer/lib/smtp-pool/pool-resource.js +0 -259
  144. package/packages/mailx-api/node_modules/nodemailer/lib/smtp-transport/index.js +0 -421
  145. package/packages/mailx-api/node_modules/nodemailer/lib/stream-transport/index.js +0 -135
  146. package/packages/mailx-api/node_modules/nodemailer/lib/well-known/index.js +0 -47
  147. package/packages/mailx-api/node_modules/nodemailer/lib/well-known/services.json +0 -611
  148. package/packages/mailx-api/node_modules/nodemailer/lib/xoauth2/index.js +0 -427
  149. package/packages/mailx-api/node_modules/nodemailer/package.json +0 -47
  150. package/packages/mailx-imap/node_modules/nodemailer/.ncurc.js +0 -9
  151. package/packages/mailx-imap/node_modules/nodemailer/.prettierignore +0 -8
  152. package/packages/mailx-imap/node_modules/nodemailer/.prettierrc +0 -12
  153. package/packages/mailx-imap/node_modules/nodemailer/.prettierrc.js +0 -10
  154. package/packages/mailx-imap/node_modules/nodemailer/.release-please-config.json +0 -9
  155. package/packages/mailx-imap/node_modules/nodemailer/LICENSE +0 -16
  156. package/packages/mailx-imap/node_modules/nodemailer/README.md +0 -86
  157. package/packages/mailx-imap/node_modules/nodemailer/SECURITY.txt +0 -22
  158. package/packages/mailx-imap/node_modules/nodemailer/eslint.config.js +0 -88
  159. package/packages/mailx-imap/node_modules/nodemailer/lib/addressparser/index.js +0 -383
  160. package/packages/mailx-imap/node_modules/nodemailer/lib/base64/index.js +0 -139
  161. package/packages/mailx-imap/node_modules/nodemailer/lib/dkim/index.js +0 -253
  162. package/packages/mailx-imap/node_modules/nodemailer/lib/dkim/message-parser.js +0 -155
  163. package/packages/mailx-imap/node_modules/nodemailer/lib/dkim/relaxed-body.js +0 -154
  164. package/packages/mailx-imap/node_modules/nodemailer/lib/dkim/sign.js +0 -117
  165. package/packages/mailx-imap/node_modules/nodemailer/lib/fetch/cookies.js +0 -281
  166. package/packages/mailx-imap/node_modules/nodemailer/lib/fetch/index.js +0 -280
  167. package/packages/mailx-imap/node_modules/nodemailer/lib/json-transport/index.js +0 -82
  168. package/packages/mailx-imap/node_modules/nodemailer/lib/mail-composer/index.js +0 -629
  169. package/packages/mailx-imap/node_modules/nodemailer/lib/mailer/index.js +0 -441
  170. package/packages/mailx-imap/node_modules/nodemailer/lib/mailer/mail-message.js +0 -316
  171. package/packages/mailx-imap/node_modules/nodemailer/lib/mime-funcs/index.js +0 -625
  172. package/packages/mailx-imap/node_modules/nodemailer/lib/mime-funcs/mime-types.js +0 -2113
  173. package/packages/mailx-imap/node_modules/nodemailer/lib/mime-node/index.js +0 -1316
  174. package/packages/mailx-imap/node_modules/nodemailer/lib/mime-node/last-newline.js +0 -33
  175. package/packages/mailx-imap/node_modules/nodemailer/lib/mime-node/le-unix.js +0 -43
  176. package/packages/mailx-imap/node_modules/nodemailer/lib/mime-node/le-windows.js +0 -52
  177. package/packages/mailx-imap/node_modules/nodemailer/lib/nodemailer.js +0 -157
  178. package/packages/mailx-imap/node_modules/nodemailer/lib/punycode/index.js +0 -460
  179. package/packages/mailx-imap/node_modules/nodemailer/lib/qp/index.js +0 -227
  180. package/packages/mailx-imap/node_modules/nodemailer/lib/sendmail-transport/index.js +0 -210
  181. package/packages/mailx-imap/node_modules/nodemailer/lib/ses-transport/index.js +0 -234
  182. package/packages/mailx-imap/node_modules/nodemailer/lib/shared/index.js +0 -754
  183. package/packages/mailx-imap/node_modules/nodemailer/lib/smtp-connection/data-stream.js +0 -108
  184. package/packages/mailx-imap/node_modules/nodemailer/lib/smtp-connection/http-proxy-client.js +0 -143
  185. package/packages/mailx-imap/node_modules/nodemailer/lib/smtp-connection/index.js +0 -1870
  186. package/packages/mailx-imap/node_modules/nodemailer/lib/smtp-pool/index.js +0 -652
  187. package/packages/mailx-imap/node_modules/nodemailer/lib/smtp-pool/pool-resource.js +0 -259
  188. package/packages/mailx-imap/node_modules/nodemailer/lib/smtp-transport/index.js +0 -421
  189. package/packages/mailx-imap/node_modules/nodemailer/lib/stream-transport/index.js +0 -135
  190. package/packages/mailx-imap/node_modules/nodemailer/lib/well-known/index.js +0 -47
  191. package/packages/mailx-imap/node_modules/nodemailer/lib/well-known/services.json +0 -611
  192. package/packages/mailx-imap/node_modules/nodemailer/lib/xoauth2/index.js +0 -427
  193. package/packages/mailx-imap/node_modules/nodemailer/package.json +0 -47
  194. package/packages/mailx-send/node_modules/nodemailer/.ncurc.js +0 -9
  195. package/packages/mailx-send/node_modules/nodemailer/.prettierignore +0 -8
  196. package/packages/mailx-send/node_modules/nodemailer/.prettierrc +0 -12
  197. package/packages/mailx-send/node_modules/nodemailer/.prettierrc.js +0 -10
  198. package/packages/mailx-send/node_modules/nodemailer/.release-please-config.json +0 -9
  199. package/packages/mailx-send/node_modules/nodemailer/LICENSE +0 -16
  200. package/packages/mailx-send/node_modules/nodemailer/README.md +0 -86
  201. package/packages/mailx-send/node_modules/nodemailer/SECURITY.txt +0 -22
  202. package/packages/mailx-send/node_modules/nodemailer/eslint.config.js +0 -88
  203. package/packages/mailx-send/node_modules/nodemailer/lib/addressparser/index.js +0 -383
  204. package/packages/mailx-send/node_modules/nodemailer/lib/base64/index.js +0 -139
  205. package/packages/mailx-send/node_modules/nodemailer/lib/dkim/index.js +0 -253
  206. package/packages/mailx-send/node_modules/nodemailer/lib/dkim/message-parser.js +0 -155
  207. package/packages/mailx-send/node_modules/nodemailer/lib/dkim/relaxed-body.js +0 -154
  208. package/packages/mailx-send/node_modules/nodemailer/lib/dkim/sign.js +0 -117
  209. package/packages/mailx-send/node_modules/nodemailer/lib/fetch/cookies.js +0 -281
  210. package/packages/mailx-send/node_modules/nodemailer/lib/fetch/index.js +0 -280
  211. package/packages/mailx-send/node_modules/nodemailer/lib/json-transport/index.js +0 -82
  212. package/packages/mailx-send/node_modules/nodemailer/lib/mail-composer/index.js +0 -629
  213. package/packages/mailx-send/node_modules/nodemailer/lib/mailer/index.js +0 -441
  214. package/packages/mailx-send/node_modules/nodemailer/lib/mailer/mail-message.js +0 -316
  215. package/packages/mailx-send/node_modules/nodemailer/lib/mime-funcs/index.js +0 -625
  216. package/packages/mailx-send/node_modules/nodemailer/lib/mime-funcs/mime-types.js +0 -2113
  217. package/packages/mailx-send/node_modules/nodemailer/lib/mime-node/index.js +0 -1316
  218. package/packages/mailx-send/node_modules/nodemailer/lib/mime-node/last-newline.js +0 -33
  219. package/packages/mailx-send/node_modules/nodemailer/lib/mime-node/le-unix.js +0 -43
  220. package/packages/mailx-send/node_modules/nodemailer/lib/mime-node/le-windows.js +0 -52
  221. package/packages/mailx-send/node_modules/nodemailer/lib/nodemailer.js +0 -157
  222. package/packages/mailx-send/node_modules/nodemailer/lib/punycode/index.js +0 -460
  223. package/packages/mailx-send/node_modules/nodemailer/lib/qp/index.js +0 -227
  224. package/packages/mailx-send/node_modules/nodemailer/lib/sendmail-transport/index.js +0 -210
  225. package/packages/mailx-send/node_modules/nodemailer/lib/ses-transport/index.js +0 -234
  226. package/packages/mailx-send/node_modules/nodemailer/lib/shared/index.js +0 -754
  227. package/packages/mailx-send/node_modules/nodemailer/lib/smtp-connection/data-stream.js +0 -108
  228. package/packages/mailx-send/node_modules/nodemailer/lib/smtp-connection/http-proxy-client.js +0 -143
  229. package/packages/mailx-send/node_modules/nodemailer/lib/smtp-connection/index.js +0 -1870
  230. package/packages/mailx-send/node_modules/nodemailer/lib/smtp-pool/index.js +0 -652
  231. package/packages/mailx-send/node_modules/nodemailer/lib/smtp-pool/pool-resource.js +0 -259
  232. package/packages/mailx-send/node_modules/nodemailer/lib/smtp-transport/index.js +0 -421
  233. package/packages/mailx-send/node_modules/nodemailer/lib/stream-transport/index.js +0 -135
  234. package/packages/mailx-send/node_modules/nodemailer/lib/well-known/index.js +0 -47
  235. package/packages/mailx-send/node_modules/nodemailer/lib/well-known/services.json +0 -611
  236. package/packages/mailx-send/node_modules/nodemailer/lib/xoauth2/index.js +0 -427
  237. package/packages/mailx-send/node_modules/nodemailer/package.json +0 -47
@@ -11,10 +11,10 @@ import { ImapManager } from "@bobfrankston/mailx-imap";
11
11
  import { createApiRouter } from "@bobfrankston/mailx-api";
12
12
  import { loadSettings, getConfigDir, initLocalConfig } from "@bobfrankston/mailx-settings";
13
13
  import { ports } from "@bobfrankston/miscinfo";
14
- import { InitServerAsync, InitServerOptions } from "@bobfrankston/certsupport";
14
+ import { createServer } from "node:http";
15
15
  const PORT = ports.mailx;
16
16
  // ── File logging ──
17
- const logDir = path.join(process.env.USERPROFILE || process.env.HOME || ".", ".mailx");
17
+ const logDir = path.join(process.env.USERPROFILE || process.env.HOME || ".", ".mailx", "logs");
18
18
  fs.mkdirSync(logDir, { recursive: true });
19
19
  // Rotate: delete logs older than 7 days
20
20
  try {
@@ -53,7 +53,19 @@ const db = new MailxDB(dbDir);
53
53
  const imapManager = new ImapManager(db);
54
54
  // ── Express App ──
55
55
  const app = express();
56
- app.use(express.json());
56
+ app.use(express.json({ limit: "Infinity" }));
57
+ // Request logging
58
+ app.use((req, res, next) => {
59
+ const start = Date.now();
60
+ res.on("finish", () => {
61
+ const ms = Date.now() - start;
62
+ // Skip noisy polling endpoints
63
+ if (req.path === "/api/sync/pending")
64
+ return;
65
+ console.log(` ${req.method} ${req.path} ${res.statusCode} ${ms}ms`);
66
+ });
67
+ next();
68
+ });
57
69
  // Serve client static files
58
70
  const clientDir = path.join(import.meta.dirname, "..", "..", "client");
59
71
  const rootDir = path.join(import.meta.dirname, "..", "..");
@@ -97,15 +109,14 @@ ${accountInfo.map((a) => `<tr><td>${a.name}</td><td>${a.folders}</td><td>${a.inb
97
109
  <p style="margin-top:2rem;font-size:0.8rem"><a href="/">Open mailx</a> | Auto-refreshes every 10s</p>
98
110
  </body></html>`);
99
111
  });
100
- // Dev: restart server + reload clients
112
+ // Restart server + reload clients
101
113
  app.post("/api/restart", (req, res) => {
102
114
  res.json({ ok: true });
103
115
  broadcast({ type: "reload" });
104
- // Touch the server file to trigger node --watch restart
105
- const serverFile = path.join(import.meta.dirname, "index.js");
106
- setTimeout(() => {
107
- const now = new Date();
108
- fs.utimesSync(serverFile, now, now);
116
+ // Graceful shutdown node --watch will auto-restart
117
+ setTimeout(async () => {
118
+ console.log(" Restart requested via API");
119
+ await shutdown();
109
120
  }, 500);
110
121
  });
111
122
  // SPA fallback
@@ -113,8 +124,13 @@ app.get("*", (req, res) => {
113
124
  if (!req.path.startsWith("/api"))
114
125
  res.sendFile(path.join(clientDir, "index.html"));
115
126
  });
116
- // ── HTTPS Server (certsupport with SNI) ──
117
- const certspath = path.join(import.meta.dirname, "certs");
127
+ // JSON error handler all errors return JSON, never HTML
128
+ app.use((err, _req, res, _next) => {
129
+ console.error(`ERROR ${err.message}`);
130
+ const status = err.status || err.statusCode || 500;
131
+ res.status(status).json({ error: err.message || "Internal server error" });
132
+ });
133
+ // ── HTTP Server ──
118
134
  let server;
119
135
  let wss;
120
136
  const clients = new Set();
@@ -147,19 +163,19 @@ async function start() {
147
163
  const seeded = db.seedContactsFromMessages();
148
164
  if (seeded > 0)
149
165
  console.log(` Seeded ${seeded} contacts`);
150
- // Search index — only rebuild if empty (new DB or after reset)
151
- try {
152
- const ftsCount = db.db.prepare("SELECT COUNT(*) as cnt FROM messages_fts").get();
153
- if (!ftsCount?.cnt) {
166
+ // Search index — rebuild in background after server starts (non-blocking)
167
+ setTimeout(() => {
168
+ let ftsCount = 0;
169
+ try {
170
+ ftsCount = db.db.prepare("SELECT COUNT(*) as cnt FROM messages_fts").get()?.cnt || 0;
171
+ }
172
+ catch { /* */ }
173
+ if (ftsCount === 0) {
154
174
  const indexed = db.rebuildSearchIndex();
155
- console.log(` Search index built: ${indexed} messages`);
175
+ if (indexed > 0)
176
+ console.log(` Search index: ${indexed} messages`);
156
177
  }
157
- }
158
- catch {
159
- // FTS table might not exist yet
160
- const indexed = db.rebuildSearchIndex();
161
- console.log(` Search index built: ${indexed} messages`);
162
- }
178
+ }, 5000);
163
179
  // Add configured accounts
164
180
  for (const account of settings.accounts) {
165
181
  if (!account.enabled)
@@ -191,17 +207,12 @@ async function start() {
191
207
  imapManager.startOutboxWorker();
192
208
  // Start server — localhost only by default, --external for network access
193
209
  const externalAccess = process.argv.includes("--external");
194
- const opts = new InitServerOptions({
195
- port: PORT,
196
- hostname: externalAccess ? undefined : "127.0.0.1",
197
- app,
198
- certspath,
199
- msger: (msg) => console.log(` [cert] ${msg}`),
200
- });
201
- server = await InitServerAsync(opts);
210
+ const hostname = externalAccess ? "0.0.0.0" : "127.0.0.1";
211
+ server = createServer(app);
202
212
  wss = new WebSocketServer({ server });
203
213
  wireWebSocket();
204
- console.log(`mailx server running on port ${PORT} (http+https)`);
214
+ await new Promise((resolve) => server.listen(PORT, hostname, resolve));
215
+ console.log(`mailx server running on http://${hostname}:${PORT}`);
205
216
  }
206
217
  // ── Graceful Shutdown ──
207
218
  async function shutdown() {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bobfrankston/mailx-server",
3
- "version": "1.0.4",
3
+ "version": "1.0.7",
4
4
  "type": "module",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -14,7 +14,6 @@
14
14
  "@bobfrankston/mailx-imap": "file:../mailx-imap",
15
15
  "@bobfrankston/mailx-api": "file:../mailx-api",
16
16
  "@bobfrankston/mailx-settings": "file:../mailx-settings",
17
- "@bobfrankston/certsupport": "file:../../../../projects/nodejs/certsupport",
18
17
  "express": "^4.21.0",
19
18
  "ws": "^8.18.0"
20
19
  },
@@ -8,7 +8,7 @@
8
8
  * allowlist.jsonc — remote content allow-list
9
9
  *
10
10
  * Local overrides (~/.mailx/):
11
- * config.json — pointer to shared dir + local-only settings (storePath, historyDays)
11
+ * config.jsonc — pointer to shared dir + local-only settings (storePath, historyDays)
12
12
  * accounts.jsonc — cached copy, fallback when shared unavailable
13
13
  * preferences.jsonc — local overrides merged on top of shared
14
14
  * allowlist.jsonc — cached copy
@@ -8,7 +8,7 @@
8
8
  * allowlist.jsonc — remote content allow-list
9
9
  *
10
10
  * Local overrides (~/.mailx/):
11
- * config.json — pointer to shared dir + local-only settings (storePath, historyDays)
11
+ * config.jsonc — pointer to shared dir + local-only settings (storePath, historyDays)
12
12
  * accounts.jsonc — cached copy, fallback when shared unavailable
13
13
  * preferences.jsonc — local overrides merged on top of shared
14
14
  * allowlist.jsonc — cached copy
@@ -20,17 +20,17 @@ import * as path from "node:path";
20
20
  import { parse as parseJsonc } from "jsonc-parser";
21
21
  // ── Paths ──
22
22
  const LOCAL_DIR = path.join(process.env.USERPROFILE || process.env.HOME || ".", ".mailx");
23
- const LOCAL_CONFIG_PATH = path.join(LOCAL_DIR, "config.json");
23
+ const LOCAL_CONFIG_PATH = path.join(LOCAL_DIR, "config.jsonc");
24
+ const LEGACY_CONFIG_PATH = path.join(LOCAL_DIR, "config.json");
24
25
  const DEFAULT_STORE_PATH = path.join(LOCAL_DIR, "mailxstore");
25
26
  function readLocalConfig() {
26
- if (!fs.existsSync(LOCAL_CONFIG_PATH))
27
- return {};
28
- try {
29
- return JSON.parse(fs.readFileSync(LOCAL_CONFIG_PATH, "utf-8"));
27
+ // Migrate config.json → config.jsonc
28
+ if (!fs.existsSync(LOCAL_CONFIG_PATH) && fs.existsSync(LEGACY_CONFIG_PATH)) {
29
+ fs.renameSync(LEGACY_CONFIG_PATH, LOCAL_CONFIG_PATH);
30
30
  }
31
- catch {
31
+ if (!fs.existsSync(LOCAL_CONFIG_PATH))
32
32
  return {};
33
- }
33
+ return readJsonc(LOCAL_CONFIG_PATH) || {};
34
34
  }
35
35
  function getSharedDir() {
36
36
  const config = readLocalConfig();
@@ -42,14 +42,23 @@ function getSharedDir() {
42
42
  return LOCAL_DIR;
43
43
  }
44
44
  // ── File helpers ──
45
+ /** Read JSON or JSONC file. If exact path not found, tries .json/.jsonc variant. */
45
46
  function readJsonc(filePath) {
46
- if (!fs.existsSync(filePath))
47
- return null;
47
+ let actual = filePath;
48
+ if (!fs.existsSync(actual)) {
49
+ // Try alternate extension
50
+ if (actual.endsWith(".jsonc"))
51
+ actual = actual.replace(/\.jsonc$/, ".json");
52
+ else if (actual.endsWith(".json"))
53
+ actual = actual.replace(/\.json$/, ".jsonc");
54
+ if (!fs.existsSync(actual))
55
+ return null;
56
+ }
48
57
  try {
49
- return parseJsonc(fs.readFileSync(filePath, "utf-8"));
58
+ return parseJsonc(fs.readFileSync(actual, "utf-8"));
50
59
  }
51
60
  catch (e) {
52
- console.error(`Failed to read ${filePath}: ${e.message}`);
61
+ console.error(`Failed to read ${actual}: ${e.message}`);
53
62
  return null;
54
63
  }
55
64
  }
@@ -44,7 +44,9 @@ export declare class MailxDB {
44
44
  bodyPath: string;
45
45
  }): number;
46
46
  getMessages(query: MessageQuery): PagedResult<MessageEnvelope>;
47
- getMessageByUid(accountId: string, uid: number): MessageEnvelope;
47
+ /** Unified inbox: all inbox folders across accounts, sorted by date, paginated in SQL */
48
+ getUnifiedInbox(page?: number, pageSize?: number): PagedResult<MessageEnvelope>;
49
+ getMessageByUid(accountId: string, uid: number, folderId?: number): MessageEnvelope;
48
50
  getMessageBodyPath(accountId: string, uid: number): string;
49
51
  updateMessageFlags(accountId: string, uid: number, flags: string[]): void;
50
52
  getHighestUid(accountId: string, folderId: number): number;
@@ -52,6 +54,8 @@ export declare class MailxDB {
52
54
  getUidsForFolder(accountId: string, folderId: number): number[];
53
55
  /** Delete a message by account + UID */
54
56
  deleteMessage(accountId: string, uid: number): void;
57
+ /** Recalculate folder total/unread counts from actual messages */
58
+ recalcFolderCounts(folderId: number): void;
55
59
  /** Bulk insert within a transaction for sync performance */
56
60
  beginTransaction(): void;
57
61
  commitTransaction(): void;
@@ -241,8 +241,43 @@ export class MailxDB {
241
241
  }));
242
242
  return { items, total, page, pageSize };
243
243
  }
244
- getMessageByUid(accountId, uid) {
245
- const r = this.db.prepare("SELECT * FROM messages WHERE account_id = ? AND uid = ?").get(accountId, uid);
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"); }
@@ -401,19 +448,24 @@ export class MailxDB {
401
448
  subject, from_name, from_address, to_text, cc_text, body_text,
402
449
  content=messages, content_rowid=id
403
450
  )`);
451
+ // Use a single transaction + prepared statement for speed (~50x faster than individual inserts)
452
+ const insert = this.db.prepare("INSERT INTO messages_fts (rowid, subject, from_name, from_address, to_text, cc_text, body_text) VALUES (?, ?, ?, ?, ?, ?, ?)");
404
453
  const rows = this.db.prepare("SELECT id, subject, from_name, from_address, to_json, cc_json, preview FROM messages").all();
405
454
  let count = 0;
406
- for (const r of rows) {
407
- const to = JSON.parse(r.to_json || "[]");
408
- const cc = JSON.parse(r.cc_json || "[]");
409
- const toText = to.map((a) => `${a.name} ${a.address}`).join(" ");
410
- const ccText = cc.map((a) => `${a.name} ${a.address}`).join(" ");
411
- try {
412
- this.db.prepare("INSERT INTO messages_fts (rowid, subject, from_name, from_address, to_text, cc_text, body_text) VALUES (?, ?, ?, ?, ?, ?, ?)").run(r.id, r.subject, r.from_name, r.from_address, toText, ccText, r.preview);
413
- count++;
455
+ const batchInsert = this.db.transaction(() => {
456
+ for (const r of rows) {
457
+ const to = JSON.parse(r.to_json || "[]");
458
+ const cc = JSON.parse(r.cc_json || "[]");
459
+ const toText = to.map((a) => `${a.name} ${a.address}`).join(" ");
460
+ const ccText = cc.map((a) => `${a.name} ${a.address}`).join(" ");
461
+ try {
462
+ insert.run(r.id, r.subject, r.from_name, r.from_address, toText, ccText, r.preview);
463
+ count++;
464
+ }
465
+ catch { /* skip duplicates */ }
414
466
  }
415
- catch { /* skip duplicates */ }
416
- }
467
+ });
468
+ batchInsert();
417
469
  return count;
418
470
  }
419
471
  // ── Sync Actions ──
@@ -1,19 +1,13 @@
1
1
  /**
2
2
  * File-per-message body storage backend.
3
- * Messages stored as: {basePath}/{accountId}/{folderName}/{uid}.eml
4
- * Legacy: also checks {basePath}/{accountId}/{folderId}/{uid}.eml
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}/{folderName}/{uid}.eml
4
- * Legacy: also checks {basePath}/{accountId}/{folderId}/{uid}.eml
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
- const filePath = this.messagePath(accountId, folderId, uid);
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
- for (const p of [this.messagePath(accountId, folderId, uid), this.legacyPath(accountId, folderId, uid)]) {
50
- if (fs.existsSync(p))
51
- fs.unlinkSync(p);
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; /** Display name */
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";