proton-mail-bridge-client 2.0.3 → 2.0.5
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.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +45 -14
- package/dist/index.js.map +1 -1
- package/dist/services/delivery-queue-service.d.ts.map +1 -1
- package/dist/services/delivery-queue-service.js +53 -7
- package/dist/services/delivery-queue-service.js.map +1 -1
- package/dist/services/draft-store-service.d.ts.map +1 -1
- package/dist/services/draft-store-service.js +12 -0
- package/dist/services/draft-store-service.js.map +1 -1
- package/dist/services/local-index-service.d.ts +2 -0
- package/dist/services/local-index-service.d.ts.map +1 -1
- package/dist/services/local-index-service.js +359 -12
- package/dist/services/local-index-service.js.map +1 -1
- package/dist/services/simple-imap-service.d.ts +8 -0
- package/dist/services/simple-imap-service.d.ts.map +1 -1
- package/dist/services/simple-imap-service.js +193 -38
- package/dist/services/simple-imap-service.js.map +1 -1
- package/dist/services/smtp-service.d.ts.map +1 -1
- package/dist/services/smtp-service.js +9 -0
- package/dist/services/smtp-service.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -26,6 +26,8 @@ export declare function getReplyRecipients(detail: EmailDetail, ownerEmail: stri
|
|
|
26
26
|
to: string[];
|
|
27
27
|
cc: string[];
|
|
28
28
|
};
|
|
29
|
+
export declare function getBulkMaxBatchSize(args: Record<string, unknown>): number;
|
|
30
|
+
export declare function ensureBulkBatchSize(uidsLength: number, max: number): void;
|
|
29
31
|
export declare function buildConfigFromEnv(): ProtonMailConfig;
|
|
30
32
|
export declare function createServer(config: ProtonMailConfig, options?: {
|
|
31
33
|
startBackgroundSync?: boolean;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AASA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAYnE,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAC;AAC9E,OAAO,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;AAC5E,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EAA2H,iBAAiB,EAA+B,MAAM,mCAAmC,CAAC;AAC5N,OAAO,EAAkB,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACzE,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAE7D,OAAO,KAAK,EAUV,WAAW,EAEX,gBAAgB,EAEjB,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AASA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAYnE,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAC;AAC9E,OAAO,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;AAC5E,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EAA2H,iBAAiB,EAA+B,MAAM,mCAAmC,CAAC;AAC5N,OAAO,EAAkB,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACzE,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAE7D,OAAO,KAAK,EAUV,WAAW,EAEX,gBAAgB,EAEjB,MAAM,kBAAkB,CAAC;AA6qD1B,eAAO,MAAM,eAAe,aAyB1B,CAAC;AAgGH,wBAAsB,SAAS,CAAC,CAAC,EAC/B,YAAY,EAAE,YAAY,EAC1B,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAC1B,OAAO,CAAC,CAAC,CAAC,CAwBZ;AAmED,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAK3G;AAKD,wBAAgB,0BAA0B,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAI1G;AASD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAa9E;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,WAAW,GAAG;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,CAS7F;AA4KD,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,WAAW,EACnB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,OAAO,GAChB;IAAE,EAAE,EAAE,MAAM,EAAE,CAAC;IAAC,EAAE,EAAE,MAAM,EAAE,CAAA;CAAE,CAyBhC;AAoiBD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAEzE;AAED,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAOzE;AAyQD,wBAAgB,kBAAkB,IAAI,gBAAgB,CAkGrD;AAED,wBAAgB,YAAY,CAC1B,MAAM,EAAE,gBAAgB,EACxB,OAAO,GAAE;IACP,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC1B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgjGP;AAED,wBAAsB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAmE1C"}
|
package/dist/index.js
CHANGED
|
@@ -1131,6 +1131,7 @@ const TOOLS = [
|
|
|
1131
1131
|
description: "Preview the impact without mutating the mailbox.",
|
|
1132
1132
|
default: false,
|
|
1133
1133
|
},
|
|
1134
|
+
maxBatchSize: { type: "number", description: "Maximum number of messages to process. Defaults to 500. Use to prevent runaway operations." },
|
|
1134
1135
|
},
|
|
1135
1136
|
required: ["emailIds", "action"],
|
|
1136
1137
|
},
|
|
@@ -1171,6 +1172,7 @@ const TOOLS = [
|
|
|
1171
1172
|
description: "Refresh the local mailbox index from IMAP before resolving the thread.",
|
|
1172
1173
|
default: false,
|
|
1173
1174
|
},
|
|
1175
|
+
maxBatchSize: { type: "number", description: "Maximum number of messages to process. Defaults to 500. Use to prevent runaway operations." },
|
|
1174
1176
|
},
|
|
1175
1177
|
required: ["threadId", "action"],
|
|
1176
1178
|
},
|
|
@@ -2498,10 +2500,10 @@ async function previewEmailAction(imapService, emailId, action, targetFolder) {
|
|
|
2498
2500
|
async function verifySentCopy(imapService, messageId) {
|
|
2499
2501
|
return imapService.sentCopyVerify(messageId, "Sent", 8_000);
|
|
2500
2502
|
}
|
|
2501
|
-
function getBulkMaxBatchSize(args) {
|
|
2503
|
+
export function getBulkMaxBatchSize(args) {
|
|
2502
2504
|
return typeof args.maxBatchSize === "number" ? Math.min(args.maxBatchSize, 2000) : 500;
|
|
2503
2505
|
}
|
|
2504
|
-
function ensureBulkBatchSize(uidsLength, max) {
|
|
2506
|
+
export function ensureBulkBatchSize(uidsLength, max) {
|
|
2505
2507
|
if (uidsLength > max) {
|
|
2506
2508
|
throw new McpError(ErrorCode.InvalidParams, "Batch size " + uidsLength + " exceeds limit " + max + ". Use match criteria to narrow the scope, or increase maxBatchSize.");
|
|
2507
2509
|
}
|
|
@@ -3850,6 +3852,15 @@ export function createServer(config, options = {}) {
|
|
|
3850
3852
|
// after an ambiguous response) sailed past the status check above
|
|
3851
3853
|
// and enqueued a second, independent delivery-queue record. Both
|
|
3852
3854
|
// fire independently later, delivering the same email twice.
|
|
3855
|
+
//
|
|
3856
|
+
// Found live: this list()-then-check was itself a non-atomic
|
|
3857
|
+
// TOCTOU race — two concurrent schedule_draft calls could both
|
|
3858
|
+
// observe no pending record here and both enqueue. The real
|
|
3859
|
+
// enforcement now lives inside deliveryQueueService.enqueue()
|
|
3860
|
+
// itself, under its lock, which is what actually prevents the
|
|
3861
|
+
// duplicate. This external check is kept only as an optional
|
|
3862
|
+
// early-exit optimization to avoid a wasted round-trip to the lock
|
|
3863
|
+
// in the common non-racing case.
|
|
3853
3864
|
const alreadyPendingScheduled = (await deliveryQueueService.list()).find((record) => record.sourceDraftId === draft.id && record.status === "pending");
|
|
3854
3865
|
if (alreadyPendingScheduled) {
|
|
3855
3866
|
throw new McpError(ErrorCode.InvalidParams, `This draft already has a pending scheduled send (id ${alreadyPendingScheduled.id}, sendAt ${alreadyPendingScheduled.sendAt}). Scheduling it again would deliver it twice. Cancel the existing one with cancel_send first if you want a different sendAt.`);
|
|
@@ -4121,15 +4132,23 @@ export function createServer(config, options = {}) {
|
|
|
4121
4132
|
// mailbox each time.
|
|
4122
4133
|
const currentUidValidity = emailIds ? await imapService.getMailboxUidValidity(folder) : undefined;
|
|
4123
4134
|
const notFoundEmailIds = getBulkNotFoundEmailIds(emailIds, folder, currentUidValidity);
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
ensureBulkBatchSize(preview.total, max);
|
|
4135
|
+
// Resolve the match/emailIds set exactly once and reuse it for both
|
|
4136
|
+
// the preview and the real run — see resolveUidsForBulkOp's
|
|
4137
|
+
// comment for why re-resolving `match` a second time (the old
|
|
4138
|
+
// dry-run-then-real-run pattern) could silently exceed maxBatchSize.
|
|
4139
|
+
// Also excludes any id whose embedded UIDVALIDITY is stale.
|
|
4140
|
+
const uids = await imapService.resolveUidsForBulkOp(folder, emailIds, match, currentUidValidity);
|
|
4141
|
+
ensureBulkBatchSize(uids.length, max);
|
|
4132
4142
|
if (normalizeBoolean(args.dryRun, false)) {
|
|
4143
|
+
const preview = await imapService.bulkMove({
|
|
4144
|
+
emailIds,
|
|
4145
|
+
match,
|
|
4146
|
+
folder,
|
|
4147
|
+
targetFolder,
|
|
4148
|
+
resolvedUids: uids,
|
|
4149
|
+
uidValidity: currentUidValidity,
|
|
4150
|
+
dryRun: true,
|
|
4151
|
+
});
|
|
4133
4152
|
return createTextResult(withBulkNotFound(preview, notFoundEmailIds));
|
|
4134
4153
|
}
|
|
4135
4154
|
const result = await withAudit(auditService, name, args, () => imapService.bulkMove({
|
|
@@ -4137,6 +4156,8 @@ export function createServer(config, options = {}) {
|
|
|
4137
4156
|
match,
|
|
4138
4157
|
folder,
|
|
4139
4158
|
targetFolder,
|
|
4159
|
+
resolvedUids: uids,
|
|
4160
|
+
uidValidity: currentUidValidity,
|
|
4140
4161
|
dryRun: false,
|
|
4141
4162
|
}));
|
|
4142
4163
|
return createTextResult(withBulkNotFound(result, notFoundEmailIds));
|
|
@@ -4182,6 +4203,7 @@ export function createServer(config, options = {}) {
|
|
|
4182
4203
|
folder,
|
|
4183
4204
|
permanent,
|
|
4184
4205
|
resolvedUids: uids,
|
|
4206
|
+
uidValidity: currentUidValidity,
|
|
4185
4207
|
dryRun: true,
|
|
4186
4208
|
});
|
|
4187
4209
|
return createTextResult(withBulkNotFound(preview, notFoundEmailIds));
|
|
@@ -4192,6 +4214,7 @@ export function createServer(config, options = {}) {
|
|
|
4192
4214
|
folder,
|
|
4193
4215
|
permanent,
|
|
4194
4216
|
resolvedUids: uids,
|
|
4217
|
+
uidValidity: currentUidValidity,
|
|
4195
4218
|
dryRun: false,
|
|
4196
4219
|
}));
|
|
4197
4220
|
return createTextResult(withBulkNotFound(result, notFoundEmailIds));
|
|
@@ -4226,10 +4249,10 @@ export function createServer(config, options = {}) {
|
|
|
4226
4249
|
const uids = await imapService.resolveUidsForBulkOp(folder, emailIds, match, currentUidValidity);
|
|
4227
4250
|
ensureBulkBatchSize(uids.length, max);
|
|
4228
4251
|
if (normalizeBoolean(args.dryRun, false)) {
|
|
4229
|
-
const preview = await imapService.bulkUpdateFlags({ emailIds, match, folder, flagsToAdd, flagsToRemove, resolvedUids: uids, dryRun: true });
|
|
4252
|
+
const preview = await imapService.bulkUpdateFlags({ emailIds, match, folder, flagsToAdd, flagsToRemove, resolvedUids: uids, uidValidity: currentUidValidity, dryRun: true });
|
|
4230
4253
|
return createTextResult(withBulkNotFound(preview, notFoundEmailIds));
|
|
4231
4254
|
}
|
|
4232
|
-
const result = await withAudit(auditService, name, args, () => imapService.bulkUpdateFlags({ emailIds, match, folder, flagsToAdd, flagsToRemove, resolvedUids: uids, dryRun: false }));
|
|
4255
|
+
const result = await withAudit(auditService, name, args, () => imapService.bulkUpdateFlags({ emailIds, match, folder, flagsToAdd, flagsToRemove, resolvedUids: uids, uidValidity: currentUidValidity, dryRun: false }));
|
|
4233
4256
|
return createTextResult(withBulkNotFound(result, notFoundEmailIds));
|
|
4234
4257
|
}
|
|
4235
4258
|
case "bulk_update_labels": {
|
|
@@ -4260,10 +4283,10 @@ export function createServer(config, options = {}) {
|
|
|
4260
4283
|
const uids = await imapService.resolveUidsForBulkOp(folder, emailIds, match, currentUidValidity);
|
|
4261
4284
|
ensureBulkBatchSize(uids.length, max);
|
|
4262
4285
|
if (normalizeBoolean(args.dryRun, false)) {
|
|
4263
|
-
const preview = await imapService.bulkUpdateLabels({ emailIds, match, folder, labelsToAdd, labelsToRemove, resolvedUids: uids, dryRun: true });
|
|
4286
|
+
const preview = await imapService.bulkUpdateLabels({ emailIds, match, folder, labelsToAdd, labelsToRemove, resolvedUids: uids, uidValidity: currentUidValidity, dryRun: true });
|
|
4264
4287
|
return createTextResult(withBulkNotFound(preview, notFoundEmailIds));
|
|
4265
4288
|
}
|
|
4266
|
-
const result = await withAudit(auditService, name, args, () => imapService.bulkUpdateLabels({ emailIds, match, folder, labelsToAdd, labelsToRemove, resolvedUids: uids, dryRun: false }));
|
|
4289
|
+
const result = await withAudit(auditService, name, args, () => imapService.bulkUpdateLabels({ emailIds, match, folder, labelsToAdd, labelsToRemove, resolvedUids: uids, uidValidity: currentUidValidity, dryRun: false }));
|
|
4267
4290
|
return createTextResult(withBulkNotFound(result, notFoundEmailIds));
|
|
4268
4291
|
}
|
|
4269
4292
|
case "top_senders": {
|
|
@@ -4532,6 +4555,10 @@ export function createServer(config, options = {}) {
|
|
|
4532
4555
|
if (emailIds.length === 0) {
|
|
4533
4556
|
throw new McpError(ErrorCode.InvalidParams, "emailIds must contain at least one email id.");
|
|
4534
4557
|
}
|
|
4558
|
+
// Same safety rail as the bulk_* tools (bulk_delete etc.) — without
|
|
4559
|
+
// it, an arbitrarily large emailIds array would be processed in
|
|
4560
|
+
// full with no size limit at all.
|
|
4561
|
+
ensureBulkBatchSize(emailIds.length, getBulkMaxBatchSize(args));
|
|
4535
4562
|
const action = requireEmailAction(args);
|
|
4536
4563
|
ensureEmailActionAllowed(config.runtime, action);
|
|
4537
4564
|
if (action === "delete") {
|
|
@@ -5114,6 +5141,10 @@ export function createServer(config, options = {}) {
|
|
|
5114
5141
|
const emailIds = [...new Set(thread.messages
|
|
5115
5142
|
.filter((message) => !unreadOnly || !message.isRead)
|
|
5116
5143
|
.map((message) => message.primaryEmailId))];
|
|
5144
|
+
// Same safety rail as the bulk_* tools (bulk_delete etc.) — without
|
|
5145
|
+
// it, a thread with an arbitrarily large message count would be
|
|
5146
|
+
// processed in full with no size limit at all.
|
|
5147
|
+
ensureBulkBatchSize(emailIds.length, getBulkMaxBatchSize(args));
|
|
5117
5148
|
if (action === "delete") {
|
|
5118
5149
|
ensureDestructiveConfirmed(config.runtime, normalizeBoolean(args.confirmed, false), `Permanently delete ${emailIds.length} email(s) in thread (cannot be recovered)`);
|
|
5119
5150
|
}
|