@wirecat/mail-cli 0.4.0 → 0.6.0

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 (281) hide show
  1. package/CHANGELOG.md +115 -0
  2. package/README.md +41 -10
  3. package/dist/bin/mail.js +2 -2
  4. package/dist/bundle/{all-profiles-55XPXQHY.js → all-profiles-GBFTKUHA.js} +9 -9
  5. package/dist/bundle/{anthropic-K5B6I4LB.js → anthropic-PTSCWUG6.js} +6 -6
  6. package/dist/bundle/{app-server-VWWLQLTZ.js → app-server-5VJ2WCKJ.js} +46 -46
  7. package/dist/bundle/{bun-EO7AI6YP.js → bun-2KRUBPIN.js} +2 -2
  8. package/dist/bundle/{bun-sqlite-F24A4IOP.js → bun-sqlite-ELSRSJBM.js} +5 -5
  9. package/dist/bundle/{chunk-X7AXH2IC.js → chunk-3KY7DA5A.js} +428 -434
  10. package/dist/bundle/{chunk-ANRI6EZY.js → chunk-4PKHZQIM.js} +8 -8
  11. package/dist/bundle/{chunk-CADRRSQK.js → chunk-56PI2BRH.js} +1 -1
  12. package/dist/bundle/{chunk-2ADB5DSG.js → chunk-5AQKM47C.js} +3 -3
  13. package/dist/bundle/{chunk-VP5GCMHM.js → chunk-5KHJUYHQ.js} +8 -8
  14. package/dist/bundle/{chunk-HUB42T2Z.js → chunk-6MV2TBDB.js} +57 -54
  15. package/dist/bundle/{chunk-4KLJN3LK.js → chunk-AGX7NR3S.js} +26 -13
  16. package/dist/bundle/{chunk-ZD3WUGR2.js → chunk-B337KHJ5.js} +4 -4
  17. package/dist/bundle/{chunk-5BVIWP3S.js → chunk-BM445GYF.js} +2 -2
  18. package/dist/bundle/{chunk-H7K2DN3R.js → chunk-BVIHT7KR.js} +9 -9
  19. package/dist/bundle/{chunk-EDKV6D6T.js → chunk-DA46WQEA.js} +1 -1
  20. package/dist/bundle/{chunk-UO7X2VW4.js → chunk-DV4RSEAH.js} +6 -6
  21. package/dist/bundle/{chunk-JZFIHVRB.js → chunk-ES4PWHBJ.js} +28 -28
  22. package/dist/bundle/{chunk-7X64JS6S.js → chunk-FIQOBLHS.js} +1 -1
  23. package/dist/bundle/{chunk-TI6VBZKJ.js → chunk-FUB3X25H.js} +4 -4
  24. package/dist/bundle/{chunk-VWXCEEUH.js → chunk-H4VFIH5W.js} +3 -3
  25. package/dist/bundle/{chunk-JKHI3PH7.js → chunk-J4C32YKH.js} +1 -1
  26. package/dist/bundle/{chunk-F6JTOQIK.js → chunk-J5MYH4L5.js} +12 -6
  27. package/dist/bundle/{chunk-QYWDC7NP.js → chunk-JFJTDL22.js} +47 -46
  28. package/dist/bundle/{chunk-UZDHK26H.js → chunk-JIQAFFPV.js} +2 -2
  29. package/dist/bundle/{chunk-BHKI5OCD.js → chunk-JKA2AICL.js} +2 -2
  30. package/dist/bundle/{dist-FMN7UZ7R.js → chunk-JKLQHPED.js} +16 -116
  31. package/dist/bundle/{chunk-J3QXTBD2.js → chunk-JLRMSNPX.js} +18 -18
  32. package/dist/bundle/{chunk-HORM6VRV.js → chunk-K5JUROGN.js} +1 -1
  33. package/dist/bundle/{chunk-SY3SP7EI.js → chunk-KUQYWIVR.js} +6 -6
  34. package/dist/bundle/{chunk-7QQ4EMYF.js → chunk-LWTG5UOF.js} +2 -2
  35. package/dist/bundle/{chunk-YSSMDVT3.js → chunk-M7V3GSJQ.js} +1 -1
  36. package/dist/bundle/chunk-MD2J3POF.js +52 -0
  37. package/dist/bundle/{chunk-SWRNMYDL.js → chunk-NCWO2FNC.js} +2 -2
  38. package/dist/bundle/{chunk-LKDK5YMI.js → chunk-NOU6MWEM.js} +2 -2
  39. package/dist/bundle/{chunk-LQ37ALDJ.js → chunk-NXJLC2WK.js} +8 -8
  40. package/dist/bundle/{chunk-ZAR67WKR.js → chunk-NZB4WGQS.js} +6 -6
  41. package/dist/bundle/{chunk-5RUTHKXZ.js → chunk-O555ZEQR.js} +4 -4
  42. package/dist/bundle/{chunk-MGBGE2Y4.js → chunk-O7VK7CJX.js} +2 -2
  43. package/dist/bundle/{chunk-WFBTPZK3.js → chunk-OHV5RDFE.js} +4 -4
  44. package/dist/bundle/{chunk-HJEMHZRU.js → chunk-P5B7IFOG.js} +2 -2
  45. package/dist/bundle/{chunk-VWHRIGYJ.js → chunk-PBYDT3CG.js} +13 -3
  46. package/dist/bundle/{chunk-7IYDIU4P.js → chunk-PHPC72DP.js} +7 -7
  47. package/dist/bundle/{chunk-ID24SLH3.js → chunk-PKU6V4EQ.js} +17 -17
  48. package/dist/bundle/{chunk-P7P5MNAU.js → chunk-QZBT6BOU.js} +1 -1
  49. package/dist/bundle/{chunk-NL5LNYGX.js → chunk-RAZOSYEO.js} +23 -23
  50. package/dist/bundle/{chunk-CCNHVZ3G.js → chunk-RDSAI6DC.js} +398 -293
  51. package/dist/bundle/{chunk-CSI73XJ5.js → chunk-SAZJDKEI.js} +8 -8
  52. package/dist/bundle/{chunk-QX7RCLRS.js → chunk-SQLCCKEL.js} +1 -1
  53. package/dist/bundle/{chunk-ORYYYM5Y.js → chunk-TKJDGAHT.js} +23 -23
  54. package/dist/bundle/{chunk-RLSGMMGC.js → chunk-TPNC5VCJ.js} +4 -4
  55. package/dist/bundle/{chunk-IIO6NXCA.js → chunk-UAXBLHZK.js} +2 -2
  56. package/dist/bundle/{chunk-2NZGUKYK.js → chunk-VEAP5RVI.js} +10 -8
  57. package/dist/bundle/{chunk-6BNMEOVS.js → chunk-VF24ZAPX.js} +4 -4
  58. package/dist/bundle/{chunk-FFKNUVVD.js → chunk-WCL3WBH5.js} +3 -3
  59. package/dist/bundle/{chunk-M4NTQ247.js → chunk-WGK4AIRL.js} +12 -12
  60. package/dist/bundle/{chunk-OM4ZBLT7.js → chunk-XERTHQ6D.js} +88 -34
  61. package/dist/bundle/{chunk-6BR6JMCR.js → chunk-XZGLY2LU.js} +14 -14
  62. package/dist/bundle/{chunk-2LP46EUH.js → chunk-Y7JKWQC2.js} +96 -94
  63. package/dist/bundle/{chunk-F7KAJNNK.js → chunk-YBJMBPL7.js} +6 -6
  64. package/dist/bundle/{chunk-YYTWV5GU.js → chunk-ZMMIIBTM.js} +73 -57
  65. package/dist/bundle/{chunk-EOEYP7CJ.js → chunk-ZPGLWMNH.js} +3 -3
  66. package/dist/bundle/{chunk-UJYCKCFR.js → chunk-ZRYFEEXZ.js} +3 -3
  67. package/dist/bundle/command-contract-NZF4B5OR.js +34 -0
  68. package/dist/bundle/{decode-ON4KBMEX.js → decode-HVXDCQ63.js} +5 -5
  69. package/dist/bundle/{dispatch-EUKKT3PD.js → dispatch-GDAH4JHS.js} +8 -8
  70. package/dist/bundle/dist-43DZXMBL.js +134 -0
  71. package/dist/bundle/{echarts-XPA226QR.js → echarts-LZ74IXHG.js} +2 -2
  72. package/dist/bundle/{embed-QERDAB73.js → embed-OQF5U2C6.js} +6 -6
  73. package/dist/bundle/{embedder-I76YT3E5.js → embedder-OCWQAWKO.js} +9 -9
  74. package/dist/bundle/{failure-OAIC5VAP.js → failure-6COJAO7T.js} +2 -2
  75. package/dist/bundle/{first-run-KZJFR55N.js → first-run-MTZPUPGA.js} +11 -11
  76. package/dist/bundle/first-screen-4PBS6QK5.js +32 -0
  77. package/dist/bundle/{instructions-NN3BCFIM.js → instructions-M6F4FP7U.js} +1 -1
  78. package/dist/bundle/mail.js +12 -11
  79. package/dist/bundle/{mcp-L7SRVDRN.js → mcp-GAPDLFWA.js} +2 -2
  80. package/dist/bundle/{node-2S75QJ6B.js → node-NYBBFHGN.js} +2 -2
  81. package/dist/bundle/{node-sqlite-RC7WM3EG.js → node-sqlite-CWCNWO75.js} +5 -5
  82. package/dist/bundle/{oauth-FUHLZCKV.js → oauth-DVX45EME.js} +7 -7
  83. package/dist/bundle/{open-JOKT7LKY.js → open-M7EQWWHL.js} +4 -4
  84. package/dist/bundle/{openai-U3IMQ6UI.js → openai-63KRU5H2.js} +14 -14
  85. package/dist/bundle/{process-LKODK722.js → process-DV5GQIGM.js} +1 -1
  86. package/dist/bundle/{program-RMLIQXCA.js → program-EPR3QCMX.js} +20570 -7622
  87. package/dist/bundle/{prompt-23VYMNNB.js → prompt-EPWPWTB3.js} +5 -5
  88. package/dist/bundle/{recognize-TXO3462R.js → recognize-R46KDXK4.js} +4 -4
  89. package/dist/bundle/{remote-5F4ZOASM.js → remote-RENCYB5X.js} +7 -7
  90. package/dist/bundle/{rerank-TXSDPEFE.js → rerank-VHPC5O73.js} +7 -7
  91. package/dist/bundle/{serve-TWYECYWM.js → serve-KCH3ORYO.js} +9 -9
  92. package/dist/bundle/server-FMCPE2ZK.js +63 -0
  93. package/dist/bundle/{server-3S3BKE6D.js → server-HZVXSK7B.js} +38 -38
  94. package/dist/bundle/{sqlite-runtime-BEOBGC6K.js → sqlite-runtime-XP7ZJCKJ.js} +5 -5
  95. package/dist/bundle/{state-ERWIUTQQ.js → state-GQ4MEQJ5.js} +6 -6
  96. package/dist/bundle/{store-2JO4JGQL.js → store-CQNLNINW.js} +13 -13
  97. package/dist/bundle/{store-4RY5UMOP.js → store-WT7YTR3Y.js} +15 -15
  98. package/dist/bundle/store-maintenance-command-YYR42IT4.js +52 -0
  99. package/dist/commands/attachments.d.ts +3 -0
  100. package/dist/commands/attachments.d.ts.map +1 -0
  101. package/dist/commands/attachments.js +97 -0
  102. package/dist/commands/attachments.js.map +1 -0
  103. package/dist/commands/context.d.ts.map +1 -1
  104. package/dist/commands/context.js +11 -1
  105. package/dist/commands/context.js.map +1 -1
  106. package/dist/commands/drafts-send.d.ts +7 -0
  107. package/dist/commands/drafts-send.d.ts.map +1 -0
  108. package/dist/commands/drafts-send.js +58 -0
  109. package/dist/commands/drafts-send.js.map +1 -0
  110. package/dist/commands/drafts.d.ts +3 -0
  111. package/dist/commands/drafts.d.ts.map +1 -0
  112. package/dist/commands/drafts.js +239 -0
  113. package/dist/commands/drafts.js.map +1 -0
  114. package/dist/commands/export.d.ts +3 -0
  115. package/dist/commands/export.d.ts.map +1 -0
  116. package/dist/commands/export.js +275 -0
  117. package/dist/commands/export.js.map +1 -0
  118. package/dist/commands/folders.d.ts.map +1 -1
  119. package/dist/commands/folders.js +120 -2
  120. package/dist/commands/folders.js.map +1 -1
  121. package/dist/commands/messages.d.ts +25 -0
  122. package/dist/commands/messages.d.ts.map +1 -0
  123. package/dist/commands/messages.js +502 -0
  124. package/dist/commands/messages.js.map +1 -0
  125. package/dist/commands/read.d.ts +4 -1
  126. package/dist/commands/read.d.ts.map +1 -1
  127. package/dist/commands/read.js +12 -2
  128. package/dist/commands/read.js.map +1 -1
  129. package/dist/commands/rules.d.ts +3 -0
  130. package/dist/commands/rules.d.ts.map +1 -0
  131. package/dist/commands/rules.js +292 -0
  132. package/dist/commands/rules.js.map +1 -0
  133. package/dist/commands/send.d.ts +39 -0
  134. package/dist/commands/send.d.ts.map +1 -0
  135. package/dist/commands/send.js +309 -0
  136. package/dist/commands/send.js.map +1 -0
  137. package/dist/commands/server-search.d.ts +8 -0
  138. package/dist/commands/server-search.d.ts.map +1 -0
  139. package/dist/commands/server-search.js +38 -0
  140. package/dist/commands/server-search.js.map +1 -0
  141. package/dist/commands/stats.d.ts +3 -0
  142. package/dist/commands/stats.d.ts.map +1 -0
  143. package/dist/commands/stats.js +90 -0
  144. package/dist/commands/stats.js.map +1 -0
  145. package/dist/commands/sync.d.ts +7 -0
  146. package/dist/commands/sync.d.ts.map +1 -1
  147. package/dist/commands/sync.js +22 -7
  148. package/dist/commands/sync.js.map +1 -1
  149. package/dist/commands/tags.d.ts +3 -0
  150. package/dist/commands/tags.d.ts.map +1 -0
  151. package/dist/commands/tags.js +144 -0
  152. package/dist/commands/tags.js.map +1 -0
  153. package/dist/config.d.ts +13 -0
  154. package/dist/config.d.ts.map +1 -1
  155. package/dist/config.js +47 -1
  156. package/dist/config.js.map +1 -1
  157. package/dist/export/format.d.ts +19 -0
  158. package/dist/export/format.d.ts.map +1 -0
  159. package/dist/export/format.js +40 -0
  160. package/dist/export/format.js.map +1 -0
  161. package/dist/export/journal.d.ts +32 -0
  162. package/dist/export/journal.d.ts.map +1 -0
  163. package/dist/export/journal.js +84 -0
  164. package/dist/export/journal.js.map +1 -0
  165. package/dist/export/write.d.ts +14 -0
  166. package/dist/export/write.d.ts.map +1 -0
  167. package/dist/export/write.js +42 -0
  168. package/dist/export/write.js.map +1 -0
  169. package/dist/identity.d.ts.map +1 -1
  170. package/dist/identity.js +3 -0
  171. package/dist/identity.js.map +1 -1
  172. package/dist/mail/backend.d.ts +81 -1
  173. package/dist/mail/backend.d.ts.map +1 -1
  174. package/dist/mail/changes.d.ts +91 -0
  175. package/dist/mail/changes.d.ts.map +1 -0
  176. package/dist/mail/changes.js +198 -0
  177. package/dist/mail/changes.js.map +1 -0
  178. package/dist/mail/cleanup.d.ts +41 -0
  179. package/dist/mail/cleanup.d.ts.map +1 -0
  180. package/dist/mail/cleanup.js +119 -0
  181. package/dist/mail/cleanup.js.map +1 -0
  182. package/dist/mail/compose.d.ts +73 -0
  183. package/dist/mail/compose.d.ts.map +1 -0
  184. package/dist/mail/compose.js +122 -0
  185. package/dist/mail/compose.js.map +1 -0
  186. package/dist/mail/doctor.d.ts +25 -0
  187. package/dist/mail/doctor.d.ts.map +1 -0
  188. package/dist/mail/doctor.js +39 -0
  189. package/dist/mail/doctor.js.map +1 -0
  190. package/dist/mail/drafts.d.ts +54 -0
  191. package/dist/mail/drafts.d.ts.map +1 -0
  192. package/dist/mail/drafts.js +104 -0
  193. package/dist/mail/drafts.js.map +1 -0
  194. package/dist/mail/imap/connection.d.ts +7 -0
  195. package/dist/mail/imap/connection.d.ts.map +1 -1
  196. package/dist/mail/imap/connection.js +24 -2
  197. package/dist/mail/imap/connection.js.map +1 -1
  198. package/dist/mail/imap/index.d.ts +1 -1
  199. package/dist/mail/imap/index.d.ts.map +1 -1
  200. package/dist/mail/imap/index.js +12 -2
  201. package/dist/mail/imap/index.js.map +1 -1
  202. package/dist/mail/imap/messages.d.ts +5 -6
  203. package/dist/mail/imap/messages.d.ts.map +1 -1
  204. package/dist/mail/imap/messages.js +14 -28
  205. package/dist/mail/imap/messages.js.map +1 -1
  206. package/dist/mail/imap/read.d.ts.map +1 -1
  207. package/dist/mail/imap/read.js +27 -13
  208. package/dist/mail/imap/read.js.map +1 -1
  209. package/dist/mail/imap/search.d.ts +14 -0
  210. package/dist/mail/imap/search.d.ts.map +1 -0
  211. package/dist/mail/imap/search.js +49 -0
  212. package/dist/mail/imap/search.js.map +1 -0
  213. package/dist/mail/imap/write.d.ts +5 -0
  214. package/dist/mail/imap/write.d.ts.map +1 -0
  215. package/dist/mail/imap/write.js +93 -0
  216. package/dist/mail/imap/write.js.map +1 -0
  217. package/dist/mail/organise.d.ts +116 -0
  218. package/dist/mail/organise.d.ts.map +1 -0
  219. package/dist/mail/organise.js +531 -0
  220. package/dist/mail/organise.js.map +1 -0
  221. package/dist/mail/rethread.d.ts +1 -2
  222. package/dist/mail/rethread.d.ts.map +1 -1
  223. package/dist/mail/rethread.js +8 -3
  224. package/dist/mail/rethread.js.map +1 -1
  225. package/dist/mail/rules/apply.d.ts +40 -0
  226. package/dist/mail/rules/apply.d.ts.map +1 -0
  227. package/dist/mail/rules/apply.js +114 -0
  228. package/dist/mail/rules/apply.js.map +1 -0
  229. package/dist/mail/rules/file.d.ts +9 -0
  230. package/dist/mail/rules/file.d.ts.map +1 -0
  231. package/dist/mail/rules/file.js +51 -0
  232. package/dist/mail/rules/file.js.map +1 -0
  233. package/dist/mail/rules/filters.d.ts +11 -0
  234. package/dist/mail/rules/filters.d.ts.map +1 -0
  235. package/dist/mail/rules/filters.js +150 -0
  236. package/dist/mail/rules/filters.js.map +1 -0
  237. package/dist/mail/rules/folders.d.ts +11 -0
  238. package/dist/mail/rules/folders.d.ts.map +1 -0
  239. package/dist/mail/rules/folders.js +17 -0
  240. package/dist/mail/rules/folders.js.map +1 -0
  241. package/dist/mail/rules/query.d.ts +15 -0
  242. package/dist/mail/rules/query.d.ts.map +1 -0
  243. package/dist/mail/rules/query.js +103 -0
  244. package/dist/mail/rules/query.js.map +1 -0
  245. package/dist/mail/rules/store.d.ts +9 -0
  246. package/dist/mail/rules/store.d.ts.map +1 -0
  247. package/dist/mail/rules/store.js +17 -0
  248. package/dist/mail/rules/store.js.map +1 -0
  249. package/dist/mail/save.d.ts +12 -0
  250. package/dist/mail/save.d.ts.map +1 -0
  251. package/dist/mail/save.js +71 -0
  252. package/dist/mail/save.js.map +1 -0
  253. package/dist/mail/send.d.ts +67 -0
  254. package/dist/mail/send.d.ts.map +1 -0
  255. package/dist/mail/send.js +172 -0
  256. package/dist/mail/send.js.map +1 -0
  257. package/dist/mail/smtp.d.ts +4 -0
  258. package/dist/mail/smtp.d.ts.map +1 -0
  259. package/dist/mail/smtp.js +97 -0
  260. package/dist/mail/smtp.js.map +1 -0
  261. package/dist/program.d.ts.map +1 -1
  262. package/dist/program.js +28 -6
  263. package/dist/program.js.map +1 -1
  264. package/dist/providers.d.ts +71 -6
  265. package/dist/providers.d.ts.map +1 -1
  266. package/dist/providers.js +38 -9
  267. package/dist/providers.js.map +1 -1
  268. package/dist/reasons.d.ts +9 -0
  269. package/dist/reasons.d.ts.map +1 -0
  270. package/dist/reasons.js +21 -0
  271. package/dist/reasons.js.map +1 -0
  272. package/dist/version.d.ts +1 -1
  273. package/dist/version.js +1 -1
  274. package/package.json +8 -5
  275. package/skills/mail-cli/SKILL.md +30 -3
  276. package/dist/bundle/chunk-XJ5TBPCK.js +0 -27
  277. package/dist/bundle/command-contract-L65UZ7AF.js +0 -34
  278. package/dist/bundle/first-screen-EORANEAK.js +0 -32
  279. package/dist/bundle/server-2GEAXKX2.js +0 -63
  280. package/dist/bundle/store-maintenance-command-T7D4OTN7.js +0 -52
  281. /package/dist/bundle/{chunk-NPGVOZVK.js → chunk-WJWLHLQ7.js} +0 -0
