@wirecat/mail-cli 0.5.0 → 0.7.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 +149 -0
- package/README.md +48 -13
- package/dist/bin/mail.js +2 -2
- package/dist/bundle/{all-profiles-GR5JXYEQ.js → all-profiles-SI67TKZM.js} +9 -9
- package/dist/bundle/{anthropic-REBXE65F.js → anthropic-DALMLC3Y.js} +6 -6
- package/dist/bundle/{app-server-QJ7ICQXZ.js → app-server-XOH327Z2.js} +46 -46
- package/dist/bundle/{bun-WAX4QHW5.js → bun-ORL67CJ6.js} +2 -2
- package/dist/bundle/{bun-sqlite-5S7TQ4SG.js → bun-sqlite-DGXFNFHI.js} +5 -5
- package/dist/bundle/{chunk-ZD3WUGR2.js → chunk-23IEVVL2.js} +4 -4
- package/dist/bundle/{chunk-B5WSIWY5.js → chunk-2M4K7HYR.js} +17 -17
- package/dist/bundle/{chunk-IWDOGGMY.js → chunk-35KD2CI2.js} +501 -301
- package/dist/bundle/{chunk-7A7BHABA.js → chunk-3GZK5GTU.js} +1 -1
- package/dist/bundle/{chunk-JJBQPA7D.js → chunk-3TYEJRMZ.js} +4 -4
- package/dist/bundle/{chunk-M6BDHZON.js → chunk-45KA5667.js} +26 -13
- package/dist/bundle/{chunk-LOA4X6JW.js → chunk-4NYWHINR.js} +6 -6
- package/dist/bundle/{dist-KJOAJ6NF.js → chunk-4ULY3GDL.js} +16 -116
- package/dist/bundle/{chunk-2FXVBCA3.js → chunk-5BSEGMNE.js} +4 -4
- package/dist/bundle/{chunk-HCMUGUAG.js → chunk-5JEYIHS6.js} +3 -3
- package/dist/bundle/{chunk-QXOSGGKS.js → chunk-6LK7KTWB.js} +1 -1
- package/dist/bundle/{chunk-ESNNQA7D.js → chunk-6RMMAUUW.js} +28 -28
- package/dist/bundle/{chunk-VXAZZGXE.js → chunk-6XNPXAJU.js} +33 -27
- package/dist/bundle/{chunk-5INWLYBD.js → chunk-73OJJGZE.js} +14 -3
- package/dist/bundle/{chunk-4XJ4AM3K.js → chunk-7K6KJWTO.js} +12 -12
- package/dist/bundle/{chunk-KIDF77MA.js → chunk-AP7V256W.js} +1 -1
- package/dist/bundle/{chunk-4BMNP2FT.js → chunk-BEMLGWY4.js} +1 -1
- package/dist/bundle/{chunk-BFJV4FWJ.js → chunk-BGUMGCUY.js} +2 -2
- package/dist/bundle/{chunk-5BVIWP3S.js → chunk-BM445GYF.js} +2 -2
- package/dist/bundle/{chunk-F3NYA4KN.js → chunk-CAKBG5FC.js} +6 -6
- package/dist/bundle/{chunk-EB3R2PV3.js → chunk-DKQWTQVY.js} +23 -23
- package/dist/bundle/{chunk-6TY3DGCC.js → chunk-DXGMPMFP.js} +4 -4
- package/dist/bundle/{chunk-LFRHIXCF.js → chunk-E3DRM6YP.js} +3 -3
- package/dist/bundle/{chunk-FSUNGHRI.js → chunk-EYT33MM3.js} +47 -46
- package/dist/bundle/{chunk-DXDQOZ2P.js → chunk-FPOGVDLS.js} +2 -2
- package/dist/bundle/{chunk-S677WGOQ.js → chunk-FTFNWGIR.js} +8 -8
- package/dist/bundle/{chunk-TI6VBZKJ.js → chunk-FUB3X25H.js} +4 -4
- package/dist/bundle/{chunk-7JCRQX56.js → chunk-GJUUTUK4.js} +8 -8
- package/dist/bundle/{chunk-BLS5YG77.js → chunk-HFJNEXU7.js} +2 -2
- package/dist/bundle/{chunk-YKPBC3NL.js → chunk-HV3EIYX4.js} +1 -1
- package/dist/bundle/{chunk-EL554DV2.js → chunk-IYZHM3ZN.js} +3 -3
- package/dist/bundle/{chunk-6EO7GVYJ.js → chunk-JFMUI4H6.js} +1 -1
- package/dist/bundle/{chunk-2YQNBIDQ.js → chunk-LZ5J3UXD.js} +4 -4
- package/dist/bundle/{chunk-WNCCYHRV.js → chunk-M2JCUVCJ.js} +116 -95
- package/dist/bundle/{chunk-7F3NDIYL.js → chunk-MCJ7LKYR.js} +6 -6
- package/dist/bundle/{chunk-VDAIJM5L.js → chunk-MHQKHWCJ.js} +88 -34
- package/dist/bundle/{chunk-SQ7KOBRA.js → chunk-MMXMVGA6.js} +10 -8
- package/dist/bundle/{chunk-AFCGOZR7.js → chunk-NNIXREJH.js} +7 -7
- package/dist/bundle/{chunk-LQ37ALDJ.js → chunk-NXJLC2WK.js} +8 -8
- package/dist/bundle/{chunk-6GE3EADU.js → chunk-OHTR4WFO.js} +2 -2
- package/dist/bundle/{chunk-PJCTWPJB.js → chunk-PDL4UREY.js} +8 -8
- package/dist/bundle/{chunk-J3QXTBD2.js → chunk-Q2C3VMSU.js} +20 -18
- package/dist/bundle/{chunk-SWJAG5IE.js → chunk-Q44AYEOB.js} +2 -2
- package/dist/bundle/{chunk-P7P5MNAU.js → chunk-QZBT6BOU.js} +1 -1
- package/dist/bundle/{chunk-IBYTYIYO.js → chunk-R5MML3FC.js} +61 -54
- package/dist/bundle/{chunk-CEAANMJ2.js → chunk-RQVWZBW3.js} +3 -3
- package/dist/bundle/{chunk-5CXAH4Y6.js → chunk-S4YUR4S3.js} +656 -572
- package/dist/bundle/{chunk-QX7RCLRS.js → chunk-SQLCCKEL.js} +1 -1
- package/dist/bundle/chunk-U6UJ3HRS.js +58 -0
- package/dist/bundle/{chunk-YRGBZZUW.js → chunk-V4TDG4KF.js} +14 -14
- package/dist/bundle/{chunk-5FK6RD4M.js → chunk-VBOMKZ4E.js} +73 -57
- package/dist/bundle/{chunk-MQUJEQTU.js → chunk-VKPWP3AK.js} +2 -2
- package/dist/bundle/{chunk-7XNPSIWD.js → chunk-VNJMO5F6.js} +2 -2
- package/dist/bundle/{chunk-MMDCL42A.js → chunk-VSHJWTX5.js} +12 -6
- package/dist/bundle/{chunk-2MRECWJZ.js → chunk-XQJWMBDY.js} +6 -6
- package/dist/bundle/{chunk-2U4IANVV.js → chunk-ZKCNMW7G.js} +2 -2
- package/dist/bundle/{chunk-LNS27BTB.js → chunk-ZKZABB4K.js} +3 -3
- package/dist/bundle/{chunk-WNI5BZFB.js → chunk-ZNGQ3NZ4.js} +9 -9
- package/dist/bundle/command-contract-CB5BII3S.js +34 -0
- package/dist/bundle/{decode-D7BDVIVB.js → decode-KOBURZIQ.js} +5 -5
- package/dist/bundle/{dispatch-EUKKT3PD.js → dispatch-GDAH4JHS.js} +8 -8
- package/dist/bundle/dist-T7HMT675.js +134 -0
- package/dist/bundle/{echarts-IVRX7XHP.js → echarts-LEWTQO6H.js} +2 -2
- package/dist/bundle/{embed-X527RBTG.js → embed-PUFE4BSQ.js} +6 -6
- package/dist/bundle/{embedder-F4PSJS6S.js → embedder-3G4BQQ6X.js} +9 -9
- package/dist/bundle/{failure-OAIC5VAP.js → failure-6COJAO7T.js} +2 -2
- package/dist/bundle/{first-run-M5CIX6NA.js → first-run-FLXOC53U.js} +11 -11
- package/dist/bundle/first-screen-VUZEDSQW.js +32 -0
- package/dist/bundle/{instructions-UX36BT5F.js → instructions-HGSXDCBT.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-OXT7WE2T.js → node-5Z7PS4F5.js} +2 -2
- package/dist/bundle/{node-sqlite-X2PSEHA4.js → node-sqlite-OAW7APIX.js} +5 -5
- package/dist/bundle/{oauth-MYK4BSYN.js → oauth-ZFZWPAJN.js} +7 -7
- package/dist/bundle/{open-GONIP2DH.js → open-ZQMBZVH4.js} +4 -4
- package/dist/bundle/{openai-YJFNUOQT.js → openai-XT2RIXAK.js} +14 -14
- package/dist/bundle/{process-7IEUUSRK.js → process-VVEQIHPE.js} +1 -1
- package/dist/bundle/{program-Q73TTG3E.js → program-RD3BBDNY.js} +21470 -7075
- package/dist/bundle/{prompt-SKQ72KN7.js → prompt-PU7GE4Z4.js} +5 -5
- package/dist/bundle/{recognize-GC7CU2DB.js → recognize-AG4A3KUK.js} +4 -4
- package/dist/bundle/{remote-UEXFZP2I.js → remote-D6TQ6T7F.js} +7 -7
- package/dist/bundle/{rerank-2U2NDEZP.js → rerank-GO24HJPF.js} +7 -7
- package/dist/bundle/{serve-OOGKFEWL.js → serve-WCHJAH6G.js} +9 -9
- package/dist/bundle/server-5KJJ3D6P.js +63 -0
- package/dist/bundle/{server-FZ3LFQTF.js → server-CAVNBG3P.js} +38 -38
- package/dist/bundle/{sqlite-runtime-GIQSW6LJ.js → sqlite-runtime-ANXC4AW2.js} +5 -5
- package/dist/bundle/{state-EMFXPQVZ.js → state-EGJ66A62.js} +6 -6
- package/dist/bundle/{store-BDU4UPNK.js → store-OON7FCMQ.js} +15 -15
- package/dist/bundle/{store-LDI62AUG.js → store-SBFA444C.js} +13 -13
- package/dist/bundle/store-maintenance-command-UEOJLYMJ.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 +21 -6
- package/dist/commands/context.d.ts.map +1 -1
- package/dist/commands/context.js +58 -7
- 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 +243 -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 +278 -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 +506 -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 +14 -3
- 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/session-start.d.ts.map +1 -1
- package/dist/commands/session-start.js +107 -10
- package/dist/commands/session-start.js.map +1 -1
- package/dist/commands/session.d.ts.map +1 -1
- package/dist/commands/session.js +72 -9
- package/dist/commands/session.js.map +1 -1
- package/dist/commands/stats.d.ts +3 -0
- package/dist/commands/stats.d.ts.map +1 -0
- package/dist/commands/stats.js +89 -0
- package/dist/commands/stats.js.map +1 -0
- package/dist/commands/status.js +2 -2
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/sync.d.ts +6 -0
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +28 -20
- 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 +15 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +52 -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 +104 -2
- package/dist/mail/backend.d.ts.map +1 -1
- package/dist/mail/backend.js +4 -1
- package/dist/mail/backend.js.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 +110 -0
- package/dist/mail/compose.js.map +1 -0
- package/dist/mail/doctor.d.ts +67 -0
- package/dist/mail/doctor.d.ts.map +1 -0
- package/dist/mail/doctor.js +115 -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 +13 -3
- package/dist/mail/imap/connection.d.ts.map +1 -1
- package/dist/mail/imap/connection.js +87 -18
- package/dist/mail/imap/connection.js.map +1 -1
- package/dist/mail/imap/index.d.ts +3 -3
- package/dist/mail/imap/index.d.ts.map +1 -1
- package/dist/mail/imap/index.js +14 -4
- 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 +55 -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 +9 -0
- package/dist/mail/save.d.ts.map +1 -0
- package/dist/mail/save.js +50 -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 +173 -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 +133 -0
- package/dist/mail/smtp.js.map +1 -0
- package/dist/oauth.d.ts +74 -0
- package/dist/oauth.d.ts.map +1 -0
- package/dist/oauth.js +230 -0
- package/dist/oauth.js.map +1 -0
- package/dist/program.d.ts.map +1 -1
- package/dist/program.js +26 -4
- package/dist/program.js.map +1 -1
- package/dist/providers.d.ts +96 -9
- package/dist/providers.d.ts.map +1 -1
- package/dist/providers.js +69 -16
- 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 +27 -0
- package/dist/reasons.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +7 -5
- package/skills/mail-cli/SKILL.md +30 -3
- package/dist/bundle/chunk-YD5WV757.js +0 -27
- package/dist/bundle/command-contract-GPUED3GT.js +0 -34
- package/dist/bundle/first-screen-M7MT776O.js +0 -32
- package/dist/bundle/server-4JMHDHZ7.js +0 -63
- package/dist/bundle/store-maintenance-command-OFRPORN2.js +0 -52
- /package/dist/bundle/{chunk-NPGVOZVK.js → chunk-WJWLHLQ7.js} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../../src/mail/rules/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqC,SAAS,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAGrG,MAAM,UAAU,GAAG,CAAC,OAAe,EAAc,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAA;AAE3G,sFAAsF;AACtF,MAAM,WAAW,GAAG,CAAC,KAAmB,EAAE,OAAe,EAAE,EAAE,CAC3D,KAAK,CAAC,QAAQ,CAAC,WAAW,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAA;AAEpE,MAAM,CAAC,MAAM,QAAQ,GAAG,KAAK,EAAE,KAAmB,EAAE,OAAe,EAAE,IAAc,EAAqB,EAAE;IACxG,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,WAAW,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAA;IAC5G,OAAO,cAAc,CAAC,MAAM,CAAC,IAAI,IAAI,CAAA;AACvC,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,UAAU,GAAG,KAAK,EAAE,KAAmB,EAAE,OAAe,EAAE,KAAoB,EAAoB,EAAE;IAC/G,MAAM,EAAE,UAAU,EAAE,GAAG,SAAS,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,CAAA;IACjG,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,WAAW,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,UAAU,CAAC,CAAA;AAC/E,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,UAAU,GAAG,KAAK,EAAE,KAAmB,EAAE,OAAe,EAAE,EAAE,CACvE,IAAI,GAAG,CACL,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,WAAW,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;IACpG,MAAM;IACN,EAAE,MAAM,EAAE,KAAK,EAAE;CAClB,CAAC,CACH,CAAA"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const present: (path: string) => boolean;
|
|
2
|
+
/** A file only this user reads. Without `overwrite` an existing file is never touched. */
|
|
3
|
+
export declare const savePrivately: (path: string, bytes: Uint8Array, overwrite: boolean) => Promise<void>;
|
|
4
|
+
export declare const refuseExisting: (path: string) => void;
|
|
5
|
+
/** A sender's file name as cli-core's downloads clean it, or `fallback` when nothing safe is left of it. */
|
|
6
|
+
export declare const safeName: (name: string, fallback: string) => string;
|
|
7
|
+
/** `report.pdf`, then `report (2).pdf` for the second of the same name in one message. */
|
|
8
|
+
export declare const distinctNames: (names: readonly string[]) => string[];
|
|
9
|
+
//# sourceMappingURL=save.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"save.d.ts","sourceRoot":"","sources":["../../src/mail/save.ts"],"names":[],"mappings":"AAWA,eAAO,MAAM,OAAO,SAAU,MAAM,KAAG,OAQtC,CAAA;AAED,0FAA0F;AAC1F,eAAO,MAAM,aAAa,SAAgB,MAAM,SAAS,UAAU,aAAa,OAAO,KAAG,OAAO,CAAC,IAAI,CAQrG,CAAA;AAED,eAAO,MAAM,cAAc,SAAU,MAAM,KAAG,IAE7C,CAAA;AAED,4GAA4G;AAC5G,eAAO,MAAM,QAAQ,SAAU,MAAM,YAAY,MAAM,KAAG,MAAoD,CAAA;AAE9G,0FAA0F;AAC1F,eAAO,MAAM,aAAa,UAAW,SAAS,MAAM,EAAE,KAAG,MAAM,EAS9D,CAAA"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { lstatSync, mkdirSync } from "node:fs";
|
|
2
|
+
import { dirname, extname } from "node:path";
|
|
3
|
+
import { CliError } from "@wirecat/cli-base";
|
|
4
|
+
import { safeName as plainName, writeFileAtomic } from "@wirecat/cli-core/files";
|
|
5
|
+
const exists = (path) => new CliError("validation_error", `${path} already exists; pass --replace to overwrite it`, {
|
|
6
|
+
reason: "download.exists",
|
|
7
|
+
param: "output-dir",
|
|
8
|
+
});
|
|
9
|
+
export const present = (path) => {
|
|
10
|
+
try {
|
|
11
|
+
lstatSync(path);
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
catch (error) {
|
|
15
|
+
if (error.code === "ENOENT")
|
|
16
|
+
return false;
|
|
17
|
+
throw error;
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
/** A file only this user reads. Without `overwrite` an existing file is never touched. */
|
|
21
|
+
export const savePrivately = async (path, bytes, overwrite) => {
|
|
22
|
+
mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
|
|
23
|
+
try {
|
|
24
|
+
await writeFileAtomic(path, bytes, { overwrite });
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
if (error.code === "EEXIST")
|
|
28
|
+
throw exists(path);
|
|
29
|
+
throw error;
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
export const refuseExisting = (path) => {
|
|
33
|
+
if (present(path))
|
|
34
|
+
throw exists(path);
|
|
35
|
+
};
|
|
36
|
+
/** A sender's file name as cli-core's downloads clean it, or `fallback` when nothing safe is left of it. */
|
|
37
|
+
export const safeName = (name, fallback) => plainName(name)?.slice(0, 200) || fallback;
|
|
38
|
+
/** `report.pdf`, then `report (2).pdf` for the second of the same name in one message. */
|
|
39
|
+
export const distinctNames = (names) => {
|
|
40
|
+
const used = new Map();
|
|
41
|
+
return names.map((name) => {
|
|
42
|
+
const seen = (used.get(name.toLowerCase()) ?? 0) + 1;
|
|
43
|
+
used.set(name.toLowerCase(), seen);
|
|
44
|
+
if (seen === 1)
|
|
45
|
+
return name;
|
|
46
|
+
const extension = extname(name);
|
|
47
|
+
return `${name.slice(0, name.length - extension.length)} (${seen})${extension}`;
|
|
48
|
+
});
|
|
49
|
+
};
|
|
50
|
+
//# sourceMappingURL=save.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"save.js","sourceRoot":"","sources":["../../src/mail/save.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAC9C,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAC5C,OAAO,EAAE,QAAQ,IAAI,SAAS,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AAEhF,MAAM,MAAM,GAAG,CAAC,IAAY,EAAE,EAAE,CAC9B,IAAI,QAAQ,CAAC,kBAAkB,EAAE,GAAG,IAAI,iDAAiD,EAAE;IACzF,MAAM,EAAE,iBAAiB;IACzB,KAAK,EAAE,YAAY;CACpB,CAAC,CAAA;AAEJ,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,IAAY,EAAW,EAAE;IAC/C,IAAI,CAAC;QACH,SAAS,CAAC,IAAI,CAAC,CAAA;QACf,OAAO,IAAI,CAAA;IACb,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAA;QACpE,MAAM,KAAK,CAAA;IACb,CAAC;AACH,CAAC,CAAA;AAED,0FAA0F;AAC1F,MAAM,CAAC,MAAM,aAAa,GAAG,KAAK,EAAE,IAAY,EAAE,KAAiB,EAAE,SAAkB,EAAiB,EAAE;IACxG,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;IAC1D,IAAI,CAAC;QACH,MAAM,eAAe,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,CAAC,CAAA;IACnD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ;YAAE,MAAM,MAAM,CAAC,IAAI,CAAC,CAAA;QAC1E,MAAM,KAAK,CAAA;IACb,CAAC;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,IAAY,EAAQ,EAAE;IACnD,IAAI,OAAO,CAAC,IAAI,CAAC;QAAE,MAAM,MAAM,CAAC,IAAI,CAAC,CAAA;AACvC,CAAC,CAAA;AAED,4GAA4G;AAC5G,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,IAAY,EAAE,QAAgB,EAAU,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,QAAQ,CAAA;AAE9G,0FAA0F;AAC1F,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,KAAwB,EAAY,EAAE;IAClE,MAAM,IAAI,GAAG,IAAI,GAAG,EAAkB,CAAA;IACtC,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACxB,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAA;QACpD,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,IAAI,CAAC,CAAA;QAClC,IAAI,IAAI,KAAK,CAAC;YAAE,OAAO,IAAI,CAAA;QAC3B,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;QAC/B,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,KAAK,IAAI,IAAI,SAAS,EAAE,CAAA;IACjF,CAAC,CAAC,CAAA;AACJ,CAAC,CAAA"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { type SendGuard, type SendKind } from "@wirecat/cli-core/sends";
|
|
2
|
+
import type { MailBackend } from "./backend.js";
|
|
3
|
+
import { type Draft, type Person } from "./compose.js";
|
|
4
|
+
import { type Mailbox } from "./organise.js";
|
|
5
|
+
/** What a send needs of the opened profile, beside the draft. */
|
|
6
|
+
export interface Sending {
|
|
7
|
+
mailbox: Mailbox;
|
|
8
|
+
backend: MailBackend;
|
|
9
|
+
guard: SendGuard;
|
|
10
|
+
profile: string;
|
|
11
|
+
env: NodeJS.ProcessEnv;
|
|
12
|
+
owner: ReadonlySet<string>;
|
|
13
|
+
/** The provider files what SMTP carried into Sent itself (Gmail). */
|
|
14
|
+
savesSent: boolean;
|
|
15
|
+
/** The folders a plain `sync` reads, so the sent message is stored as the next sync would store it. */
|
|
16
|
+
syncFolders: () => Promise<{
|
|
17
|
+
folders: string[];
|
|
18
|
+
mode: "imap" | "gmail";
|
|
19
|
+
}>;
|
|
20
|
+
warn: (message: string) => void;
|
|
21
|
+
/**
|
|
22
|
+
* Run by an agent over MCP, where `ask` would go ahead (WC-MCP-7), and the owner has not set
|
|
23
|
+
* `messages.send.others` in the config: mail to others is then refused, as `readonly` would.
|
|
24
|
+
*/
|
|
25
|
+
agentWithoutOthers?: boolean;
|
|
26
|
+
}
|
|
27
|
+
export declare const everyone: (draft: Pick<Draft, "to" | "cc" | "bcc">) => Person[];
|
|
28
|
+
export declare const othersOf: (draft: Pick<Draft, "to" | "cc" | "bcc">, owner: ReadonlySet<string>) => Person[];
|
|
29
|
+
/** The original of a reply or forward on the server: where it is, and its bytes. */
|
|
30
|
+
export declare const fetchOriginal: (mailbox: Mailbox, backend: MailBackend, ref: string, profile: string) => Promise<{
|
|
31
|
+
folder: string;
|
|
32
|
+
validity: string;
|
|
33
|
+
uid: number;
|
|
34
|
+
raw: Uint8Array<ArrayBufferLike>;
|
|
35
|
+
}>;
|
|
36
|
+
export type SentCopy = "server" | "appended" | "found" | "no-sent-folder" | "failed";
|
|
37
|
+
export interface Outgoing {
|
|
38
|
+
draft: Draft;
|
|
39
|
+
kind: Extract<SendKind, "message" | "forward">;
|
|
40
|
+
key: "messages.send" | "messages.forward";
|
|
41
|
+
operationId: string;
|
|
42
|
+
/** Set by the owner's `--operation-id`: a retry, so Sent is checked before anything goes again. */
|
|
43
|
+
retry: boolean;
|
|
44
|
+
original?: {
|
|
45
|
+
folder: string;
|
|
46
|
+
validity: string;
|
|
47
|
+
uid: number;
|
|
48
|
+
flag: string;
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
export interface Sent {
|
|
52
|
+
operationId: string;
|
|
53
|
+
messageId: string;
|
|
54
|
+
alreadySent: boolean;
|
|
55
|
+
accepted: number;
|
|
56
|
+
rejected: number;
|
|
57
|
+
sentCopy: SentCopy | null;
|
|
58
|
+
stored: boolean;
|
|
59
|
+
markedOriginal: boolean | null;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Asks and checks the guard, waits for the pace, submits once, then files the copy, marks the original and stores the
|
|
63
|
+
* message. Everything after the submission is best effort: the message is with people, and an error there would invite
|
|
64
|
+
* the owner to send it again.
|
|
65
|
+
*/
|
|
66
|
+
export declare const sendOut: (sending: Sending, outgoing: Outgoing) => Promise<Sent>;
|
|
67
|
+
//# sourceMappingURL=send.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"send.d.ts","sourceRoot":"","sources":["../../src/mail/send.ts"],"names":[],"mappings":"AAEA,OAAO,EAOL,KAAK,SAAS,EACd,KAAK,QAAQ,EACd,MAAM,yBAAyB,CAAA;AAGhC,OAAO,KAAK,EAAE,WAAW,EAAa,MAAM,cAAc,CAAA;AAC1D,OAAO,EAAS,KAAK,KAAK,EAAE,KAAK,MAAM,EAAE,MAAM,cAAc,CAAA;AAC7D,OAAO,EAAU,KAAK,OAAO,EAAa,MAAM,eAAe,CAAA;AAI/D,iEAAiE;AACjE,MAAM,WAAW,OAAO;IACtB,OAAO,EAAE,OAAO,CAAA;IAChB,OAAO,EAAE,WAAW,CAAA;IACpB,KAAK,EAAE,SAAS,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,GAAG,EAAE,MAAM,CAAC,UAAU,CAAA;IACtB,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;IAC1B,qEAAqE;IACrE,SAAS,EAAE,OAAO,CAAA;IAClB,uGAAuG;IACvG,WAAW,EAAE,MAAM,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,EAAE,CAAC;QAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC,CAAA;IACzE,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;IAC/B;;;OAGG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAA;CAC7B;AAED,eAAO,MAAM,QAAQ,UAAW,IAAI,CAAC,KAAK,EAAE,IAAI,GAAG,IAAI,GAAG,KAAK,CAAC,KAAG,MAAM,EAGxE,CAAA;AAED,eAAO,MAAM,QAAQ,UAAW,IAAI,CAAC,KAAK,EAAE,IAAI,GAAG,IAAI,GAAG,KAAK,CAAC,SAAS,WAAW,CAAC,MAAM,CAAC,KAAG,MAAM,EACvC,CAAA;AAE9D,oFAAoF;AACpF,eAAO,MAAM,aAAa,YAAmB,OAAO,WAAW,WAAW,OAAO,MAAM,WAAW,MAAM;;;;;EAavG,CAAA;AAYD,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,UAAU,GAAG,OAAO,GAAG,gBAAgB,GAAG,QAAQ,CAAA;AAiEpF,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,KAAK,CAAA;IACZ,IAAI,EAAE,OAAO,CAAC,QAAQ,EAAE,SAAS,GAAG,SAAS,CAAC,CAAA;IAC9C,GAAG,EAAE,eAAe,GAAG,kBAAkB,CAAA;IACzC,WAAW,EAAE,MAAM,CAAA;IACnB,mGAAmG;IACnG,KAAK,EAAE,OAAO,CAAA;IACd,QAAQ,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;CAC3E;AAED,MAAM,WAAW,IAAI;IACnB,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,OAAO,CAAA;IACpB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAA;IACzB,MAAM,EAAE,OAAO,CAAA;IACf,cAAc,EAAE,OAAO,GAAG,IAAI,CAAA;CAC/B;AAED;;;;GAIG;AACH,eAAO,MAAM,OAAO,YAAmB,OAAO,YAAY,QAAQ,KAAG,OAAO,CAAC,IAAI,CAqFhF,CAAA"}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { CliError, realSleep } from "@wirecat/cli-base";
|
|
2
|
+
import { storedMailRules, syncMail } from "@wirecat/cli-core/mail";
|
|
3
|
+
import { DEFAULT_PACE, guardedWrite, newOperationId, Pacer, pacePathFor, } from "@wirecat/cli-core/sends";
|
|
4
|
+
import { SEND_OTHERS_KEY } from "../config.js";
|
|
5
|
+
import { IDENTITY } from "../identity.js";
|
|
6
|
+
import { build } from "./compose.js";
|
|
7
|
+
import { locate, selectIds } from "./organise.js";
|
|
8
|
+
export const everyone = (draft) => {
|
|
9
|
+
const seen = new Set();
|
|
10
|
+
return [...draft.to, ...draft.cc, ...draft.bcc].filter(({ address }) => !seen.has(address) && !!seen.add(address));
|
|
11
|
+
};
|
|
12
|
+
export const othersOf = (draft, owner) => everyone(draft).filter(({ address }) => !owner.has(address));
|
|
13
|
+
/** The original of a reply or forward on the server: where it is, and its bytes. */
|
|
14
|
+
export const fetchOriginal = async (mailbox, backend, ref, profile) => {
|
|
15
|
+
const { ids } = await selectIds(mailbox, { refs: [ref] });
|
|
16
|
+
const { located } = await locate(mailbox, ids);
|
|
17
|
+
const place = located[0];
|
|
18
|
+
const item = place?.items[0];
|
|
19
|
+
if (!place || !item)
|
|
20
|
+
throw new CliError("not_found", `${ref} is not on the server any more, or not where the store last saw it; run \`${IDENTITY.command} ${profile} sync\``);
|
|
21
|
+
const [raw] = await backend.fetchRaw([{ uid: String(item.uid), folder: place.folder, receivedAt: "" }]);
|
|
22
|
+
if (!(raw instanceof Uint8Array))
|
|
23
|
+
throw new CliError("provider_error", "the server did not give the original message");
|
|
24
|
+
return { folder: place.folder, validity: place.validity, uid: item.uid, raw };
|
|
25
|
+
};
|
|
26
|
+
const sentFolder = async (mailbox) => (await mailbox.folders()).find(({ role }) => role === "sent")?.path;
|
|
27
|
+
/** Whether Sent already holds this Message-ID: a send the server answered too late, or Gmail's own copy. */
|
|
28
|
+
const inSent = async (mailbox, messageId) => {
|
|
29
|
+
const folder = await sentFolder(mailbox);
|
|
30
|
+
if (!folder)
|
|
31
|
+
return { found: false };
|
|
32
|
+
const { uids } = await mailbox.writes.locate(folder, { messageIds: [messageId] });
|
|
33
|
+
return { folder, found: uids.size > 0 };
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* After SMTP: a server that files sent mail itself is left alone; otherwise the copy goes to Sent unless Sent already
|
|
37
|
+
* has it, so a server that also files it keeps one copy.
|
|
38
|
+
*/
|
|
39
|
+
const fileCopy = async (sending, messageId, copy) => {
|
|
40
|
+
if (sending.savesSent)
|
|
41
|
+
return "server";
|
|
42
|
+
try {
|
|
43
|
+
const { folder, found } = await inSent(sending.mailbox, messageId);
|
|
44
|
+
if (!folder)
|
|
45
|
+
return "no-sent-folder";
|
|
46
|
+
if (found)
|
|
47
|
+
return "found";
|
|
48
|
+
await sending.mailbox.writes.append(folder, copy, ["\\Seen"]);
|
|
49
|
+
return "appended";
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
sending.warn("the message was sent, but its copy could not be put in Sent");
|
|
53
|
+
return "failed";
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
const SYNC_WINDOW_MS = 10 * 60 * 1000;
|
|
57
|
+
/** The sent copy into the store the way `sync` reads it, so it has the server's id and no second row ever appears. */
|
|
58
|
+
const storeSent = async (sending) => {
|
|
59
|
+
try {
|
|
60
|
+
const { folders, mode } = await sending.syncFolders();
|
|
61
|
+
const address = sending.mailbox.key.account;
|
|
62
|
+
const rules = await storedMailRules(sending.mailbox.store, { address });
|
|
63
|
+
const report = await syncMail(sending.backend, sending.mailbox.store, {
|
|
64
|
+
account: { address, mode, folders, rules },
|
|
65
|
+
since: new Date(Date.now() - SYNC_WINDOW_MS),
|
|
66
|
+
saveCoverage: false,
|
|
67
|
+
});
|
|
68
|
+
return report.saved + report.alreadyStored > 0;
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
sending.warn(`the message was sent; \`${IDENTITY.command} ${sending.profile} sync\` stores it`);
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
/** `\Answered` on a replied message, `$Forwarded` on a forwarded one, as mail clients mark them; best effort. */
|
|
76
|
+
const markOriginal = async (sending, original, flag) => {
|
|
77
|
+
const request = {
|
|
78
|
+
chatId: null,
|
|
79
|
+
kind: "account",
|
|
80
|
+
action: "message-flag",
|
|
81
|
+
key: "messages.update",
|
|
82
|
+
count: 1,
|
|
83
|
+
operationId: newOperationId(),
|
|
84
|
+
};
|
|
85
|
+
try {
|
|
86
|
+
await guardedWrite(sending.guard, request, () => sending.mailbox.writes.flag(original.folder, original.validity, [original.uid], { add: [flag] }));
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
sending.warn(`the message was sent; the original was not marked ${flag}`);
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
/**
|
|
95
|
+
* Asks and checks the guard, waits for the pace, submits once, then files the copy, marks the original and stores the
|
|
96
|
+
* message. Everything after the submission is best effort: the message is with people, and an error there would invite
|
|
97
|
+
* the owner to send it again.
|
|
98
|
+
*/
|
|
99
|
+
export const sendOut = async (sending, outgoing) => {
|
|
100
|
+
const { draft, operationId } = outgoing;
|
|
101
|
+
const recipients = everyone(draft);
|
|
102
|
+
const attempt = {
|
|
103
|
+
chatId: null,
|
|
104
|
+
kind: outgoing.kind,
|
|
105
|
+
key: outgoing.key,
|
|
106
|
+
count: recipients.length,
|
|
107
|
+
operationId,
|
|
108
|
+
sendId: operationId,
|
|
109
|
+
length: draft.text.length,
|
|
110
|
+
...(draft.files.length || draft.message
|
|
111
|
+
? {
|
|
112
|
+
attachments: [
|
|
113
|
+
...draft.files.map(({ bytes }) => ({ kind: "file", bytes })),
|
|
114
|
+
...(draft.message ? [{ kind: "file", bytes: draft.message.raw.byteLength }] : []),
|
|
115
|
+
],
|
|
116
|
+
}
|
|
117
|
+
: {}),
|
|
118
|
+
};
|
|
119
|
+
if (othersOf(draft, sending.owner).length > 0) {
|
|
120
|
+
// One more key for mail that reaches anyone but the owner: the owner can open self-sends and still be asked here.
|
|
121
|
+
const probe = { chatId: null, kind: "read", key: SEND_OTHERS_KEY };
|
|
122
|
+
try {
|
|
123
|
+
if (sending.agentWithoutOthers)
|
|
124
|
+
throw new CliError("permission_error", `over MCP, profile ${sending.profile} mails only its owner: permissions.${SEND_OTHERS_KEY} is readonly for an ` +
|
|
125
|
+
"agent until the owner sets it in the config; to let an agent mail others: " +
|
|
126
|
+
`${IDENTITY.command} ${sending.profile} config set permissions.${SEND_OTHERS_KEY} allow`, { permission: SEND_OTHERS_KEY });
|
|
127
|
+
await sending.guard.ask?.(probe);
|
|
128
|
+
sending.guard.check(probe, { reserve: false });
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
sending.guard.record({ ...attempt, outcome: "refused", errorCode: error.code ?? "unknown" });
|
|
132
|
+
throw error;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
if (outgoing.retry && (await inSent(sending.mailbox, draft.messageId)).found)
|
|
136
|
+
return {
|
|
137
|
+
operationId,
|
|
138
|
+
messageId: draft.messageId,
|
|
139
|
+
alreadySent: true,
|
|
140
|
+
accepted: 0,
|
|
141
|
+
rejected: 0,
|
|
142
|
+
sentCopy: "found",
|
|
143
|
+
stored: false,
|
|
144
|
+
markedOriginal: null,
|
|
145
|
+
};
|
|
146
|
+
const submit = sending.backend.submit;
|
|
147
|
+
if (!submit)
|
|
148
|
+
throw new CliError("configuration_error", `profile ${sending.profile} names no submission server; set smtp_host, smtp_port and smtp_security with ` +
|
|
149
|
+
`\`${IDENTITY.command} ${sending.profile} config set\``, { sent: false });
|
|
150
|
+
const { raw, copy } = await build(draft);
|
|
151
|
+
const pacer = new Pacer(pacePathFor(IDENTITY, sending.profile, sending.env), DEFAULT_PACE);
|
|
152
|
+
const submitted = await guardedWrite(sending.guard, attempt, () => submit.send({ from: draft.from.address, recipients: recipients.map(({ address }) => address), raw }), () => ({}), async () => {
|
|
153
|
+
const at = await pacer.reserve();
|
|
154
|
+
if (at > Date.now())
|
|
155
|
+
await realSleep(at - Date.now());
|
|
156
|
+
});
|
|
157
|
+
const sentCopy = await fileCopy(sending, draft.messageId, copy);
|
|
158
|
+
const markedOriginal = outgoing.original
|
|
159
|
+
? await markOriginal(sending, outgoing.original, outgoing.original.flag)
|
|
160
|
+
: null;
|
|
161
|
+
const stored = await storeSent(sending);
|
|
162
|
+
return {
|
|
163
|
+
operationId,
|
|
164
|
+
messageId: draft.messageId,
|
|
165
|
+
alreadySent: false,
|
|
166
|
+
accepted: submitted.accepted.length,
|
|
167
|
+
rejected: submitted.rejected.length,
|
|
168
|
+
sentCopy,
|
|
169
|
+
stored,
|
|
170
|
+
markedOriginal,
|
|
171
|
+
};
|
|
172
|
+
};
|
|
173
|
+
//# sourceMappingURL=send.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"send.js","sourceRoot":"","sources":["../../src/mail/send.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { MailCredential, MailEndpoint, MailSubmit, RunBounds } from "./backend.js";
|
|
2
|
+
/** SMTP submission with the profile's login and its app password or OAuth token, one connection per message. */
|
|
3
|
+
export declare const smtpSubmit: (endpoint: Pick<MailEndpoint, "host" | "port" | "security" | "login">, credential: MailCredential, bounds?: RunBounds) => MailSubmit;
|
|
4
|
+
//# sourceMappingURL=smtp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"smtp.d.ts","sourceRoot":"","sources":["../../src/mail/smtp.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAa,UAAU,EAAE,SAAS,EAAa,MAAM,cAAc,CAAA;AAgF7G,gHAAgH;AAChH,eAAO,MAAM,UAAU,aACX,IAAI,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,UAAU,GAAG,OAAO,CAAC,cACxD,cAAc,WAClB,SAAS,KAChB,UA6ED,CAAA"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { CliError } from "@wirecat/cli-base";
|
|
2
|
+
import SMTPConnection from "nodemailer/lib/smtp-connection";
|
|
3
|
+
import XOAuth2 from "nodemailer/lib/xoauth2";
|
|
4
|
+
/** The server's reply can quote addresses, so only its codes reach the caller. */
|
|
5
|
+
const codes = (error) => ({
|
|
6
|
+
...(error.code && /^[A-Z0-9_]{1,40}$/.test(error.code) ? { cause_code: error.code } : {}),
|
|
7
|
+
...(error.responseCode ? { smtp_code: error.responseCode } : {}),
|
|
8
|
+
});
|
|
9
|
+
const loginRefused = (error) => error.code === "EAUTH" || error.responseCode === 535;
|
|
10
|
+
/** A token refused after a refresh: on Microsoft 365 most often SMTP AUTH turned off for the mailbox. */
|
|
11
|
+
const tokenRefused = (error, credential) => credential.provider === "microsoft"
|
|
12
|
+
? new CliError("authentication_error", "Microsoft refused the OAuth login for sending; reading still works. On a Microsoft 365 mailbox an admin " +
|
|
13
|
+
'has to turn on "Authenticated SMTP" for it (security defaults turn it off for the whole organisation)', { reason: "mail.smtp-auth-disabled", sent: false, ...codes(error) })
|
|
14
|
+
: new CliError("authentication_error", `the submission server refused the OAuth login; sign in again${credential.signInCommand ? `: ${credential.signInCommand}` : ""}`, { reason: "mail.oauth-refused", sent: false, ...codes(error) });
|
|
15
|
+
/** A failure before the message left: nothing was sent, so the owner may simply run the command again. */
|
|
16
|
+
const beforeSending = (error) => {
|
|
17
|
+
if (loginRefused(error))
|
|
18
|
+
return new CliError("authentication_error", "the submission server refused the login; check that the app password allows sending (SMTP) for this mailbox", { reason: "mail.smtp-login-refused", sent: false, ...codes(error) });
|
|
19
|
+
if (error.code === "ETIMEDOUT")
|
|
20
|
+
return new CliError("timeout", "the submission server did not answer in time; nothing was sent", {
|
|
21
|
+
sent: false,
|
|
22
|
+
retryable: true,
|
|
23
|
+
...codes(error),
|
|
24
|
+
});
|
|
25
|
+
if (["ECONNECTION", "ESOCKET", "EDNS", "ETLS"].includes(error.code ?? ""))
|
|
26
|
+
return new CliError("network_error", "cannot reach the submission server; nothing was sent", {
|
|
27
|
+
sent: false,
|
|
28
|
+
retryable: true,
|
|
29
|
+
...codes(error),
|
|
30
|
+
});
|
|
31
|
+
return new CliError("provider_error", "the submission server refused the connection; nothing was sent", {
|
|
32
|
+
sent: false,
|
|
33
|
+
...codes(error),
|
|
34
|
+
});
|
|
35
|
+
};
|
|
36
|
+
/** The server answered the envelope or the message with an error code: it took nothing. */
|
|
37
|
+
const refused = (error) => {
|
|
38
|
+
const temporary = error.responseCode !== undefined && error.responseCode >= 400 && error.responseCode < 500;
|
|
39
|
+
return new CliError(temporary ? "provider_unavailable" : "provider_error", temporary
|
|
40
|
+
? "the submission server cannot take the message now; nothing was sent, try again later"
|
|
41
|
+
: "the submission server refused the message; nothing was sent", { sent: false, ...(temporary ? { retryable: true } : {}), ...codes(error) });
|
|
42
|
+
};
|
|
43
|
+
/** One step's callback, or the connection's 'error' event, which nodemailer raises instead when the socket fails. */
|
|
44
|
+
const settle = (connection, start) => new Promise((resolve, reject) => {
|
|
45
|
+
const failed = (error) => reject(error);
|
|
46
|
+
connection.once("error", failed);
|
|
47
|
+
start((error, value) => {
|
|
48
|
+
connection.off("error", failed);
|
|
49
|
+
if (error)
|
|
50
|
+
reject(error);
|
|
51
|
+
else
|
|
52
|
+
resolve(value);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
/** SMTP submission with the profile's login and its app password or OAuth token, one connection per message. */
|
|
56
|
+
export const smtpSubmit = (endpoint, credential, bounds = {}) => ({
|
|
57
|
+
send: async ({ from, recipients, raw }) => {
|
|
58
|
+
const timeout = Math.max(1_000, Math.min(60_000, bounds.timeLeftMs?.() ?? 60_000));
|
|
59
|
+
const open = async (login) => {
|
|
60
|
+
const connection = new SMTPConnection({
|
|
61
|
+
host: endpoint.host,
|
|
62
|
+
port: endpoint.port,
|
|
63
|
+
secure: endpoint.security === "tls",
|
|
64
|
+
requireTLS: endpoint.security === "starttls",
|
|
65
|
+
ignoreTLS: endpoint.security === "plain",
|
|
66
|
+
connectionTimeout: 15_000,
|
|
67
|
+
greetingTimeout: 15_000,
|
|
68
|
+
socketTimeout: timeout,
|
|
69
|
+
logger: false,
|
|
70
|
+
});
|
|
71
|
+
// An 'error' event with no listener would end the process; each step's callback already rejects.
|
|
72
|
+
connection.on("error", () => { });
|
|
73
|
+
const abort = () => connection.close();
|
|
74
|
+
bounds.signal?.addEventListener("abort", abort, { once: true });
|
|
75
|
+
const done = () => {
|
|
76
|
+
bounds.signal?.removeEventListener("abort", abort);
|
|
77
|
+
try {
|
|
78
|
+
connection.quit();
|
|
79
|
+
}
|
|
80
|
+
catch { }
|
|
81
|
+
};
|
|
82
|
+
try {
|
|
83
|
+
await settle(connection, (finish) => connection.connect((error) => finish(error ?? null)));
|
|
84
|
+
await settle(connection, (finish) => connection.login("pass" in login
|
|
85
|
+
? { user: endpoint.login, pass: login.pass }
|
|
86
|
+
: { user: endpoint.login, oauth2: new XOAuth2({ user: endpoint.login, accessToken: login.accessToken }) }, finish));
|
|
87
|
+
return { connection, done };
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
done();
|
|
91
|
+
throw error;
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
let opened;
|
|
95
|
+
try {
|
|
96
|
+
try {
|
|
97
|
+
opened = await open(await credential.login());
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
if (credential.kind !== "oauth" || !loginRefused(error))
|
|
101
|
+
throw error;
|
|
102
|
+
try {
|
|
103
|
+
opened = await open(await credential.login({ refresh: true }));
|
|
104
|
+
}
|
|
105
|
+
catch (again) {
|
|
106
|
+
if (loginRefused(again))
|
|
107
|
+
throw tokenRefused(again, credential);
|
|
108
|
+
throw again;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
throw error instanceof CliError ? error : beforeSending(error);
|
|
114
|
+
}
|
|
115
|
+
const { connection, done } = opened;
|
|
116
|
+
try {
|
|
117
|
+
const info = await settle(connection, (finish) => connection.send({ from, to: [...recipients] }, Buffer.from(raw), finish));
|
|
118
|
+
return { accepted: info.accepted, rejected: info.rejected };
|
|
119
|
+
}
|
|
120
|
+
catch (raw) {
|
|
121
|
+
const error = raw;
|
|
122
|
+
// The envelope is answered before the body goes; a message refused with a code was not taken either.
|
|
123
|
+
if (error.code === "EENVELOPE" || (error.code === "EMESSAGE" && error.responseCode))
|
|
124
|
+
throw refused(error);
|
|
125
|
+
throw new CliError("outcome_unknown", "the line to the submission server broke while the message was going; it may have been sent — " +
|
|
126
|
+
"look in Sent before sending it again", { retryable: false, ...codes(error) });
|
|
127
|
+
}
|
|
128
|
+
finally {
|
|
129
|
+
done();
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
//# sourceMappingURL=smtp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"smtp.js","sourceRoot":"","sources":["../../src/mail/smtp.ts"],"names":[],"mappings":"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"}
|
package/dist/oauth.d.ts
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { type KeyringStore } from "@wirecat/cli-base";
|
|
3
|
+
import { type OAuthClient, type TokenKeeper, type TokenStorage } from "@wirecat/cli-core/oauth";
|
|
4
|
+
import type { Mailbox } from "./config.js";
|
|
5
|
+
import type { MailCredential } from "./mail/backend.js";
|
|
6
|
+
export type OAuthKind = "microsoft" | "google";
|
|
7
|
+
/**
|
|
8
|
+
* WireCat's Microsoft app: a public client for any Entra tenant and personal accounts. Empty until WireCat registers
|
|
9
|
+
* it (docs/oauth-microsoft.md); until then a sign-in needs `microsoft_client_id` in the config.
|
|
10
|
+
*/
|
|
11
|
+
export declare const WIRECAT_MICROSOFT_CLIENT_ID = "";
|
|
12
|
+
export declare const OAUTH_GUIDE = "https://github.com/WireCatLabs/mail-cli/blob/main/docs/oauth-microsoft.md";
|
|
13
|
+
export declare const MICROSOFT_IMAP_SCOPE = "https://outlook.office.com/IMAP.AccessAsUser.All";
|
|
14
|
+
export declare const MICROSOFT_SMTP_SCOPE = "https://outlook.office.com/SMTP.Send";
|
|
15
|
+
/** IMAP and SMTP are one resource, so one token covers both; offline_access brings the refresh token. */
|
|
16
|
+
export declare const MICROSOFT_SCOPES: readonly ["offline_access", "https://outlook.office.com/IMAP.AccessAsUser.All", "https://outlook.office.com/SMTP.Send"];
|
|
17
|
+
export declare const GOOGLE_GUIDE = "https://github.com/WireCatLabs/mail-cli/blob/main/docs/oauth-google.md";
|
|
18
|
+
/** The only scope Gmail gives IMAP and SMTP: https://developers.google.com/workspace/gmail/imap/xoauth2-protocol */
|
|
19
|
+
export declare const GOOGLE_MAIL_SCOPE = "https://mail.google.com/";
|
|
20
|
+
export declare const GOOGLE_SCOPES: readonly ["openid", "email", "https://mail.google.com/"];
|
|
21
|
+
/** What each scope lets mail do, shown before the browser opens. */
|
|
22
|
+
export declare const SCOPE_WORDS: Record<string, string>;
|
|
23
|
+
export declare const OAUTH_NAMES: Record<OAuthKind, string>;
|
|
24
|
+
export declare const scopesOf: (kind: OAuthKind) => readonly string[];
|
|
25
|
+
/** The scope without which a profile cannot send. */
|
|
26
|
+
export declare const sendScopeOf: (kind: OAuthKind) => "https://mail.google.com/" | "https://outlook.office.com/SMTP.Send";
|
|
27
|
+
/** The owner's Desktop client: `--client-file` (private to the owner), else MAIL_GOOGLE_CLIENT_ID; no bundled one. */
|
|
28
|
+
export declare const googleClient: (env: NodeJS.ProcessEnv, file?: string, platform?: NodeJS.Platform) => OAuthClient;
|
|
29
|
+
/** The address Google signed in, from OpenID userinfo; the token goes in a header, so no failure prints it. */
|
|
30
|
+
export declare const googleAddress: (accessToken: string, fetcher: typeof fetch, signal?: AbortSignal) => Promise<string>;
|
|
31
|
+
/** The owner's own Microsoft app when the config names one, else WireCat's; only the owner sets the key (OWNER_ONLY). */
|
|
32
|
+
export declare const microsoftClient: (mailbox: Mailbox) => {
|
|
33
|
+
client: OAuthClient;
|
|
34
|
+
source: "wirecat" | "own";
|
|
35
|
+
};
|
|
36
|
+
export type CredentialStorage = "keyring" | "file";
|
|
37
|
+
export interface OAuthOptions {
|
|
38
|
+
env: NodeJS.ProcessEnv;
|
|
39
|
+
profile: string;
|
|
40
|
+
kind: OAuthKind;
|
|
41
|
+
keyring?: KeyringStore | undefined;
|
|
42
|
+
/** Where a new sign-in goes; a saved one is read and refreshed where it is. */
|
|
43
|
+
storage?: CredentialStorage | undefined;
|
|
44
|
+
}
|
|
45
|
+
/** The entry `oauth:<provider>:<profile>` beside the profile's app password, under the same options (WC-SECR-24). */
|
|
46
|
+
export declare const oauthStorage: ({ env, profile, kind, keyring, storage }: OAuthOptions) => TokenStorage;
|
|
47
|
+
export declare const signInWords: (profile: string) => string;
|
|
48
|
+
export interface KeeperOptions extends OAuthOptions {
|
|
49
|
+
client: OAuthClient;
|
|
50
|
+
/** Sent as `login_hint`, so the provider offers the right account first. */
|
|
51
|
+
address?: string | undefined;
|
|
52
|
+
fetch?: typeof fetch | undefined;
|
|
53
|
+
signal?: AbortSignal | undefined;
|
|
54
|
+
}
|
|
55
|
+
/** One profile's sign-in, refreshed under a lock every mail process shares; a refresh uses the app it signed in with. */
|
|
56
|
+
export declare const oauthKeeper: (options: KeeperOptions) => TokenKeeper;
|
|
57
|
+
export declare const oauthCredential: (keeper: TokenKeeper, kind: OAuthKind, profile: string) => MailCredential;
|
|
58
|
+
/** A token just received at sign-in, before anything is saved: a refusal fails the sign-in, nothing refreshes. */
|
|
59
|
+
export declare const tokenCredential: (accessToken: string, kind: OAuthKind) => MailCredential;
|
|
60
|
+
/**
|
|
61
|
+
* What `doctor` knows of each sign-in without opening the keyring: when it happened, with which app and scopes. Never
|
|
62
|
+
* a token.
|
|
63
|
+
*/
|
|
64
|
+
export interface SignInRecord {
|
|
65
|
+
provider: OAuthKind;
|
|
66
|
+
client: "wirecat" | "own";
|
|
67
|
+
signed_in_at: string;
|
|
68
|
+
scopes: string[];
|
|
69
|
+
}
|
|
70
|
+
export declare const signInRecords: (env: NodeJS.ProcessEnv) => Record<string, SignInRecord>;
|
|
71
|
+
export declare const recordSignIn: (env: NodeJS.ProcessEnv, profile: string, record: SignInRecord | undefined) => Promise<void>;
|
|
72
|
+
/** The system browser; the sign-in link is printed too, so a failure here only means opening it by hand. */
|
|
73
|
+
export declare const systemBrowser: (url: string, platform?: NodeJS.Platform, start?: typeof spawn) => Promise<void>;
|
|
74
|
+
//# sourceMappingURL=oauth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../src/oauth.ts"],"names":[],"mappings":"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"}
|