proton-mail-bridge-client 2.8.6 → 2.9.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/dist/index.js CHANGED
@@ -8,8 +8,9 @@ import { isAbsolute, join, resolve as pathResolve, sep as pathSep } from "node:p
8
8
  import { fileURLToPath } from "node:url";
9
9
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
10
10
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
11
- import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, ListResourcesRequestSchema, McpError, ReadResourceRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
11
+ import { CallToolRequestSchema, ErrorCode, GetPromptRequestSchema, ListPromptsRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, McpError, ReadResourceRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
12
12
  import { isMainModule } from "./is-main.js";
13
+ import { findMailPrompt, MAIL_PROMPTS } from "./utils/mail-prompts.js";
13
14
  import { AnalyticsService } from "./services/analytics-service.js";
14
15
  import { applyBodyEdits, draftSyncFingerprint } from "./services/draft-store-service.js";
15
16
  import { BULK_ITEM_TIMEOUT_MS, describeImapError, isLikelyAuthenticationError, isLikelyConnectionError, isLikelyTlsMismatchError, UID_VALIDITY_MISMATCH_ERROR } from "./services/simple-imap-service.js";
@@ -3641,10 +3642,31 @@ function validatePortEnv(name) {
3641
3642
  throw new Error(`${name} must be an integer between 1 and 65535, got: ${raw}`);
3642
3643
  }
3643
3644
  }