@@ -0,0 +1,40 @@
1
+ import type { MailSource } from "@wirecat/cli-core/mail";
2
+ import { type MailAccount, type MailRule, type TagOutcome } from "@wirecat/cli-core/mail";
3
+ import type { MessageStore } from "@wirecat/cli-core/store";
4
+ export interface RuleEffect {
5
+ rule: MailRule;
6
+ emails: number;
7
+ /** Text this rule's emails hold in the store: bodies and attachment text. */
8
+ bytes: number;
9
+ }
10
+ export interface ApplyResult {
11
+ account: string;
12
+ applied: boolean;
13
+ listed: number;
14
+ /** Stored in full, matched by an envelope rule: cut to envelopes, or would be. */
15
+ envelopes: number;
16
+ bytes: number;
17
+ /** Stored in full, matched only by a skip rule: left as stored, since removing them is another decision. */
18
+ skipMatched: number;
19
+ /** Stored in full, matched by a protected rule: never cut, whatever else matches. */
20
+ protectedKept: number;
21
+ /** Stored emails a rule's tag was put on, or would be. */
22
+ tagged: number;
23
+ rules: RuleEffect[];
24
+ tagsReused?: TagOutcome["reused"];
25
+ tagsSkipped?: TagOutcome["skipped"];
26
+ }
27
+ /**
28
+ * Cuts mail stored in full that an envelope rule now matches down to what an envelope sync stores. Matching
29
+ * reads the account's headers from the server, as sync does: List-Id is not stored with a full email.
30
+ */
31
+ export declare const applyRules: ({ store, source, account, folders, since, apply, now, }: {
32
+ store: MessageStore;
33
+ source: Pick<MailSource, "list">;
34
+ account: Pick<MailAccount, "address" | "rules">;
35
+ folders: readonly string[];
36
+ since: Date;
37
+ apply: boolean;
38
+ now?: () => number;
39
+ }) => Promise<ApplyResult>;
40
+ //# sourceMappingURL=apply.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../../src/mail/rules/apply.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAU,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAChE,OAAO,EAKL,KAAK,WAAW,EAChB,KAAK,QAAQ,EAKb,KAAK,UAAU,EAEhB,MAAM,wBAAwB,CAAA;AAC/B,OAAO,KAAK,EAAc,YAAY,EAAE,MAAM,yBAAyB,CAAA;AAEvE,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,QAAQ,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,6EAA6E;IAC7E,KAAK,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,OAAO,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,kFAAkF;IAClF,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,4GAA4G;IAC5G,WAAW,EAAE,MAAM,CAAA;IACnB,qFAAqF;IACrF,aAAa,EAAE,MAAM,CAAA;IACrB,0DAA0D;IAC1D,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,UAAU,EAAE,CAAA;IACnB,UAAU,CAAC,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAA;IACjC,WAAW,CAAC,EAAE,UAAU,CAAC,SAAS,CAAC,CAAA;CACpC;AAID;;;GAGG;AACH,eAAO,MAAM,UAAU,4DAQpB;IACD,KAAK,EAAE,YAAY,CAAA;IACnB,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,CAAA;IAChC,OAAO,EAAE,IAAI,CAAC,WAAW,EAAE,SAAS,GAAG,OAAO,CAAC,CAAA;IAC/C,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;IAC1B,KAAK,EAAE,IAAI,CAAA;IACX,KAAK,EAAE,OAAO,CAAA;IACd,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;CACnB,KAAG,OAAO,CAAC,WAAW,CAmGtB,CAAA"}
@@ -0,0 +1,114 @@
1
+ import { decide, ENVELOPE, envelopeBox, factsOf, ruleTagger, sameMatch, settleRuleTags, tagsOf, } from "@wirecat/cli-core/mail";
2
+ const textBytes = (text) => (text ? Buffer.byteLength(text) : 0);
3
+ /**
4
+ * Cuts mail stored in full that an envelope rule now matches down to what an envelope sync stores. Matching
5
+ * reads the account's headers from the server, as sync does: List-Id is not stored with a full email.
6
+ */
7
+ export const applyRules = async ({ store, source, account, folders, since, apply, now = Date.now, }) => {
8
+ const startedAt = now();
9
+ const key = { provider: "email", account: account.address.toLowerCase() };
10
+ const rules = account.rules ?? [];
11
+ const effects = rules
12
+ .filter(({ action, protected: kept }) => action === ENVELOPE && !kept)
13
+ .map((rule) => ({ rule, emails: 0, bytes: 0 }));
14
+ const result = {
15
+ account: key.account,
16
+ applied: apply,
17
+ listed: 0,
18
+ envelopes: 0,
19
+ bytes: 0,
20
+ skipMatched: 0,
21
+ protectedKept: 0,
22
+ tagged: 0,
23
+ rules: effects,
24
+ };
25
+ if (effects.length === 0 && !rules.some(({ tags, protected: kept }) => tags?.length || kept))
26
+ return result;
27
+ const stored = await store.accounts.storedAccount(key).catch(() => null);
28
+ if (stored === null)
29
+ return result;
30
+ const listed = new Map();
31
+ for (const folder of folders)
32
+ for (const item of await source.list(since, folder, { headers: true }))
33
+ listed.set(item.messageId, item);
34
+ result.listed = listed.size;
35
+ const full = new Set((await store.mail.emailRefs({ accountId: stored.id }))
36
+ .filter(({ deleted, mailboxes }) => !deleted && !mailboxes.some(({ kind }) => kind === ENVELOPE))
37
+ .map(({ externalId }) => externalId));
38
+ const effectOf = (match) => effects.find(({ rule }) => sameMatch(rule.match, match));
39
+ const all = new Set((await store.mail.emailRefs({ accountId: stored.id })).map(({ externalId }) => externalId));
40
+ const factsFor = factsOf([...listed.values()], rules);
41
+ const tagger = ruleTagger(store, key);
42
+ const chosen = [];
43
+ for (const item of listed.values()) {
44
+ const facts = factsFor(item);
45
+ const tags = all.has(item.messageId) ? tagsOf(rules, facts) : [];
46
+ if (tags.length) {
47
+ result.tagged++;
48
+ if (apply)
49
+ await tagger.tag({ type: "message", chatId: item.threadId, messageId: item.messageId }, tags);
50
+ }
51
+ if (!full.has(item.messageId))
52
+ continue;
53
+ const rule = decide(rules, facts);
54
+ if (rule?.protected)
55
+ result.protectedKept++;
56
+ if (rule?.action === "skip")
57
+ result.skipMatched++;
58
+ if (rule?.action === ENVELOPE)
59
+ chosen.push({ item, rule });
60
+ }
61
+ for (const { item, rule } of chosen) {
62
+ const email = await store.mail.email(stored.id, item.messageId);
63
+ if (email === null)
64
+ continue;
65
+ const bytes = textBytes(email.bodyText) +
66
+ textBytes(email.bodyHtml) +
67
+ email.attachments.reduce((sum, { text }) => sum + textBytes(text), 0);
68
+ const effect = effectOf(rule.match);
69
+ effect.emails++;
70
+ effect.bytes += bytes;
71
+ result.envelopes++;
72
+ result.bytes += bytes;
73
+ if (!apply)
74
+ continue;
75
+ const [placed] = await store.mail.inThreads(stored.id, [item.messageId]);
76
+ const subject = email.subject ?? item.headers?.subject;
77
+ const listId = item.headers?.listId;
78
+ await store.mail.saveThread({
79
+ accountId: stored.id,
80
+ externalId: placed?.threadExternalId ?? item.threadId,
81
+ now: startedAt,
82
+ emails: [
83
+ {
84
+ externalId: item.messageId,
85
+ subject: null,
86
+ from: email.fromAddress === null ? null : { address: email.fromAddress, name: email.fromName },
87
+ sentAt: email.sentAt,
88
+ bodyText: null,
89
+ bodyHtml: null,
90
+ snippet: null,
91
+ size: email.size ?? item.size ?? null,
92
+ mailboxes: [envelopeBox(rule.match)],
93
+ mailRuleId: rule.id ?? null,
94
+ attachments: [],
95
+ metadata: {
96
+ ...email.metadata,
97
+ rule: { action: rule.action, match: { ...rule.match } },
98
+ ...(subject ? { subject } : {}),
99
+ ...(listId ? { listId } : {}),
100
+ },
101
+ },
102
+ ],
103
+ });
104
+ }
105
+ const tagging = tagger.outcome();
106
+ if (apply)
107
+ await settleRuleTags(store, stored.id, rules, tagging);
108
+ if (tagging.reused.length)
109
+ result.tagsReused = tagging.reused;
110
+ if (tagging.skipped.length)
111
+ result.tagsSkipped = tagging.skipped;
112
+ return result;
113
+ };
114
+ //# sourceMappingURL=apply.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apply.js","sourceRoot":"","sources":["../../../src/mail/rules/apply.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import { type MailRule } from "@wirecat/cli-core/mail";
2
+ /** What `rules export` prints and `rules import` reads back; memo writes and reads the same file. */
3
+ export interface RulesFile {
4
+ version: 1;
5
+ account: string;
6
+ rules: Omit<MailRule, "id">[];
7
+ }
8
+ export declare const rulesFileOf: (text: string, path: string, exporter: string) => MailRule[];
9
+ //# sourceMappingURL=file.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file.d.ts","sourceRoot":"","sources":["../../../src/mail/rules/file.ts"],"names":[],"mappings":"AACA,OAAO,EAAkC,KAAK,QAAQ,EAAsB,MAAM,wBAAwB,CAAA;AAE1G,qGAAqG;AACrG,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,CAAC,CAAA;IACV,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,CAAA;CAC9B;AAqBD,eAAO,MAAM,WAAW,SAAU,MAAM,QAAQ,MAAM,YAAY,MAAM,KAAG,QAAQ,EA4BlF,CAAA"}
@@ -0,0 +1,51 @@
1
+ import { CliError } from "@wirecat/cli-base";
2
+ import { conditionKeys } from "@wirecat/cli-core/mail";
3
+ const ACTIONS = ["skip", "envelope", "keep"];
4
+ const CONDITIONS = [
5
+ "from",
6
+ "from_contains",
7
+ "domain",
8
+ "to",
9
+ "list_id",
10
+ "subject",
11
+ "older_than_days",
12
+ "larger_than_bytes",
13
+ "has_attachments",
14
+ "label",
15
+ "unread",
16
+ "bulk",
17
+ "score_at_least",
18
+ "preset",
19
+ ];
20
+ export const rulesFileOf = (text, path, exporter) => {
21
+ const bad = (why) => new CliError("validation_error", `${path}: ${why}`, { reason: "mail.rules-file-invalid" });
22
+ let parsed;
23
+ try {
24
+ parsed = JSON.parse(text);
25
+ }
26
+ catch {
27
+ throw bad("not JSON");
28
+ }
29
+ const rules = parsed?.rules;
30
+ if (!Array.isArray(rules))
31
+ throw bad(`no rules list; write it with ${exporter}`);
32
+ return rules.map((raw, index) => {
33
+ const rule = (raw ?? {});
34
+ if (!ACTIONS.includes(rule.action) || conditionKeys(rule.match ?? {}).length === 0)
35
+ throw bad(`rule ${index + 1} needs at least one match condition and an action`);
36
+ const match = rule.match;
37
+ const unknown = conditionKeys(match).filter((key) => !CONDITIONS.includes(key));
38
+ if (unknown.length)
39
+ throw bad(`rule ${index + 1} has conditions mail does not know: ${unknown.join(", ")}`);
40
+ return {
41
+ match,
42
+ action: rule.action,
43
+ ...(Array.isArray(rule.tags) ? { tags: rule.tags.filter((tag) => typeof tag === "string") } : {}),
44
+ ...(typeof rule.reason === "string" ? { reason: rule.reason } : {}),
45
+ ...(rule.protected === true ? { protected: true } : {}),
46
+ ...(typeof rule.source === "string" ? { source: rule.source } : {}),
47
+ decided_at: typeof rule.decided_at === "string" ? rule.decided_at : new Date().toISOString(),
48
+ };
49
+ });
50
+ };
51
+ //# sourceMappingURL=file.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file.js","sourceRoot":"","sources":["../../../src/mail/rules/file.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { MailRule } from "@wirecat/cli-core/mail";
2
+ export interface FiltersProposal {
3
+ rules: MailRule[];
4
+ skipped: {
5
+ filter: string;
6
+ why: string;
7
+ }[];
8
+ }
9
+ /** The rules a Takeout Filters.json suggests; nothing is saved here. */
10
+ export declare const importFilters: (json: string, path: string, now?: Date) => FiltersProposal;
11
+ //# sourceMappingURL=filters.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filters.d.ts","sourceRoot":"","sources":["../../../src/mail/rules/filters.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAiB,MAAM,wBAAwB,CAAA;AAGrE,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,QAAQ,EAAE,CAAA;IACjB,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAC3C;AA2ID,wEAAwE;AACxE,eAAO,MAAM,aAAa,SAAU,MAAM,QAAQ,MAAM,iBAAqB,eAkB5E,CAAA"}
@@ -0,0 +1,150 @@
1
+ import { CliError } from "@wirecat/cli-base";
2
+ import { isAddress, senderMatch } from "./query.js";
3
+ const text = (value) => typeof value === "string" && value.trim() !== "" ? value.trim() : undefined;
4
+ const list = (value) => Array.isArray(value) ? value.flatMap((item) => (typeof item === "string" ? [item] : [])) : [];
5
+ const yes = (value) => value === true || value === "true";
6
+ const SYSTEM = new Set(["INBOX", "UNREAD", "SPAM", "TRASH", "IMPORTANT", "STARRED", "CATEGORY_PROMOTIONS"]);
7
+ /** `a OR b`, `(a OR b)`, `{a b}`: Gmail's ways of writing either of several values. */
8
+ const alternatives = (value) => value
9
+ .replace(/^[({]|[)}]$/g, "")
10
+ .split(/\s+OR\s+|\s+|,/)
11
+ .map((part) => part.trim())
12
+ .filter((part) => part !== "" && part !== "OR");
13
+ /**
14
+ * A filter's search query, as the Takeout export writes it (`from:a from:b to:me@x.example word`). A sender cannot
15
+ * be two addresses at once, so repeated from: or to: terms are read as either one: one rule per term.
16
+ */
17
+ const queryOf = (query) => {
18
+ const parsed = { from: [], to: [], words: [], attachment: false, unknown: [] };
19
+ for (const [, field, grouped, quoted, plain, word] of query.matchAll(/(\w+):(?:([({][^)}]*[)}])|"([^"]*)"|(\S+))|(\S+)/g)) {
20
+ if (word !== undefined) {
21
+ if (word !== "OR")
22
+ parsed.words.push(word.replace(/^"|"$/g, ""));
23
+ continue;
24
+ }
25
+ const value = grouped ?? quoted ?? plain ?? "";
26
+ switch (field?.toLowerCase()) {
27
+ case "from":
28
+ for (const sender of alternatives(value))
29
+ parsed.from.push(sender);
30
+ break;
31
+ case "to":
32
+ case "cc":
33
+ for (const recipient of alternatives(value))
34
+ parsed.to.push(recipient);
35
+ break;
36
+ case "subject":
37
+ for (const part of value.replace(/^[({]|[)}]$/g, "").split(/\s+/))
38
+ if (part)
39
+ parsed.words.push(part);
40
+ break;
41
+ case "has":
42
+ if (/^attachments?$/i.test(value))
43
+ parsed.attachment = true;
44
+ else
45
+ parsed.unknown.push(`has:${value}`);
46
+ break;
47
+ default:
48
+ parsed.unknown.push(`${field}:`);
49
+ }
50
+ }
51
+ return parsed;
52
+ };
53
+ /** The matches one filter's conditions make: one per sender or recipient it names, each with the shared rest. */
54
+ const matchesOf = (criteria) => {
55
+ const query = queryOf([
56
+ text(criteria.query),
57
+ text(criteria.hasTheWord),
58
+ text(criteria.from) && `from:(${text(criteria.from)})`,
59
+ text(criteria.to) && `to:(${text(criteria.to)})`,
60
+ ]
61
+ .filter(Boolean)
62
+ .join(" "));
63
+ if (text(criteria.negatedQuery) ?? text(criteria.doesNotHaveTheWord))
64
+ return "it excludes words, which mail rules cannot do";
65
+ if (criteria.size !== undefined)
66
+ return "it matches size, which this import does not map";
67
+ if (query.unknown.length)
68
+ return `it uses ${query.unknown.join(", ")}, which this import does not map`;
69
+ const badTo = query.to.find((value) => !isAddress(value));
70
+ if (badTo !== undefined)
71
+ return "it names a recipient that is not one address";
72
+ const subject = [...query.words, ...(text(criteria.subject) ? [text(criteria.subject)] : [])].join(" ");
73
+ const shared = {
74
+ ...(subject === "" ? {} : { subject }),
75
+ ...(query.attachment || yes(criteria.hasAttachment) ? { has_attachments: true } : {}),
76
+ };
77
+ const senders = query.from.length ? query.from.map(senderMatch) : [{}];
78
+ const recipients = query.to.length ? query.to.map((to) => ({ to: to.toLowerCase() })) : [{}];
79
+ const matches = senders.flatMap((sender) => recipients.map((recipient) => ({ ...sender, ...recipient, ...shared })));
80
+ return Object.keys(matches[0] ?? {}).length === 0 ? "it has no condition a mail rule can match" : matches;
81
+ };
82
+ /**
83
+ * One filter, in any shape Google writes them: the Gmail API's `{criteria, action}` (developers.google.com,
84
+ * users.settings.filters), the settings export's flat properties (`from`, `hasTheWord`, `shouldArchive`, `label`),
85
+ * or Takeout's `{query, labelsToAdd, labelsToRemove}`. Words are matched in the subject only; Gmail searched the
86
+ * whole email, so such a rule says so in its reason.
87
+ */
88
+ const rulesOf = (raw, decidedAt) => {
89
+ const criteria = raw.criteria ?? raw;
90
+ const action = raw.action ?? raw;
91
+ const matches = matchesOf(criteria);
92
+ if (typeof matches === "string")
93
+ return matches;
94
+ // The API writes system labels as INBOX, Takeout as Inbox.
95
+ const removed = [...list(action.removeLabelIds), ...list(action.labelsToRemove)].map((id) => id.toUpperCase());
96
+ const addedAsWritten = [...list(action.addLabelIds), ...list(action.labelsToAdd)];
97
+ const added = addedAsWritten.map((id) => id.toUpperCase());
98
+ const hides = removed.includes("INBOX") ||
99
+ removed.includes("UNREAD") ||
100
+ added.includes("TRASH") ||
101
+ yes(action.shouldArchive) ||
102
+ yes(action.shouldMarkAsRead) ||
103
+ yes(action.shouldTrash);
104
+ const tags = [
105
+ ...addedAsWritten.filter((id) => !SYSTEM.has(id.toUpperCase())),
106
+ ...(text(action.label) === undefined ? [] : [text(action.label)]),
107
+ ];
108
+ if (!hides && tags.length === 0)
109
+ return "it does nothing a mail rule can mirror";
110
+ return matches.map((match) => ({
111
+ match,
112
+ action: hides ? "envelope" : "keep",
113
+ ...(tags.length ? { tags } : {}),
114
+ source: "gmail-filter",
115
+ reason: match.subject
116
+ ? "from a Gmail filter; Gmail searched these words anywhere, the rule matches the subject"
117
+ : "from a Gmail filter",
118
+ decided_at: decidedAt,
119
+ }));
120
+ };
121
+ const nameOf = (raw, index) => {
122
+ const criteria = raw.criteria ?? raw;
123
+ return text(criteria.query) ?? text(criteria.from) ?? text(criteria.subject) ?? text(raw.id) ?? `filter ${index + 1}`;
124
+ };
125
+ /** The rules a Takeout Filters.json suggests; nothing is saved here. */
126
+ export const importFilters = (json, path, now = new Date()) => {
127
+ let parsed;
128
+ try {
129
+ parsed = JSON.parse(json);
130
+ }
131
+ catch {
132
+ throw new CliError("validation_error", `${path}: not JSON`, { reason: "mail.filters-file-invalid" });
133
+ }
134
+ const filters = Array.isArray(parsed) ? parsed : (parsed?.filters ?? parsed?.filter);
135
+ if (!Array.isArray(filters))
136
+ throw new CliError("validation_error", `${path}: no list of filters`, { reason: "mail.filters-file-invalid" });
137
+ const proposal = { rules: [], skipped: [] };
138
+ for (const [index, raw] of filters.entries()) {
139
+ if (raw === null || typeof raw !== "object")
140
+ continue;
141
+ const outcome = rulesOf(raw, now.toISOString());
142
+ if (typeof outcome === "string")
143
+ proposal.skipped.push({ filter: nameOf(raw, index), why: outcome });
144
+ else
145
+ for (const rule of outcome)
146
+ proposal.rules.push(rule);
147
+ }
148
+ return proposal;
149
+ };
150
+ //# sourceMappingURL=filters.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filters.js","sourceRoot":"","sources":["../../../src/mail/rules/filters.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { MailBackend } from "../backend.js";
2
+ /**
3
+ * The folders `sync` reads: `--folder`, else the profile's, else the provider's by role (INBOX and Sent, All Mail on
4
+ * Gmail). `rules apply` lists the same ones, so a rule judges the mail sync stored from them.
5
+ */
6
+ export declare const syncFoldersOf: (mailbox: {
7
+ address?: string;
8
+ host?: string;
9
+ folders?: string[];
10
+ }, backend: Pick<MailBackend, "folderList">, explicit?: string[]) => Promise<string[]>;
11
+ //# sourceMappingURL=folders.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"folders.d.ts","sourceRoot":"","sources":["../../../src/mail/rules/folders.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAEhD;;;GAGG;AACH,eAAO,MAAM,aAAa,YACf;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,WACvD,IAAI,CAAC,WAAW,EAAE,YAAY,CAAC,aAC7B,MAAM,EAAE,KAClB,OAAO,CAAC,MAAM,EAAE,CAQlB,CAAA"}
@@ -0,0 +1,17 @@
1
+ import { DEFAULT_SYNC, providerFor } from "../../providers.js";
2
+ /**
3
+ * The folders `sync` reads: `--folder`, else the profile's, else the provider's by role (INBOX and Sent, All Mail on
4
+ * Gmail). `rules apply` lists the same ones, so a rule judges the mail sync stored from them.
5
+ */
6
+ export const syncFoldersOf = async (mailbox, backend, explicit) => {
7
+ if (explicit?.length)
8
+ return explicit;
9
+ if (mailbox.folders?.length)
10
+ return mailbox.folders;
11
+ const defaults = (mailbox.address ? providerFor(mailbox.address, mailbox.host)?.sync : undefined) ?? DEFAULT_SYNC;
12
+ const chosen = (await backend.folderList())
13
+ .filter((folder) => folder.role && defaults.roles.includes(folder.role))
14
+ .map(({ path }) => path);
15
+ return chosen.length ? chosen : [defaults.otherwise];
16
+ };
17
+ //# sourceMappingURL=folders.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"folders.js","sourceRoot":"","sources":["../../../src/mail/rules/folders.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAG9D;;;GAGG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,KAAK,EAChC,OAAgE,EAChE,OAAwC,EACxC,QAAmB,EACA,EAAE;IACrB,IAAI,QAAQ,EAAE,MAAM;QAAE,OAAO,QAAQ,CAAA;IACrC,IAAI,OAAO,CAAC,OAAO,EAAE,MAAM;QAAE,OAAO,OAAO,CAAC,OAAO,CAAA;IACnD,MAAM,QAAQ,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,YAAY,CAAA;IACjH,MAAM,MAAM,GAAG,CAAC,MAAM,OAAO,CAAC,UAAU,EAAE,CAAC;SACxC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,IAAI,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;SACvE,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,CAAA;IAC1B,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAA;AACtD,CAAC,CAAA"}
@@ -0,0 +1,15 @@
1
+ import type { MailAction, MailRuleMatch } from "@wirecat/cli-core/mail";
2
+ export declare const FILTER_HELP: string;
3
+ /** `from:` as Gmail reads it: one address, a whole domain (`shop.example`, `@shop.example`), or a word it contains. */
4
+ export declare const senderMatch: (value: string) => MailRuleMatch;
5
+ export declare const isAddress: (value: string) => boolean;
6
+ /** The conditions of a rule's --filter query. */
7
+ export declare const filterMatch: (query: string) => MailRuleMatch;
8
+ export declare const ACTION_HELP: string;
9
+ /** `envelope,tag:promo` → the store action, protection and tags. */
10
+ export declare const actionsOf: (value: string) => {
11
+ action: MailAction;
12
+ protect: boolean;
13
+ tags: string[];
14
+ };
15
+ //# sourceMappingURL=query.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../../src/mail/rules/query.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AAEvE,eAAO,MAAM,WAAW,QAEwD,CAAA;AAMhF,uHAAuH;AACvH,eAAO,MAAM,WAAW,UAAW,MAAM,KAAG,aAI3C,CAAA;AAED,eAAO,MAAM,SAAS,UAAW,MAAM,YAAwB,CAAA;AAS/D,iDAAiD;AACjD,eAAO,MAAM,WAAW,UAAW,MAAM,KAAG,aAmD3C,CAAA;AAED,eAAO,MAAM,WAAW,QAGoF,CAAA;AAI5G,oEAAoE;AACpE,eAAO,MAAM,SAAS,UAAW,MAAM,KAAG;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAY/F,CAAA"}
@@ -0,0 +1,103 @@
1
+ import { CliError } from "@wirecat/cli-base";
2
+ export const FILTER_HELP = "from:<address, domain or word>, to:<address>, subject:<word> (or a bare word), older:<n>d, larger:<size> (5MB, 300KB), has:attachment, label:<name> " +
3
+ '(label:"Two words"), is:unread, is:bulk, score:<n> (at least); all must hold';
4
+ const bad = (why) => new CliError("validation_error", `--filter: ${why}`);
5
+ const ADDRESS = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
6
+ /** `from:` as Gmail reads it: one address, a whole domain (`shop.example`, `@shop.example`), or a word it contains. */
7
+ export const senderMatch = (value) => {
8
+ if (ADDRESS.test(value))
9
+ return { from: value.toLowerCase() };
10
+ const domain = value.replace(/^@/, "");
11
+ return /^[a-z0-9-]+(\.[a-z0-9-]+)+$/i.test(domain) ? { domain: domain.toLowerCase() } : { from_contains: value };
12
+ };
13
+ export const isAddress = (value) => ADDRESS.test(value);
14
+ const bytesOf = (value) => {
15
+ const match = /^(\d+(?:\.\d+)?)(b|kb|mb|gb)?$/i.exec(value);
16
+ if (match === null)
17
+ throw bad(`larger:${value} is not a size like 5MB, 300KB or 2048`);
18
+ const unit = { b: 1, kb: 1024, mb: 1024 ** 2, gb: 1024 ** 3 }[(match[2] ?? "b").toLowerCase()];
19
+ return Math.round(Number(match[1]) * unit);
20
+ };
21
+ /** The conditions of a rule's --filter query. */
22
+ export const filterMatch = (query) => {
23
+ const words = [];
24
+ const match = {};
25
+ for (const [, field, quoted, plain, word] of query.matchAll(/(\w+):(?:"([^"]*)"|(\S+))|(\S+)/g)) {
26
+ const value = quoted ?? plain ?? "";
27
+ if (word !== undefined) {
28
+ words.push(word);
29
+ continue;
30
+ }
31
+ switch (field?.toLowerCase()) {
32
+ case "from":
33
+ Object.assign(match, senderMatch(value));
34
+ break;
35
+ case "to":
36
+ if (!ADDRESS.test(value))
37
+ throw bad(`to:${value} needs one address, like to:me@example.com`);
38
+ match.to = value.toLowerCase();
39
+ break;
40
+ case "subject":
41
+ for (const part of value.split(/\s+/))
42
+ if (part)
43
+ words.push(part);
44
+ break;
45
+ case "older": {
46
+ const days = /^(\d+)d$/i.exec(value)?.[1];
47
+ if (days === undefined)
48
+ throw bad(`older:${value} needs days, like older:365d`);
49
+ match.older_than_days = Number(days);
50
+ break;
51
+ }
52
+ case "larger":
53
+ match.larger_than_bytes = bytesOf(value);
54
+ break;
55
+ case "has":
56
+ if (!/^attachments?$/i.test(value))
57
+ throw bad(`has:${value}; only has:attachment is known`);
58
+ match.has_attachments = true;
59
+ break;
60
+ case "label":
61
+ match.label = value;
62
+ break;
63
+ case "is":
64
+ if (/^unread$/i.test(value))
65
+ match.unread = true;
66
+ else if (/^bulk$/i.test(value))
67
+ match.bulk = true;
68
+ else
69
+ throw bad(`is:${value}; is:unread and is:bulk are known`);
70
+ break;
71
+ case "score":
72
+ if (!/^-?\d+$/.test(value))
73
+ throw bad(`score:${value} needs a whole number`);
74
+ match.score_at_least = Number(value);
75
+ break;
76
+ default:
77
+ throw bad(`${field}: is not a field; use ${FILTER_HELP}`);
78
+ }
79
+ }
80
+ if (words.length)
81
+ match.subject = words.join(" ");
82
+ return match;
83
+ };
84
+ export const ACTION_HELP = "one of skip (never read or store), envelope (store only sender, date, size and labels: counted, out of search, " +
85
+ "cleanable later), keep (store in full even when a skip or envelope rule matches) or protect (keep, and no " +
86
+ "cleanup may ever cut, archive or trash it); add tag:<name> to also tag the mail, e.g. envelope,tag:promo";
87
+ const ACTIONS = ["skip", "envelope", "keep", "protect"];
88
+ /** `envelope,tag:promo` → the store action, protection and tags. */
89
+ export const actionsOf = (value) => {
90
+ const parts = value
91
+ .split(",")
92
+ .map((part) => part.trim())
93
+ .filter(Boolean);
94
+ const tags = parts.filter((part) => part.startsWith("tag:")).map((part) => part.slice(4).trim());
95
+ const actions = parts.filter((part) => !part.startsWith("tag:"));
96
+ if (tags.some((tag) => tag === ""))
97
+ throw new CliError("validation_error", "--do: tag: needs a name, e.g. tag:promo");
98
+ if (actions.length !== 1 || !ACTIONS.includes(actions[0]))
99
+ throw new CliError("validation_error", `--do: choose ${ACTIONS.join(", ")}, plus any tag:<name>`);
100
+ const action = actions[0];
101
+ return { action: action === "protect" ? "keep" : action, protect: action === "protect", tags };
102
+ };
103
+ //# sourceMappingURL=query.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query.js","sourceRoot":"","sources":["../../../src/mail/rules/query.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import { type MailRule, type MailRuleMatch } from "@wirecat/cli-core/mail";
2
+ import type { MessageStore } from "@wirecat/cli-core/store";
3
+ export declare const saveRule: (store: MessageStore, address: string, rule: MailRule) => Promise<MailRule>;
4
+ export declare const removeRule: (store: MessageStore, address: string, match: MailRuleMatch) => Promise<boolean>;
5
+ export declare const ruleCounts: (store: MessageStore, address: string) => Promise<Map<number, {
6
+ emails: number;
7
+ bytes: number;
8
+ }>>;
9
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../../src/mail/rules/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAE,KAAK,aAAa,EAA6B,MAAM,wBAAwB,CAAA;AACrG,OAAO,KAAK,EAAc,YAAY,EAAE,MAAM,yBAAyB,CAAA;AAQvE,eAAO,MAAM,QAAQ,UAAiB,YAAY,WAAW,MAAM,QAAQ,QAAQ,KAAG,OAAO,CAAC,QAAQ,CAGrG,CAAA;AAED,eAAO,MAAM,UAAU,UAAiB,YAAY,WAAW,MAAM,SAAS,aAAa,KAAG,OAAO,CAAC,OAAO,CAG5G,CAAA;AAED,eAAO,MAAM,UAAU,UAAiB,YAAY,WAAW,MAAM;;;GAMlE,CAAA"}
@@ -0,0 +1,17 @@
1
+ import { ruleInput, storedMailRule } from "@wirecat/cli-core/mail";
2
+ const accountKey = (address) => ({ provider: "email", account: address.toLowerCase() });
3
+ // Named by its address, as memo names it, so both tools keep one row for the mailbox.
4
+ const accountIdOf = (store, address) => store.accounts.saveAccount(accountKey(address), { name: address });
5
+ export const saveRule = async (store, address, rule) => {
6
+ const stored = await store.mail.rules.upsert(await accountIdOf(store, address), ruleInput(rule), Date.now());
7
+ return storedMailRule(stored) ?? rule;
8
+ };
9
+ export const removeRule = async (store, address, match) => {
10
+ const { conditions } = ruleInput({ match, action: "skip", decided_at: new Date().toISOString() });
11
+ return store.mail.rules.remove(await accountIdOf(store, address), conditions);
12
+ };
13
+ export const ruleCounts = async (store, address) => new Map((await store.mail.rules.counts(await accountIdOf(store, address))).map(({ ruleId, emails, bytes }) => [
14
+ ruleId,
15
+ { emails, bytes },
16
+ ]));
17
+ //# sourceMappingURL=store.js.map