@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.
- package/CHANGELOG.md +115 -0
- package/README.md +41 -10
- package/dist/bin/mail.js +2 -2
- package/dist/bundle/{all-profiles-55XPXQHY.js → all-profiles-GBFTKUHA.js} +9 -9
- package/dist/bundle/{anthropic-K5B6I4LB.js → anthropic-PTSCWUG6.js} +6 -6
- package/dist/bundle/{app-server-VWWLQLTZ.js → app-server-5VJ2WCKJ.js} +46 -46
- package/dist/bundle/{bun-EO7AI6YP.js → bun-2KRUBPIN.js} +2 -2
- package/dist/bundle/{bun-sqlite-F24A4IOP.js → bun-sqlite-ELSRSJBM.js} +5 -5
- package/dist/bundle/{chunk-X7AXH2IC.js → chunk-3KY7DA5A.js} +428 -434
- package/dist/bundle/{chunk-ANRI6EZY.js → chunk-4PKHZQIM.js} +8 -8
- package/dist/bundle/{chunk-CADRRSQK.js → chunk-56PI2BRH.js} +1 -1
- package/dist/bundle/{chunk-2ADB5DSG.js → chunk-5AQKM47C.js} +3 -3
- package/dist/bundle/{chunk-VP5GCMHM.js → chunk-5KHJUYHQ.js} +8 -8
- package/dist/bundle/{chunk-HUB42T2Z.js → chunk-6MV2TBDB.js} +57 -54
- package/dist/bundle/{chunk-4KLJN3LK.js → chunk-AGX7NR3S.js} +26 -13
- package/dist/bundle/{chunk-ZD3WUGR2.js → chunk-B337KHJ5.js} +4 -4
- package/dist/bundle/{chunk-5BVIWP3S.js → chunk-BM445GYF.js} +2 -2
- package/dist/bundle/{chunk-H7K2DN3R.js → chunk-BVIHT7KR.js} +9 -9
- package/dist/bundle/{chunk-EDKV6D6T.js → chunk-DA46WQEA.js} +1 -1
- package/dist/bundle/{chunk-UO7X2VW4.js → chunk-DV4RSEAH.js} +6 -6
- package/dist/bundle/{chunk-JZFIHVRB.js → chunk-ES4PWHBJ.js} +28 -28
- package/dist/bundle/{chunk-7X64JS6S.js → chunk-FIQOBLHS.js} +1 -1
- package/dist/bundle/{chunk-TI6VBZKJ.js → chunk-FUB3X25H.js} +4 -4
- package/dist/bundle/{chunk-VWXCEEUH.js → chunk-H4VFIH5W.js} +3 -3
- package/dist/bundle/{chunk-JKHI3PH7.js → chunk-J4C32YKH.js} +1 -1
- package/dist/bundle/{chunk-F6JTOQIK.js → chunk-J5MYH4L5.js} +12 -6
- package/dist/bundle/{chunk-QYWDC7NP.js → chunk-JFJTDL22.js} +47 -46
- package/dist/bundle/{chunk-UZDHK26H.js → chunk-JIQAFFPV.js} +2 -2
- package/dist/bundle/{chunk-BHKI5OCD.js → chunk-JKA2AICL.js} +2 -2
- package/dist/bundle/{dist-FMN7UZ7R.js → chunk-JKLQHPED.js} +16 -116
- package/dist/bundle/{chunk-J3QXTBD2.js → chunk-JLRMSNPX.js} +18 -18
- package/dist/bundle/{chunk-HORM6VRV.js → chunk-K5JUROGN.js} +1 -1
- package/dist/bundle/{chunk-SY3SP7EI.js → chunk-KUQYWIVR.js} +6 -6
- package/dist/bundle/{chunk-7QQ4EMYF.js → chunk-LWTG5UOF.js} +2 -2
- package/dist/bundle/{chunk-YSSMDVT3.js → chunk-M7V3GSJQ.js} +1 -1
- package/dist/bundle/chunk-MD2J3POF.js +52 -0
- package/dist/bundle/{chunk-SWRNMYDL.js → chunk-NCWO2FNC.js} +2 -2
- package/dist/bundle/{chunk-LKDK5YMI.js → chunk-NOU6MWEM.js} +2 -2
- package/dist/bundle/{chunk-LQ37ALDJ.js → chunk-NXJLC2WK.js} +8 -8
- package/dist/bundle/{chunk-ZAR67WKR.js → chunk-NZB4WGQS.js} +6 -6
- package/dist/bundle/{chunk-5RUTHKXZ.js → chunk-O555ZEQR.js} +4 -4
- package/dist/bundle/{chunk-MGBGE2Y4.js → chunk-O7VK7CJX.js} +2 -2
- package/dist/bundle/{chunk-WFBTPZK3.js → chunk-OHV5RDFE.js} +4 -4
- package/dist/bundle/{chunk-HJEMHZRU.js → chunk-P5B7IFOG.js} +2 -2
- package/dist/bundle/{chunk-VWHRIGYJ.js → chunk-PBYDT3CG.js} +13 -3
- package/dist/bundle/{chunk-7IYDIU4P.js → chunk-PHPC72DP.js} +7 -7
- package/dist/bundle/{chunk-ID24SLH3.js → chunk-PKU6V4EQ.js} +17 -17
- package/dist/bundle/{chunk-P7P5MNAU.js → chunk-QZBT6BOU.js} +1 -1
- package/dist/bundle/{chunk-NL5LNYGX.js → chunk-RAZOSYEO.js} +23 -23
- package/dist/bundle/{chunk-CCNHVZ3G.js → chunk-RDSAI6DC.js} +398 -293
- package/dist/bundle/{chunk-CSI73XJ5.js → chunk-SAZJDKEI.js} +8 -8
- package/dist/bundle/{chunk-QX7RCLRS.js → chunk-SQLCCKEL.js} +1 -1
- package/dist/bundle/{chunk-ORYYYM5Y.js → chunk-TKJDGAHT.js} +23 -23
- package/dist/bundle/{chunk-RLSGMMGC.js → chunk-TPNC5VCJ.js} +4 -4
- package/dist/bundle/{chunk-IIO6NXCA.js → chunk-UAXBLHZK.js} +2 -2
- package/dist/bundle/{chunk-2NZGUKYK.js → chunk-VEAP5RVI.js} +10 -8
- package/dist/bundle/{chunk-6BNMEOVS.js → chunk-VF24ZAPX.js} +4 -4
- package/dist/bundle/{chunk-FFKNUVVD.js → chunk-WCL3WBH5.js} +3 -3
- package/dist/bundle/{chunk-M4NTQ247.js → chunk-WGK4AIRL.js} +12 -12
- package/dist/bundle/{chunk-OM4ZBLT7.js → chunk-XERTHQ6D.js} +88 -34
- package/dist/bundle/{chunk-6BR6JMCR.js → chunk-XZGLY2LU.js} +14 -14
- package/dist/bundle/{chunk-2LP46EUH.js → chunk-Y7JKWQC2.js} +96 -94
- package/dist/bundle/{chunk-F7KAJNNK.js → chunk-YBJMBPL7.js} +6 -6
- package/dist/bundle/{chunk-YYTWV5GU.js → chunk-ZMMIIBTM.js} +73 -57
- package/dist/bundle/{chunk-EOEYP7CJ.js → chunk-ZPGLWMNH.js} +3 -3
- package/dist/bundle/{chunk-UJYCKCFR.js → chunk-ZRYFEEXZ.js} +3 -3
- package/dist/bundle/command-contract-NZF4B5OR.js +34 -0
- package/dist/bundle/{decode-ON4KBMEX.js → decode-HVXDCQ63.js} +5 -5
- package/dist/bundle/{dispatch-EUKKT3PD.js → dispatch-GDAH4JHS.js} +8 -8
- package/dist/bundle/dist-43DZXMBL.js +134 -0
- package/dist/bundle/{echarts-XPA226QR.js → echarts-LZ74IXHG.js} +2 -2
- package/dist/bundle/{embed-QERDAB73.js → embed-OQF5U2C6.js} +6 -6
- package/dist/bundle/{embedder-I76YT3E5.js → embedder-OCWQAWKO.js} +9 -9
- package/dist/bundle/{failure-OAIC5VAP.js → failure-6COJAO7T.js} +2 -2
- package/dist/bundle/{first-run-KZJFR55N.js → first-run-MTZPUPGA.js} +11 -11
- package/dist/bundle/first-screen-4PBS6QK5.js +32 -0
- package/dist/bundle/{instructions-NN3BCFIM.js → instructions-M6F4FP7U.js} +1 -1
- package/dist/bundle/mail.js +12 -11
- package/dist/bundle/{mcp-L7SRVDRN.js → mcp-GAPDLFWA.js} +2 -2
- package/dist/bundle/{node-2S75QJ6B.js → node-NYBBFHGN.js} +2 -2
- package/dist/bundle/{node-sqlite-RC7WM3EG.js → node-sqlite-CWCNWO75.js} +5 -5
- package/dist/bundle/{oauth-FUHLZCKV.js → oauth-DVX45EME.js} +7 -7
- package/dist/bundle/{open-JOKT7LKY.js → open-M7EQWWHL.js} +4 -4
- package/dist/bundle/{openai-U3IMQ6UI.js → openai-63KRU5H2.js} +14 -14
- package/dist/bundle/{process-LKODK722.js → process-DV5GQIGM.js} +1 -1
- package/dist/bundle/{program-RMLIQXCA.js → program-EPR3QCMX.js} +20570 -7622
- package/dist/bundle/{prompt-23VYMNNB.js → prompt-EPWPWTB3.js} +5 -5
- package/dist/bundle/{recognize-TXO3462R.js → recognize-R46KDXK4.js} +4 -4
- package/dist/bundle/{remote-5F4ZOASM.js → remote-RENCYB5X.js} +7 -7
- package/dist/bundle/{rerank-TXSDPEFE.js → rerank-VHPC5O73.js} +7 -7
- package/dist/bundle/{serve-TWYECYWM.js → serve-KCH3ORYO.js} +9 -9
- package/dist/bundle/server-FMCPE2ZK.js +63 -0
- package/dist/bundle/{server-3S3BKE6D.js → server-HZVXSK7B.js} +38 -38
- package/dist/bundle/{sqlite-runtime-BEOBGC6K.js → sqlite-runtime-XP7ZJCKJ.js} +5 -5
- package/dist/bundle/{state-ERWIUTQQ.js → state-GQ4MEQJ5.js} +6 -6
- package/dist/bundle/{store-2JO4JGQL.js → store-CQNLNINW.js} +13 -13
- package/dist/bundle/{store-4RY5UMOP.js → store-WT7YTR3Y.js} +15 -15
- package/dist/bundle/store-maintenance-command-YYR42IT4.js +52 -0
- package/dist/commands/attachments.d.ts +3 -0
- package/dist/commands/attachments.d.ts.map +1 -0
- package/dist/commands/attachments.js +97 -0
- package/dist/commands/attachments.js.map +1 -0
- package/dist/commands/context.d.ts.map +1 -1
- package/dist/commands/context.js +11 -1
- package/dist/commands/context.js.map +1 -1
- package/dist/commands/drafts-send.d.ts +7 -0
- package/dist/commands/drafts-send.d.ts.map +1 -0
- package/dist/commands/drafts-send.js +58 -0
- package/dist/commands/drafts-send.js.map +1 -0
- package/dist/commands/drafts.d.ts +3 -0
- package/dist/commands/drafts.d.ts.map +1 -0
- package/dist/commands/drafts.js +239 -0
- package/dist/commands/drafts.js.map +1 -0
- package/dist/commands/export.d.ts +3 -0
- package/dist/commands/export.d.ts.map +1 -0
- package/dist/commands/export.js +275 -0
- package/dist/commands/export.js.map +1 -0
- package/dist/commands/folders.d.ts.map +1 -1
- package/dist/commands/folders.js +120 -2
- package/dist/commands/folders.js.map +1 -1
- package/dist/commands/messages.d.ts +25 -0
- package/dist/commands/messages.d.ts.map +1 -0
- package/dist/commands/messages.js +502 -0
- package/dist/commands/messages.js.map +1 -0
- package/dist/commands/read.d.ts +4 -1
- package/dist/commands/read.d.ts.map +1 -1
- package/dist/commands/read.js +12 -2
- package/dist/commands/read.js.map +1 -1
- package/dist/commands/rules.d.ts +3 -0
- package/dist/commands/rules.d.ts.map +1 -0
- package/dist/commands/rules.js +292 -0
- package/dist/commands/rules.js.map +1 -0
- package/dist/commands/send.d.ts +39 -0
- package/dist/commands/send.d.ts.map +1 -0
- package/dist/commands/send.js +309 -0
- package/dist/commands/send.js.map +1 -0
- package/dist/commands/server-search.d.ts +8 -0
- package/dist/commands/server-search.d.ts.map +1 -0
- package/dist/commands/server-search.js +38 -0
- package/dist/commands/server-search.js.map +1 -0
- package/dist/commands/stats.d.ts +3 -0
- package/dist/commands/stats.d.ts.map +1 -0
- package/dist/commands/stats.js +90 -0
- package/dist/commands/stats.js.map +1 -0
- package/dist/commands/sync.d.ts +7 -0
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +22 -7
- package/dist/commands/sync.js.map +1 -1
- package/dist/commands/tags.d.ts +3 -0
- package/dist/commands/tags.d.ts.map +1 -0
- package/dist/commands/tags.js +144 -0
- package/dist/commands/tags.js.map +1 -0
- package/dist/config.d.ts +13 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +47 -1
- package/dist/config.js.map +1 -1
- package/dist/export/format.d.ts +19 -0
- package/dist/export/format.d.ts.map +1 -0
- package/dist/export/format.js +40 -0
- package/dist/export/format.js.map +1 -0
- package/dist/export/journal.d.ts +32 -0
- package/dist/export/journal.d.ts.map +1 -0
- package/dist/export/journal.js +84 -0
- package/dist/export/journal.js.map +1 -0
- package/dist/export/write.d.ts +14 -0
- package/dist/export/write.d.ts.map +1 -0
- package/dist/export/write.js +42 -0
- package/dist/export/write.js.map +1 -0
- package/dist/identity.d.ts.map +1 -1
- package/dist/identity.js +3 -0
- package/dist/identity.js.map +1 -1
- package/dist/mail/backend.d.ts +81 -1
- package/dist/mail/backend.d.ts.map +1 -1
- package/dist/mail/changes.d.ts +91 -0
- package/dist/mail/changes.d.ts.map +1 -0
- package/dist/mail/changes.js +198 -0
- package/dist/mail/changes.js.map +1 -0
- package/dist/mail/cleanup.d.ts +41 -0
- package/dist/mail/cleanup.d.ts.map +1 -0
- package/dist/mail/cleanup.js +119 -0
- package/dist/mail/cleanup.js.map +1 -0
- package/dist/mail/compose.d.ts +73 -0
- package/dist/mail/compose.d.ts.map +1 -0
- package/dist/mail/compose.js +122 -0
- package/dist/mail/compose.js.map +1 -0
- package/dist/mail/doctor.d.ts +25 -0
- package/dist/mail/doctor.d.ts.map +1 -0
- package/dist/mail/doctor.js +39 -0
- package/dist/mail/doctor.js.map +1 -0
- package/dist/mail/drafts.d.ts +54 -0
- package/dist/mail/drafts.d.ts.map +1 -0
- package/dist/mail/drafts.js +104 -0
- package/dist/mail/drafts.js.map +1 -0
- package/dist/mail/imap/connection.d.ts +7 -0
- package/dist/mail/imap/connection.d.ts.map +1 -1
- package/dist/mail/imap/connection.js +24 -2
- package/dist/mail/imap/connection.js.map +1 -1
- package/dist/mail/imap/index.d.ts +1 -1
- package/dist/mail/imap/index.d.ts.map +1 -1
- package/dist/mail/imap/index.js +12 -2
- package/dist/mail/imap/index.js.map +1 -1
- package/dist/mail/imap/messages.d.ts +5 -6
- package/dist/mail/imap/messages.d.ts.map +1 -1
- package/dist/mail/imap/messages.js +14 -28
- package/dist/mail/imap/messages.js.map +1 -1
- package/dist/mail/imap/read.d.ts.map +1 -1
- package/dist/mail/imap/read.js +27 -13
- package/dist/mail/imap/read.js.map +1 -1
- package/dist/mail/imap/search.d.ts +14 -0
- package/dist/mail/imap/search.d.ts.map +1 -0
- package/dist/mail/imap/search.js +49 -0
- package/dist/mail/imap/search.js.map +1 -0
- package/dist/mail/imap/write.d.ts +5 -0
- package/dist/mail/imap/write.d.ts.map +1 -0
- package/dist/mail/imap/write.js +93 -0
- package/dist/mail/imap/write.js.map +1 -0
- package/dist/mail/organise.d.ts +116 -0
- package/dist/mail/organise.d.ts.map +1 -0
- package/dist/mail/organise.js +531 -0
- package/dist/mail/organise.js.map +1 -0
- package/dist/mail/rethread.d.ts +1 -2
- package/dist/mail/rethread.d.ts.map +1 -1
- package/dist/mail/rethread.js +8 -3
- package/dist/mail/rethread.js.map +1 -1
- package/dist/mail/rules/apply.d.ts +40 -0
- package/dist/mail/rules/apply.d.ts.map +1 -0
- package/dist/mail/rules/apply.js +114 -0
- package/dist/mail/rules/apply.js.map +1 -0
- package/dist/mail/rules/file.d.ts +9 -0
- package/dist/mail/rules/file.d.ts.map +1 -0
- package/dist/mail/rules/file.js +51 -0
- package/dist/mail/rules/file.js.map +1 -0
- package/dist/mail/rules/filters.d.ts +11 -0
- package/dist/mail/rules/filters.d.ts.map +1 -0
- package/dist/mail/rules/filters.js +150 -0
- package/dist/mail/rules/filters.js.map +1 -0
- package/dist/mail/rules/folders.d.ts +11 -0
- package/dist/mail/rules/folders.d.ts.map +1 -0
- package/dist/mail/rules/folders.js +17 -0
- package/dist/mail/rules/folders.js.map +1 -0
- package/dist/mail/rules/query.d.ts +15 -0
- package/dist/mail/rules/query.d.ts.map +1 -0
- package/dist/mail/rules/query.js +103 -0
- package/dist/mail/rules/query.js.map +1 -0
- package/dist/mail/rules/store.d.ts +9 -0
- package/dist/mail/rules/store.d.ts.map +1 -0
- package/dist/mail/rules/store.js +17 -0
- package/dist/mail/rules/store.js.map +1 -0
- package/dist/mail/save.d.ts +12 -0
- package/dist/mail/save.d.ts.map +1 -0
- package/dist/mail/save.js +71 -0
- package/dist/mail/save.js.map +1 -0
- package/dist/mail/send.d.ts +67 -0
- package/dist/mail/send.d.ts.map +1 -0
- package/dist/mail/send.js +172 -0
- package/dist/mail/send.js.map +1 -0
- package/dist/mail/smtp.d.ts +4 -0
- package/dist/mail/smtp.d.ts.map +1 -0
- package/dist/mail/smtp.js +97 -0
- package/dist/mail/smtp.js.map +1 -0
- package/dist/program.d.ts.map +1 -1
- package/dist/program.js +28 -6
- package/dist/program.js.map +1 -1
- package/dist/providers.d.ts +71 -6
- package/dist/providers.d.ts.map +1 -1
- package/dist/providers.js +38 -9
- package/dist/providers.js.map +1 -1
- package/dist/reasons.d.ts +9 -0
- package/dist/reasons.d.ts.map +1 -0
- package/dist/reasons.js +21 -0
- package/dist/reasons.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +8 -5
- package/skills/mail-cli/SKILL.md +30 -3
- package/dist/bundle/chunk-XJ5TBPCK.js +0 -27
- package/dist/bundle/command-contract-L65UZ7AF.js +0 -34
- package/dist/bundle/first-screen-EORANEAK.js +0 -32
- package/dist/bundle/server-2GEAXKX2.js +0 -63
- package/dist/bundle/store-maintenance-command-T7D4OTN7.js +0 -52
- /package/dist/bundle/{chunk-NPGVOZVK.js → chunk-WJWLHLQ7.js} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write.js","sourceRoot":"","sources":["../../src/export/write.ts"],"names":[],"mappings":"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"}
|
package/dist/identity.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../src/identity.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;
|
|
1
|
+
{"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../src/identity.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAIxD,eAAO,MAAM,OAAO,sBAAsB,CAAA;AAE1C,eAAO,MAAM,QAAQ,EAAE,WAatB,CAAA;AAED,eAAO,MAAM,KAAK,mBAA0D,CAAA"}
|
package/dist/identity.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { REASONS } from "./reasons.js";
|
|
1
2
|
import { VERSION } from "./version.js";
|
|
2
3
|
export const PACKAGE = "@wirecat/mail-cli";
|
|
3
4
|
export const IDENTITY = {
|
|
@@ -8,9 +9,11 @@ export const IDENTITY = {
|
|
|
8
9
|
version: VERSION,
|
|
9
10
|
issues: "https://github.com/WireCatLabs/mail-cli/issues/new",
|
|
10
11
|
messenger: false,
|
|
12
|
+
sends: true,
|
|
11
13
|
// One call to the source reads 60 messages on 4 connections: 5 to 12 s on Yandex 360 (cli-testing, performance/mail).
|
|
12
14
|
requestMs: 9_000,
|
|
13
15
|
contentLanguages: ["ru", "en"],
|
|
16
|
+
errors: { reasons: REASONS },
|
|
14
17
|
};
|
|
15
18
|
export const SKILL = new URL("../skills/mail-cli/SKILL.md", import.meta.url);
|
|
16
19
|
//# sourceMappingURL=identity.js.map
|
package/dist/identity.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"identity.js","sourceRoot":"","sources":["../src/identity.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAEtC,MAAM,CAAC,MAAM,OAAO,GAAG,mBAAmB,CAAA;AAE1C,MAAM,CAAC,MAAM,QAAQ,GAAgB;IACnC,OAAO,EAAE,MAAM;IACf,OAAO,EAAE,UAAU;IACnB,SAAS,EAAE,MAAM;IACjB,WAAW,EAAE,oGAAoG;IACjH,OAAO,EAAE,OAAO;IAChB,MAAM,EAAE,oDAAoD;IAC5D,SAAS,EAAE,KAAK;IAChB,sHAAsH;IACtH,SAAS,EAAE,KAAK;IAChB,gBAAgB,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"identity.js","sourceRoot":"","sources":["../src/identity.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAEtC,MAAM,CAAC,MAAM,OAAO,GAAG,mBAAmB,CAAA;AAE1C,MAAM,CAAC,MAAM,QAAQ,GAAgB;IACnC,OAAO,EAAE,MAAM;IACf,OAAO,EAAE,UAAU;IACnB,SAAS,EAAE,MAAM;IACjB,WAAW,EAAE,oGAAoG;IACjH,OAAO,EAAE,OAAO;IAChB,MAAM,EAAE,oDAAoD;IAC5D,SAAS,EAAE,KAAK;IAChB,KAAK,EAAE,IAAI;IACX,sHAAsH;IACtH,SAAS,EAAE,KAAK;IAChB,gBAAgB,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC;IAC9B,MAAM,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE;CAC7B,CAAA;AAED,MAAM,CAAC,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,6BAA6B,EAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAA"}
|
package/dist/mail/backend.d.ts
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
import type { MailSource } from "@wirecat/cli-core/mail";
|
|
1
|
+
import type { MailCriteria, MailSource, Searched } from "@wirecat/cli-core/mail";
|
|
2
|
+
import type { SearchSyntax } from "./imap/search.js";
|
|
2
3
|
export interface MailEndpoint {
|
|
3
4
|
host: string;
|
|
4
5
|
port: number;
|
|
5
6
|
/** `plain` is for a local test server only; no profile can ask for it. */
|
|
6
7
|
security: "tls" | "starttls" | "plain";
|
|
7
8
|
login: string;
|
|
9
|
+
/** The submission server; without it the backend cannot send. */
|
|
10
|
+
smtp?: Pick<MailEndpoint, "host" | "port" | "security">;
|
|
8
11
|
}
|
|
9
12
|
/** What the run lets a backend spend: a retry is a request of its budget, and none outlives its deadline. */
|
|
10
13
|
export interface RunBounds {
|
|
@@ -25,10 +28,87 @@ export interface AccountCheck {
|
|
|
25
28
|
features: Record<"idle" | "condstore" | "qresync" | "move" | "uidplus" | "compress" | "x_gm_ext_1" | "objectid", boolean>;
|
|
26
29
|
folders: number;
|
|
27
30
|
}
|
|
31
|
+
/** A message's flags as the server holds them now; `labels` only on Gmail, in its own spelling (`\Inbox`, `Work`). */
|
|
32
|
+
export interface ServerState {
|
|
33
|
+
flags: string[];
|
|
34
|
+
labels?: string[];
|
|
35
|
+
/** The Message-ID, to find the message again on a server that gives no new UID after a move. */
|
|
36
|
+
messageId?: string;
|
|
37
|
+
}
|
|
38
|
+
/** Where a move or copy put the messages: their UIDs in the target, and its UIDVALIDITY, where the server says. */
|
|
39
|
+
export interface Moved {
|
|
40
|
+
uids: Map<number, number>;
|
|
41
|
+
validity?: string;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* The changes a command makes to a mailbox. Every call on messages names the folder's UIDVALIDITY as it was read with
|
|
45
|
+
* the UIDs: a server that changed it since is refused, so no UID lands on another message. None of these is retried:
|
|
46
|
+
* a write that may have reached the server is not sent twice.
|
|
47
|
+
*/
|
|
48
|
+
export interface MailWrites {
|
|
49
|
+
/**
|
|
50
|
+
* The folder's UIDVALIDITY, and the UID there of each Gmail id (`emailIds`) or Message-ID (`messageIds`)
|
|
51
|
+
* asked for, keyed by what was asked; one not there is left out.
|
|
52
|
+
*/
|
|
53
|
+
locate(folder: string, ids: {
|
|
54
|
+
emailIds?: readonly string[];
|
|
55
|
+
messageIds?: readonly string[];
|
|
56
|
+
}): Promise<{
|
|
57
|
+
validity: string;
|
|
58
|
+
uids: Map<string, number>;
|
|
59
|
+
}>;
|
|
60
|
+
state(folder: string, validity: string, uids: readonly number[]): Promise<Map<number, ServerState>>;
|
|
61
|
+
flag(folder: string, validity: string, uids: readonly number[], change: {
|
|
62
|
+
add?: string[];
|
|
63
|
+
remove?: string[];
|
|
64
|
+
}): Promise<void>;
|
|
65
|
+
/** Gmail labels, by `X-GM-LABELS`. */
|
|
66
|
+
label(folder: string, validity: string, uids: readonly number[], change: {
|
|
67
|
+
add?: string[];
|
|
68
|
+
remove?: string[];
|
|
69
|
+
}): Promise<void>;
|
|
70
|
+
/** Each moved UID's new UID in `to`, where the server says (UIDPLUS). */
|
|
71
|
+
move(folder: string, validity: string, uids: readonly number[], to: string): Promise<Moved>;
|
|
72
|
+
copy(folder: string, validity: string, uids: readonly number[], to: string): Promise<Moved>;
|
|
73
|
+
/** `\Deleted` and UID EXPUNGE of exactly these UIDs: gone for good. Undoing a copy, drafts delete and drafts send. */
|
|
74
|
+
expunge(folder: string, validity: string, uids: readonly number[]): Promise<void>;
|
|
75
|
+
/** Stores a message the tool built, with its flags; the new UID and UIDVALIDITY where the server says (APPENDUID). */
|
|
76
|
+
append(folder: string, raw: Uint8Array, flags: readonly string[]): Promise<{
|
|
77
|
+
uid?: number;
|
|
78
|
+
validity?: string;
|
|
79
|
+
}>;
|
|
80
|
+
createFolder(path: string): Promise<void>;
|
|
81
|
+
renameFolder(path: string, to: string): Promise<void>;
|
|
82
|
+
deleteFolder(path: string): Promise<void>;
|
|
83
|
+
}
|
|
84
|
+
/** One message to hand the submission server: the envelope says who receives it, Bcc included; `raw` has no Bcc line. */
|
|
85
|
+
export interface Submission {
|
|
86
|
+
from: string;
|
|
87
|
+
recipients: readonly string[];
|
|
88
|
+
raw: Uint8Array;
|
|
89
|
+
}
|
|
90
|
+
export interface Submitted {
|
|
91
|
+
/** The envelope recipients the server took, and those it refused; a send with none taken fails instead. */
|
|
92
|
+
accepted: string[];
|
|
93
|
+
rejected: string[];
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Sends over SMTP. Never retried: a server that took the message and then lost the line has sent it, so a failure
|
|
97
|
+
* after the message left is `outcome_unknown`, and one before it is marked `sent: false`.
|
|
98
|
+
*/
|
|
99
|
+
export interface MailSubmit {
|
|
100
|
+
send(message: Submission): Promise<Submitted>;
|
|
101
|
+
}
|
|
28
102
|
/** Everything a command asks of one mailbox. cli-core's sync reads it as a `MailSource`. */
|
|
29
103
|
export interface MailBackend extends MailSource {
|
|
30
104
|
check(): Promise<AccountCheck>;
|
|
31
105
|
folderList(): Promise<FolderInfo[]>;
|
|
106
|
+
/** The UIDs the server's own search finds in `folder`, in the provider's syntax. */
|
|
107
|
+
serverQuery?(criteria: MailCriteria, folder: string, syntax: SearchSyntax): Promise<Searched>;
|
|
108
|
+
/** Absent on a backend that cannot change the mailbox. */
|
|
109
|
+
writes?: MailWrites;
|
|
110
|
+
/** Absent where the profile names no submission server. */
|
|
111
|
+
submit?: MailSubmit;
|
|
32
112
|
/** After this, every call fails; nothing reconnects. */
|
|
33
113
|
close(): Promise<void>;
|
|
34
114
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../../src/mail/backend.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;
|
|
1
|
+
{"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../../src/mail/backend.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/** What one step did to the mailbox; its inverse is what `messages restore` does. */
|
|
2
|
+
export type ChangeOp = "flag" | "label" | "move" | "copy" | "trash";
|
|
3
|
+
export interface ChangedItem {
|
|
4
|
+
/** The stored email's id: Gmail's X-GM-MSGID, or the hash of its Message-ID. */
|
|
5
|
+
id: string;
|
|
6
|
+
uid: number;
|
|
7
|
+
/** Of the flags or labels this step changes, the ones the message had before it. */
|
|
8
|
+
had?: string[];
|
|
9
|
+
/** On Gmail, every label the message had before it went to Trash, so a restore puts them back. */
|
|
10
|
+
labels?: string[];
|
|
11
|
+
/** The Message-ID, to find the message again where the server gives no new UID. */
|
|
12
|
+
mid?: string;
|
|
13
|
+
}
|
|
14
|
+
/** Written before the server is asked: a step the server made without answering is still undone. */
|
|
15
|
+
export interface StepLine {
|
|
16
|
+
type: "step";
|
|
17
|
+
step: number;
|
|
18
|
+
op: ChangeOp;
|
|
19
|
+
folder: string;
|
|
20
|
+
validity: string;
|
|
21
|
+
to?: string;
|
|
22
|
+
change?: {
|
|
23
|
+
add?: string[];
|
|
24
|
+
remove?: string[];
|
|
25
|
+
};
|
|
26
|
+
items: ChangedItem[];
|
|
27
|
+
}
|
|
28
|
+
export interface DoneLine {
|
|
29
|
+
type: "done";
|
|
30
|
+
step: number;
|
|
31
|
+
ids: string[];
|
|
32
|
+
/** The UIDs the moved or copied messages have in `to`, by id, where the server said. */
|
|
33
|
+
uids?: Record<string, number>;
|
|
34
|
+
to_validity?: string;
|
|
35
|
+
}
|
|
36
|
+
export interface RunLine {
|
|
37
|
+
type: "run";
|
|
38
|
+
id: string;
|
|
39
|
+
account: string;
|
|
40
|
+
command: string;
|
|
41
|
+
started_at: string;
|
|
42
|
+
/** Gmail empties Trash after 30 days; a run that trashed mail there can be undone until then. */
|
|
43
|
+
restorable_until?: string;
|
|
44
|
+
}
|
|
45
|
+
export interface RestoreLine {
|
|
46
|
+
type: "restore";
|
|
47
|
+
at: string;
|
|
48
|
+
ids: string[];
|
|
49
|
+
}
|
|
50
|
+
export interface ChangeRun {
|
|
51
|
+
run: RunLine;
|
|
52
|
+
steps: {
|
|
53
|
+
step: StepLine;
|
|
54
|
+
done?: DoneLine;
|
|
55
|
+
}[];
|
|
56
|
+
restored: Set<string>;
|
|
57
|
+
}
|
|
58
|
+
/** One command's record of what it changed, appended as it goes; the file is the owner's only. */
|
|
59
|
+
export declare class ChangeLog {
|
|
60
|
+
readonly run: RunLine;
|
|
61
|
+
readonly path: string;
|
|
62
|
+
private step;
|
|
63
|
+
constructor(env: NodeJS.ProcessEnv, run: RunLine);
|
|
64
|
+
private write;
|
|
65
|
+
begin(step: Omit<StepLine, "type" | "step">): number;
|
|
66
|
+
done(step: number, ids: string[], moved?: {
|
|
67
|
+
uids: Map<string, number>;
|
|
68
|
+
validity?: string;
|
|
69
|
+
}): void;
|
|
70
|
+
end(at: number): void;
|
|
71
|
+
}
|
|
72
|
+
export declare const appendRestore: (path: string, ids: string[], at: number) => void;
|
|
73
|
+
/** A run of this mailbox, by the id its answer gave; memo's cleanup runs are found too. */
|
|
74
|
+
export declare const readRun: (env: NodeJS.ProcessEnv, account: string, id: string) => {
|
|
75
|
+
path: string;
|
|
76
|
+
run: ChangeRun;
|
|
77
|
+
};
|
|
78
|
+
export interface RunSummary {
|
|
79
|
+
id: string;
|
|
80
|
+
account: string;
|
|
81
|
+
command: string;
|
|
82
|
+
started_at: string;
|
|
83
|
+
/** No end line: the process stopped part way, so some steps may be done and others not. */
|
|
84
|
+
unfinished: boolean;
|
|
85
|
+
restorable_until: string | null;
|
|
86
|
+
/** Moved to Trash and not restored since. */
|
|
87
|
+
in_trash: number;
|
|
88
|
+
}
|
|
89
|
+
/** Every recorded run on this computer, of every mailbox, memo's cleanup runs included; newest first. */
|
|
90
|
+
export declare const runSummaries: (env: NodeJS.ProcessEnv) => RunSummary[];
|
|
91
|
+
//# sourceMappingURL=changes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"changes.d.ts","sourceRoot":"","sources":["../../src/mail/changes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { appendFileSync, existsSync, mkdirSync, readdirSync, readFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { CliError, resolvePaths } from "@wirecat/cli-base";
|
|
4
|
+
const RUN_ID = /^[\w.:-]+$/;
|
|
5
|
+
const runsDir = (env, account) => join(resolvePaths({ appName: "mail-cli", prefix: "MAIL", env }).state, "changes", account.toLowerCase());
|
|
6
|
+
const readLines = (path) => readFileSync(path, "utf8")
|
|
7
|
+
.split("\n")
|
|
8
|
+
.filter(Boolean)
|
|
9
|
+
.flatMap((text) => {
|
|
10
|
+
try {
|
|
11
|
+
return [JSON.parse(text)];
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
// A torn last line from a run that died; the lines before it still say what happened.
|
|
15
|
+
return [];
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
/** One command's record of what it changed, appended as it goes; the file is the owner's only. */
|
|
19
|
+
export class ChangeLog {
|
|
20
|
+
run;
|
|
21
|
+
path;
|
|
22
|
+
step = 0;
|
|
23
|
+
constructor(env, run) {
|
|
24
|
+
this.run = run;
|
|
25
|
+
const dir = runsDir(env, run.account);
|
|
26
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
27
|
+
this.path = join(dir, `${run.id.replace(/[^\w.-]/g, "_")}.jsonl`);
|
|
28
|
+
this.write(run);
|
|
29
|
+
}
|
|
30
|
+
write(line) {
|
|
31
|
+
appendFileSync(this.path, `${JSON.stringify(line)}\n`, { mode: 0o600 });
|
|
32
|
+
}
|
|
33
|
+
begin(step) {
|
|
34
|
+
this.step++;
|
|
35
|
+
this.write({ type: "step", step: this.step, ...step });
|
|
36
|
+
return this.step;
|
|
37
|
+
}
|
|
38
|
+
done(step, ids, moved) {
|
|
39
|
+
this.write({
|
|
40
|
+
type: "done",
|
|
41
|
+
step,
|
|
42
|
+
ids,
|
|
43
|
+
...(moved?.uids.size ? { uids: Object.fromEntries(moved.uids) } : {}),
|
|
44
|
+
...(moved?.validity ? { to_validity: moved.validity } : {}),
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
end(at) {
|
|
48
|
+
this.write({ type: "end", ended_at: new Date(at).toISOString() });
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
export const appendRestore = (path, ids, at) => {
|
|
52
|
+
// A file another program wrote may end without a newline, and the line would join its last one and be lost.
|
|
53
|
+
const lead = readFileSync(path, "utf8").endsWith("\n") ? "" : "\n";
|
|
54
|
+
appendFileSync(path, `${lead}${JSON.stringify({ type: "restore", at: new Date(at).toISOString(), ids })}\n`);
|
|
55
|
+
};
|
|
56
|
+
/** Gmail's own names for its system labels, as `X-GM-LABELS` takes them. */
|
|
57
|
+
const SYSTEM_LABELS = new Set(["Inbox", "Important", "Starred", "Sent", "Drafts", "Spam", "Trash"]);
|
|
58
|
+
const gmailLabel = (label) => (SYSTEM_LABELS.has(label) ? `\\${label}` : label);
|
|
59
|
+
/** What came back from a memo run: memo wrote `restored`, a restore made here writes `ids`. */
|
|
60
|
+
const memoRestored = (lines) => new Set(lines
|
|
61
|
+
.filter(({ type }) => type === "restore")
|
|
62
|
+
.flatMap((line) => [...(line.restored ?? []), ...(line.ids ?? [])]));
|
|
63
|
+
/**
|
|
64
|
+
* A cleanup run memo made before the cleanup moved here: memo kept it under its own state folder, one file per run,
|
|
65
|
+
* with every email's labels. It reads as one Gmail step from All Mail to Trash.
|
|
66
|
+
*/
|
|
67
|
+
const memoRun = (env, account, id) => {
|
|
68
|
+
const root = join(resolvePaths({ appName: "cli-memo", prefix: "MEMO", env }).state, "mail-trash");
|
|
69
|
+
if (!existsSync(root))
|
|
70
|
+
return undefined;
|
|
71
|
+
for (const name of readdirSync(root)) {
|
|
72
|
+
const path = join(root, name, `${id}.jsonl`);
|
|
73
|
+
if (!existsSync(path))
|
|
74
|
+
continue;
|
|
75
|
+
const lines = readLines(path);
|
|
76
|
+
const head = lines.find(({ type }) => type === "run");
|
|
77
|
+
if (String(head?.account ?? "").toLowerCase() !== account.toLowerCase())
|
|
78
|
+
continue;
|
|
79
|
+
const started = String(head?.started_at ?? "");
|
|
80
|
+
const emails = lines.filter(({ type }) => type === "email");
|
|
81
|
+
const step = {
|
|
82
|
+
type: "step",
|
|
83
|
+
step: 1,
|
|
84
|
+
op: "trash",
|
|
85
|
+
folder: "",
|
|
86
|
+
validity: "",
|
|
87
|
+
items: emails.map((line) => ({
|
|
88
|
+
id: String(line.message_id),
|
|
89
|
+
uid: 0,
|
|
90
|
+
labels: (line.labels ?? []).map(gmailLabel),
|
|
91
|
+
})),
|
|
92
|
+
};
|
|
93
|
+
return {
|
|
94
|
+
path,
|
|
95
|
+
run: {
|
|
96
|
+
run: {
|
|
97
|
+
type: "run",
|
|
98
|
+
id,
|
|
99
|
+
account,
|
|
100
|
+
command: "memo mail delete",
|
|
101
|
+
started_at: started,
|
|
102
|
+
restorable_until: new Date(Date.parse(started) + 30 * 86_400_000).toISOString(),
|
|
103
|
+
},
|
|
104
|
+
// Every logged email, not only those a batch line confirms: a move Gmail made but did not answer leaves none.
|
|
105
|
+
steps: [{ step }],
|
|
106
|
+
restored: memoRestored(lines),
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
return undefined;
|
|
111
|
+
};
|
|
112
|
+
/** A run of this mailbox, by the id its answer gave; memo's cleanup runs are found too. */
|
|
113
|
+
export const readRun = (env, account, id) => {
|
|
114
|
+
if (!RUN_ID.test(id))
|
|
115
|
+
throw new CliError("validation_error", "a run id is letters, digits, dots, colons and dashes");
|
|
116
|
+
const path = join(runsDir(env, account), `${id.replace(/[^\w.-]/g, "_")}.jsonl`);
|
|
117
|
+
if (!existsSync(path)) {
|
|
118
|
+
const memo = memoRun(env, account, id);
|
|
119
|
+
if (memo)
|
|
120
|
+
return memo;
|
|
121
|
+
throw new CliError("not_found", `no change run ${id} for ${account}`, { reason: "mail.run-unknown" });
|
|
122
|
+
}
|
|
123
|
+
const lines = readLines(path);
|
|
124
|
+
const run = lines.find((line) => line.type === "run");
|
|
125
|
+
if (!run)
|
|
126
|
+
throw new CliError("invalid_response", `the record of run ${id} has no start line`);
|
|
127
|
+
const done = new Map(lines.filter((line) => line.type === "done").map((line) => [line.step, line]));
|
|
128
|
+
return {
|
|
129
|
+
path,
|
|
130
|
+
run: {
|
|
131
|
+
run,
|
|
132
|
+
steps: lines
|
|
133
|
+
.filter((line) => line.type === "step")
|
|
134
|
+
.map((step) => ({ step, ...(done.has(step.step) ? { done: done.get(step.step) } : {}) })),
|
|
135
|
+
restored: new Set(lines.filter((line) => line.type === "restore").flatMap(({ ids }) => ids)),
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
};
|
|
139
|
+
const summaryOf = (lines) => {
|
|
140
|
+
const run = lines.find((line) => line.type === "run");
|
|
141
|
+
if (!run)
|
|
142
|
+
return undefined;
|
|
143
|
+
const done = new Set(lines
|
|
144
|
+
.filter((line) => line.type === "done")
|
|
145
|
+
.flatMap(({ step, ids }) => ids.map((one) => `${step}:${one}`)));
|
|
146
|
+
const restored = new Set(lines.filter((line) => line.type === "restore").flatMap(({ ids }) => ids));
|
|
147
|
+
const trashed = new Set(lines
|
|
148
|
+
.filter((line) => line.type === "step" && line.op === "trash")
|
|
149
|
+
.flatMap(({ step, items }) => items.filter(({ id }) => done.has(`${step}:${id}`)).map(({ id }) => id)));
|
|
150
|
+
return {
|
|
151
|
+
id: run.id,
|
|
152
|
+
account: run.account,
|
|
153
|
+
command: run.command,
|
|
154
|
+
started_at: run.started_at,
|
|
155
|
+
unfinished: !lines.some(({ type }) => type === "end"),
|
|
156
|
+
restorable_until: run.restorable_until ?? null,
|
|
157
|
+
in_trash: [...trashed].filter((one) => !restored.has(one)).length,
|
|
158
|
+
};
|
|
159
|
+
};
|
|
160
|
+
/** memo's cleanup runs, from before the cleanup moved here: `email` lines are what it moved, `restore` what came back. */
|
|
161
|
+
const memoSummaries = (env) => {
|
|
162
|
+
const root = join(resolvePaths({ appName: "cli-memo", prefix: "MEMO", env }).state, "mail-trash");
|
|
163
|
+
if (!existsSync(root))
|
|
164
|
+
return [];
|
|
165
|
+
return readdirSync(root).flatMap((name) => readdirSync(join(root, name))
|
|
166
|
+
.filter((file) => file.endsWith(".jsonl"))
|
|
167
|
+
.flatMap((file) => {
|
|
168
|
+
const lines = readLines(join(root, name, file));
|
|
169
|
+
const head = lines.find(({ type }) => type === "run");
|
|
170
|
+
if (!head)
|
|
171
|
+
return [];
|
|
172
|
+
const started = String(head.started_at ?? "");
|
|
173
|
+
const restored = memoRestored(lines);
|
|
174
|
+
const moved = lines.filter(({ type }) => type === "batch").flatMap((line) => line.moved ?? []);
|
|
175
|
+
return [
|
|
176
|
+
{
|
|
177
|
+
id: file.replace(/\.jsonl$/, ""),
|
|
178
|
+
account: String(head.account ?? name),
|
|
179
|
+
command: "memo mail delete",
|
|
180
|
+
started_at: started,
|
|
181
|
+
unfinished: !lines.some(({ type }) => type === "end"),
|
|
182
|
+
restorable_until: new Date(Date.parse(started) + 30 * 86_400_000).toISOString(),
|
|
183
|
+
in_trash: moved.filter((one) => !restored.has(one)).length,
|
|
184
|
+
},
|
|
185
|
+
];
|
|
186
|
+
}));
|
|
187
|
+
};
|
|
188
|
+
/** Every recorded run on this computer, of every mailbox, memo's cleanup runs included; newest first. */
|
|
189
|
+
export const runSummaries = (env) => {
|
|
190
|
+
const root = join(resolvePaths({ appName: "mail-cli", prefix: "MAIL", env }).state, "changes");
|
|
191
|
+
const own = existsSync(root)
|
|
192
|
+
? readdirSync(root).flatMap((account) => readdirSync(join(root, account))
|
|
193
|
+
.filter((file) => file.endsWith(".jsonl"))
|
|
194
|
+
.flatMap((file) => summaryOf(readLines(join(root, account, file))) ?? []))
|
|
195
|
+
: [];
|
|
196
|
+
return [...own, ...memoSummaries(env)].sort((a, b) => b.started_at.localeCompare(a.started_at));
|
|
197
|
+
};
|
|
198
|
+
//# sourceMappingURL=changes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"changes.js","sourceRoot":"","sources":["../../src/mail/changes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { type MailRule } from "@wirecat/cli-core/mail";
|
|
2
|
+
import type { Mailbox } from "./organise.js";
|
|
3
|
+
/** A first cleanup moves few, so the owner can check them by hand before trusting the rules with more. */
|
|
4
|
+
export declare const FIRST_RUN_LIMIT = 100;
|
|
5
|
+
export declare const CLEANUP_LIMIT = 5000;
|
|
6
|
+
export type KeptReason = "no_rule" | "protected" | "rule_changed" | "replied" | "starred" | "sent" | "labelled" | "too_new" | "before_since";
|
|
7
|
+
export interface RuleTotals {
|
|
8
|
+
rule: string;
|
|
9
|
+
candidates: number;
|
|
10
|
+
bytes: number;
|
|
11
|
+
}
|
|
12
|
+
export interface Cleanup {
|
|
13
|
+
ids: string[];
|
|
14
|
+
/** Envelopes in the store for this mailbox. */
|
|
15
|
+
envelopes: number;
|
|
16
|
+
candidates: number;
|
|
17
|
+
bytes: number;
|
|
18
|
+
kept: Partial<Record<KeptReason, number>>;
|
|
19
|
+
rules: RuleTotals[];
|
|
20
|
+
limit: number;
|
|
21
|
+
first_run: boolean;
|
|
22
|
+
backup: {
|
|
23
|
+
at: string | null;
|
|
24
|
+
fresh: boolean;
|
|
25
|
+
marker: string;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/** The weekly store backup's marker, written by the backup script when a copy passed its check. */
|
|
29
|
+
export declare const backupOf: (env: NodeJS.ProcessEnv, now: number) => Cleanup["backup"];
|
|
30
|
+
/** No cleanup has moved mail of this mailbox before, here or in memo. */
|
|
31
|
+
export declare const firstCleanup: (env: NodeJS.ProcessEnv, account: string) => boolean;
|
|
32
|
+
/**
|
|
33
|
+
* The envelopes the owner's rules would have the mailbox let go, each decided again with today's rules, labels and
|
|
34
|
+
* flags as the last sync stored them; oldest first, at most `limit`.
|
|
35
|
+
*/
|
|
36
|
+
export declare const cleanupOf: (mailbox: Mailbox, rules: readonly MailRule[], { limit, since, env }: {
|
|
37
|
+
limit: number;
|
|
38
|
+
since?: Date;
|
|
39
|
+
env: NodeJS.ProcessEnv;
|
|
40
|
+
}) => Promise<Cleanup>;
|
|
41
|
+
//# sourceMappingURL=cleanup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cleanup.d.ts","sourceRoot":"","sources":["../../src/mail/cleanup.ts"],"names":[],"mappings":"AAGA,OAAO,EAAmE,KAAK,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AAEvH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAK5C,0GAA0G;AAC1G,eAAO,MAAM,eAAe,MAAM,CAAA;AAClC,eAAO,MAAM,aAAa,OAAQ,CAAA;AAKlC,MAAM,MAAM,UAAU,GAClB,SAAS,GACT,WAAW,GACX,cAAc,GACd,SAAS,GACT,SAAS,GACT,MAAM,GACN,UAAU,GACV,SAAS,GACT,cAAc,CAAA;AAElB,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,MAAM,CAAA;IAClB,KAAK,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,OAAO;IACtB,GAAG,EAAE,MAAM,EAAE,CAAA;IACb,+CAA+C;IAC/C,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAA;IACzC,KAAK,EAAE,UAAU,EAAE,CAAA;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,OAAO,CAAA;IAClB,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;CAC9D;AAwBD,mGAAmG;AACnG,eAAO,MAAM,QAAQ,QAAS,MAAM,CAAC,UAAU,OAAO,MAAM,KAAG,OAAO,CAAC,QAAQ,CAQ9E,CAAA;AAED,yEAAyE;AACzE,eAAO,MAAM,YAAY,QAAS,MAAM,CAAC,UAAU,WAAW,MAAM,KAAG,OAyBtE,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,SAAS,YACX,OAAO,SACT,SAAS,QAAQ,EAAE,yBACH;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,IAAI,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC,UAAU,CAAA;CAAE,KAC7E,OAAO,CAAC,OAAO,CA6CjB,CAAA"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { resolvePaths } from "@wirecat/cli-base";
|
|
4
|
+
import { decide, describeMatch, ENVELOPE, factsOf, listedOf } from "@wirecat/cli-core/mail";
|
|
5
|
+
import { storePath } from "@wirecat/cli-core/store";
|
|
6
|
+
const DAY = 86_400_000;
|
|
7
|
+
const MIN_AGE_DAYS = 30;
|
|
8
|
+
const BACKUP_DAYS = 8;
|
|
9
|
+
/** A first cleanup moves few, so the owner can check them by hand before trusting the rules with more. */
|
|
10
|
+
export const FIRST_RUN_LIMIT = 100;
|
|
11
|
+
export const CLEANUP_LIMIT = 5_000;
|
|
12
|
+
/** Labels Gmail sets itself; any other label on a message is the owner's, and keeps it out of the trash. */
|
|
13
|
+
const SYSTEM_LABELS = new Set(["Inbox", "Important", "Starred", "Sent", "Drafts", "Spam", "Trash"]);
|
|
14
|
+
const userLabels = (item) => (item.labels ?? []).filter((label) => !SYSTEM_LABELS.has(label));
|
|
15
|
+
/** Why an envelope stays, or undefined when the cleanup may trash it. Moved from memo's `mail delete`. */
|
|
16
|
+
const keptBecause = (item, rule, replied, now) => {
|
|
17
|
+
if (rule === undefined)
|
|
18
|
+
return "no_rule";
|
|
19
|
+
if (rule.protected || rule.action === "keep")
|
|
20
|
+
return "protected";
|
|
21
|
+
if (rule.action !== ENVELOPE && rule.action !== "skip")
|
|
22
|
+
return "rule_changed";
|
|
23
|
+
const from = item.headers?.from;
|
|
24
|
+
if (from !== undefined && replied.has(from))
|
|
25
|
+
return "replied";
|
|
26
|
+
const labels = item.labels ?? [];
|
|
27
|
+
if (item.flagged || labels.includes("Starred") || labels.includes("Important"))
|
|
28
|
+
return "starred";
|
|
29
|
+
if (labels.includes("Sent") || labels.includes("Drafts"))
|
|
30
|
+
return "sent";
|
|
31
|
+
if (userLabels(item).some((label) => !rule.tags?.includes(label)))
|
|
32
|
+
return "labelled";
|
|
33
|
+
if (now - Date.parse(item.receivedAt) < MIN_AGE_DAYS * DAY)
|
|
34
|
+
return "too_new";
|
|
35
|
+
return undefined;
|
|
36
|
+
};
|
|
37
|
+
/** The weekly store backup's marker, written by the backup script when a copy passed its check. */
|
|
38
|
+
export const backupOf = (env, now) => {
|
|
39
|
+
const marker = join(dirname(storePath(env)), "backups", "last.json");
|
|
40
|
+
let at = null;
|
|
41
|
+
try {
|
|
42
|
+
const value = JSON.parse(readFileSync(marker, "utf8")).at;
|
|
43
|
+
if (typeof value === "string" && !Number.isNaN(Date.parse(value)))
|
|
44
|
+
at = value;
|
|
45
|
+
}
|
|
46
|
+
catch { }
|
|
47
|
+
return { at, fresh: at !== null && now - Date.parse(at) < BACKUP_DAYS * DAY, marker };
|
|
48
|
+
};
|
|
49
|
+
/** No cleanup has moved mail of this mailbox before, here or in memo. */
|
|
50
|
+
export const firstCleanup = (env, account) => {
|
|
51
|
+
const own = join(resolvePaths({ appName: "mail-cli", prefix: "MAIL", env }).state, "changes", account.toLowerCase());
|
|
52
|
+
const memo = join(resolvePaths({ appName: "cli-memo", prefix: "MEMO", env }).state, "mail-trash");
|
|
53
|
+
const moved = (path, test) => {
|
|
54
|
+
try {
|
|
55
|
+
return test(readFileSync(path, "utf8"));
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
if (existsSync(own))
|
|
62
|
+
for (const name of readdirSync(own))
|
|
63
|
+
if (moved(join(own, name), (text) => text.includes("delete --rules") && text.includes('"type":"done"')))
|
|
64
|
+
return false;
|
|
65
|
+
if (existsSync(memo))
|
|
66
|
+
for (const folder of readdirSync(memo))
|
|
67
|
+
for (const name of existsSync(join(memo, folder)) ? readdirSync(join(memo, folder)) : [])
|
|
68
|
+
if (moved(join(memo, folder, name), (text) => text.includes(`"account":"${account.toLowerCase()}"`) && /"moved":\["/.test(text)))
|
|
69
|
+
return false;
|
|
70
|
+
return true;
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* The envelopes the owner's rules would have the mailbox let go, each decided again with today's rules, labels and
|
|
74
|
+
* flags as the last sync stored them; oldest first, at most `limit`.
|
|
75
|
+
*/
|
|
76
|
+
export const cleanupOf = async (mailbox, rules, { limit, since, env }) => {
|
|
77
|
+
const now = mailbox.now();
|
|
78
|
+
const first = firstCleanup(env, mailbox.key.account);
|
|
79
|
+
const cap = first ? Math.min(limit, FIRST_RUN_LIMIT) : limit;
|
|
80
|
+
const facts = (await mailbox.store.mail.emailFacts({ accountId: mailbox.accountId })).map(listedOf);
|
|
81
|
+
const envelopes = facts.filter(({ envelope }) => envelope);
|
|
82
|
+
const replied = new Set(facts.filter(({ labels }) => labels?.includes("Sent")).flatMap(({ headers }) => headers?.to ?? []));
|
|
83
|
+
const factsFor = factsOf(facts, rules);
|
|
84
|
+
const kept = {};
|
|
85
|
+
const totals = new Map();
|
|
86
|
+
const chosen = [];
|
|
87
|
+
let candidates = 0;
|
|
88
|
+
let bytes = 0;
|
|
89
|
+
for (const item of envelopes) {
|
|
90
|
+
const rule = decide(rules, factsFor(item));
|
|
91
|
+
const reason = since !== undefined && Date.parse(item.receivedAt) < since.getTime()
|
|
92
|
+
? "before_since"
|
|
93
|
+
: keptBecause(item, rule, replied, now);
|
|
94
|
+
if (reason !== undefined) {
|
|
95
|
+
kept[reason] = (kept[reason] ?? 0) + 1;
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
const name = describeMatch(rule.match);
|
|
99
|
+
const total = totals.get(name) ?? { rule: name, candidates: 0, bytes: 0 };
|
|
100
|
+
total.candidates++;
|
|
101
|
+
total.bytes += item.size ?? 0;
|
|
102
|
+
totals.set(name, total);
|
|
103
|
+
candidates++;
|
|
104
|
+
bytes += item.size ?? 0;
|
|
105
|
+
chosen.push(item.messageId);
|
|
106
|
+
}
|
|
107
|
+
return {
|
|
108
|
+
ids: chosen.slice(0, cap),
|
|
109
|
+
envelopes: envelopes.length,
|
|
110
|
+
candidates,
|
|
111
|
+
bytes,
|
|
112
|
+
kept,
|
|
113
|
+
rules: [...totals.values()].sort((a, b) => b.candidates - a.candidates),
|
|
114
|
+
limit: cap,
|
|
115
|
+
first_run: first,
|
|
116
|
+
backup: backupOf(env, now),
|
|
117
|
+
};
|
|
118
|
+
};
|
|
119
|
+
//# sourceMappingURL=cleanup.js.map
|