3644
- function parseAllowedActionsEnv(name) {
3645
+ // One switch for the safety flags. A mode only sets the starting point: any of the individual variables that is set
3646
+ // explicitly still wins, so a mode never takes a setting away that someone chose on purpose.
3647
+ const SAFETY_MODES = {
3648
+ // Browse and search only: nothing is written, nothing is sent.
3649
+ "read-only": { readOnly: true },
3650
+ // Drafts and flags; no sending, and no moving, archiving or deleting.
3651
+ drafts: { allowSend: false, allowedActions: ["mark_read", "mark_unread", "star", "unstar"] },
3652
+ // Everything except permanent deletion, and every send or delete asks for confirmed:true.
3653
+ assisted: { confirmDestructive: true, allowedActions: ALL_EMAIL_ACTIONS.filter((action) => action !== "delete") },
3654
+ full: {},
3655
+ };
3656
+ function parseSafetyModeEnv(name) {
3657
+ const raw = process.env[name]?.trim().toLowerCase();
3658
+ if (!raw) {
3659
+ return undefined;
3660
+ }
3661
+ if (Object.hasOwn(SAFETY_MODES, raw)) {
3662
+ return raw;
3663
+ }
3664
+ throw new Error(`${name} must be one of: ${Object.keys(SAFETY_MODES).join(", ")} (got "${raw}").`);
3665
+ }
3666
+ function parseAllowedActionsEnv(name, fallback = ALL_EMAIL_ACTIONS) {
3645
3667
  const configured = parseListValues(process.env[name]);
3646
3668
  if (configured.length === 0) {
3647
- return [...ALL_EMAIL_ACTIONS];
3669
+ return [...fallback];
3648
3670
  }
3649
3671
  const allowed = configured.filter((value) => ALL_EMAIL_ACTIONS.includes(value));
3650
3672
  if (allowed.length === 0) {
@@ -3756,14 +3778,16 @@ export function buildConfigFromEnv() {
3756
3778
  validatePortEnv("PROTONMAIL_IMAP_PORT");
3757
3779
  const imapPort = parseIntegerEnv("PROTONMAIL_IMAP_PORT", 1143, 1, 65_535);
3758
3780
  const debug = parseBooleanEnv("DEBUG", false);
3759
- const readOnly = parseBooleanEnv("PROTONMAIL_READ_ONLY", false);
3760
- const allowSend = parseBooleanEnv("PROTONMAIL_ALLOW_SEND", !readOnly);
3781
+ const mode = parseSafetyModeEnv("PROTONMAIL_MODE");
3782
+ const preset = mode ? SAFETY_MODES[mode] : {};
3783
+ const readOnly = parseBooleanEnv("PROTONMAIL_READ_ONLY", preset.readOnly ?? false);
3784
+ const allowSend = parseBooleanEnv("PROTONMAIL_ALLOW_SEND", preset.allowSend ?? !readOnly);
3761
3785
  const allowRemoteDraftSync = parseBooleanEnv("PROTONMAIL_ALLOW_REMOTE_DRAFT_SYNC", !readOnly);
3762
3786
  const autoSync = parseBooleanEnv("PROTONMAIL_AUTO_SYNC", true);
3763
3787
  const syncInterval = parseIntegerEnv("PROTONMAIL_SYNC_INTERVAL_MINUTES", 5, 1, 24 * 60);
3764
3788
  const idleWatchEnabled = parseBooleanEnv("PROTONMAIL_IDLE_WATCH", autoSync);
3765
3789
  const idleMaxSeconds = parseIntegerEnv("PROTONMAIL_IDLE_MAX_SECONDS", 30, 5, 300);
3766
- const confirmDestructive = parseBooleanEnv("PROTONMAIL_CONFIRM_DESTRUCTIVE", false);
3790
+ const confirmDestructive = parseBooleanEnv("PROTONMAIL_CONFIRM_DESTRUCTIVE", preset.confirmDestructive ?? false);
3767
3791
  const allowEmptyFolder = parseBooleanEnv("PROTONMAIL_ALLOW_EMPTY_FOLDER", false);
3768
3792
  const restrictOutboundToSelf = parseBooleanEnv("PROTONMAIL_RESTRICT_OUTBOUND_TO_SELF", false);
3769
3793
  const allowFileDownloadDir = process.env.PROTONMAIL_ALLOW_FILE_DOWNLOAD_DIR?.trim() || undefined;
@@ -3808,10 +3832,11 @@ export function buildConfigFromEnv() {
3808
3832
  syncInterval,
3809
3833
  accounts,
3810
3834
  runtime: {
3835
+ ...(mode ? { mode } : {}),
3811
3836
  readOnly,
3812
3837
  allowSend,
3813
3838
  allowRemoteDraftSync,
3814
- allowedActions: parseAllowedActionsEnv("PROTONMAIL_ALLOWED_ACTIONS"),
3839
+ allowedActions: parseAllowedActionsEnv("PROTONMAIL_ALLOWED_ACTIONS", preset.allowedActions),
3815
3840
  startupSync: parseBooleanEnv("PROTONMAIL_STARTUP_SYNC", autoSync),
3816
3841
  // Comma-separated; Sent is included by default so pendingOn/digest/follow-up
3817
3842
  // candidates don't misreport threads that were already answered — IDLE still
@@ -4033,9 +4058,34 @@ export function createServer(config, options = {}) {
4033
4058
  capabilities: {
4034
4059
  tools: {},
4035
4060
  resources: {},
4061
+ prompts: {},
4036
4062
  },
4037
4063
  });
4038
4064
  server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: listedTools() }));
4065
+ server.setRequestHandler(ListPromptsRequestSchema, async () => ({
4066
+ prompts: MAIL_PROMPTS.map(({ name, title, description, arguments: promptArguments }) => ({
4067
+ name,
4068
+ title,
4069
+ description,
4070
+ ...(promptArguments ? { arguments: promptArguments } : {}),
4071
+ })),
4072
+ }));
4073
+ server.setRequestHandler(GetPromptRequestSchema, async (request) => {
4074
+ const prompt = findMailPrompt(request.params.name);
4075
+ if (!prompt) {
4076
+ throw new McpError(ErrorCode.InvalidParams, `Unknown prompt "${request.params.name}". Available: ${MAIL_PROMPTS.map((entry) => entry.name).join(", ")}.`);
4077
+ }
4078
+ const provided = request.params.arguments ?? {};
4079
+ for (const argument of prompt.arguments ?? []) {
4080
+ if (argument.required && !String(provided[argument.name] ?? "").trim()) {
4081
+ throw new McpError(ErrorCode.InvalidParams, `Prompt "${prompt.name}" needs the argument "${argument.name}": ${argument.description}`);
4082
+ }
4083
+ }
4084
+ return {
4085
+ description: prompt.description,
4086
+ messages: [{ role: "user", content: { type: "text", text: prompt.render(provided) } }],
4087
+ };
4088
+ });
4039
4089
  server.setRequestHandler(ListResourcesRequestSchema, async (request) => {
4040
4090
  const cursor = request.params?.cursor ? Number.parseInt(request.params.cursor, 10) : 0;
4041
4091
  // Fan out across every configured account and prefix non-primary ids exactly as the