proton-mail-bridge-client 2.1.5 → 2.1.7
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 +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +92 -15
- package/dist/index.js.map +1 -1
- package/dist/services/simple-imap-service.d.ts.map +1 -1
- package/dist/services/simple-imap-service.js +24 -4
- 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
|
@@ -65,6 +65,9 @@ export declare function redactDraftAttachmentsForListing(draft: DraftRecord): {
|
|
|
65
65
|
remoteDraft?: import("./types/index.js").RemoteDraftRef;
|
|
66
66
|
lastSendResult?: import("./types/index.js").DraftSendResult;
|
|
67
67
|
};
|
|
68
|
+
export declare function truncateDraftBodyForResponse<T extends {
|
|
69
|
+
body: string;
|
|
70
|
+
}>(draft: T): T;
|
|
68
71
|
export declare function redactQueueRecordAttachments<T extends {
|
|
69
72
|
payload: SendEmailInput;
|
|
70
73
|
}>(record: T): T;
|
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,EAAmC,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAC1F,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAE7D,OAAO,KAAK,EAMV,mBAAmB,EAEnB,WAAW,EAIX,WAAW,EAIX,gBAAgB,EAChB,cAAc,EAGf,MAAM,kBAAkB,CAAC;AAmB1B,OAAO,EAAE,cAAc,EAAE,KAAK,aAAa,EAAE,MAAM,+BAA+B,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,EAAmC,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAC1F,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAE7D,OAAO,KAAK,EAMV,mBAAmB,EAEnB,WAAW,EAIX,WAAW,EAIX,gBAAgB,EAChB,cAAc,EAGf,MAAM,kBAAkB,CAAC;AAmB1B,OAAO,EAAE,cAAc,EAAE,KAAK,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAsrDnF,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;AAuLD,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAW5E;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAe/E;AAWD,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;AA6ED,wBAAgB,aAAa,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CA4CtE;AAcD,wBAAgB,gCAAgC,CAAC,KAAK,EAAE,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAYlE;AAoBD,wBAAgB,4BAA4B,CAAC,CAAC,SAAS;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,KAAK,EAAE,CAAC,KAUhF;AAQD,wBAAgB,4BAA4B,CAAC,CAAC,SAAS;IAAE,OAAO,EAAE,cAAc,CAAA;CAAE,EAAE,MAAM,EAAE,CAAC,KAmB5F;AA8WD,wBAAgB,4BAA4B,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,CAAC,EAAE,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAKjI;AA8PD,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;AAED,UAAU,mBAAmB;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AASD,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,MAAM,EAAE,GAAG,SAAS,EAC9B,MAAM,EAAE,MAAM,EACd,kBAAkB,CAAC,EAAE,MAAM,GAC1B,mBAAmB,EAAE,CA8CvB;AAED,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,mBAAmB,EAC3B,gBAAgB,EAAE,mBAAmB,EAAE,GACtC,mBAAmB,CAmBrB;AAWD,wBAAgB,sBAAsB,CACpC,cAAc,EAAE,cAAc,EAC9B,QAAQ,EAAE,MAAM,EAAE,GACjB,GAAG,CAAC,MAAM,GAAG,SAAS,EAAE;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAYvE;AAOD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,mBAAmB,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,mBAAmB,CAQ3G;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,mBAAmB,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,mBAAmB,EAAE,CAK/G;AAID,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,mBAAmB,EAAE,GAAG,mBAAmB,CASpF;AAsQD,wBAAgB,kBAAkB,IAAI,gBAAgB,CAkGrD;AAED,wBAAgB,YAAY,CAC1B,MAAM,EAAE,gBAAgB,EACxB,OAAO,GAAE;IACP,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC1B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAwvIP;AAED,wBAAsB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAmE1C"}
|
package/dist/index.js
CHANGED
|
@@ -385,12 +385,14 @@ const TOOLS = [
|
|
|
385
385
|
},
|
|
386
386
|
{
|
|
387
387
|
name: "list_drafts",
|
|
388
|
-
description: "List all locally saved drafts with their status, subject, and timestamps. Attachment content is omitted here (filename/type/size only) to
|
|
388
|
+
description: "List all locally saved drafts with their status, subject, and timestamps. Attachment content is omitted here (filename/type/size only) — use get_draft for the full attachment content of one draft. Each draft's body is also truncated to a short preview (bodyTruncated:true, bodyLength gives the real size) — use get_draft for the full body of one draft. Use to review in-progress or unsent messages. Does NOT list drafts stored only on the Proton server — use list_remote_drafts for those. Prefer get_draft when you already have a draftId and need the full content.",
|
|
389
389
|
annotations: { readOnlyHint: true },
|
|
390
390
|
inputSchema: {
|
|
391
391
|
type: "object",
|
|
392
392
|
properties: {
|
|
393
393
|
includeSent: { type: "boolean", description: "Include drafts already sent.", default: false },
|
|
394
|
+
limit: { type: "number", description: "Maximum drafts to return. Omit to return every draft (still with truncated bodies/attachments) — set this when you only need a bounded page." },
|
|
395
|
+
offset: { type: "number", description: "Number of drafts to skip, newest-updated first.", default: 0 },
|
|
394
396
|
},
|
|
395
397
|
},
|
|
396
398
|
},
|
|
@@ -2277,6 +2279,34 @@ export function redactDraftAttachmentsForListing(draft) {
|
|
|
2277
2279
|
})),
|
|
2278
2280
|
};
|
|
2279
2281
|
}
|
|
2282
|
+
// How much of a draft's body survives into a mutation/listing response before
|
|
2283
|
+
// it's truncated — long enough to recognize the draft at a glance, short
|
|
2284
|
+
// enough that a large body (a long thread quoted into a reply, a big pasted
|
|
2285
|
+
// table) doesn't dominate the response the way redactDraftAttachmentsForListing
|
|
2286
|
+
// already stops a base64 attachment from doing.
|
|
2287
|
+
const DRAFT_BODY_PREVIEW_LENGTH = 500;
|
|
2288
|
+
// Found live (external review, repeated across three rounds): create_draft,
|
|
2289
|
+
// update_draft, create_reply_draft, create_forward_draft,
|
|
2290
|
+
// create_thread_reply_draft, sync_draft_to_remote, and list_drafts all echoed
|
|
2291
|
+
// the draft's COMPLETE body back — confirmed live at ~40k tokens for a single
|
|
2292
|
+
// update_draft call that only changed the subject of a ~202 KB draft, and
|
|
2293
|
+
// ~261k tokens for list_drafts with 107 drafts. The caller supplied the body
|
|
2294
|
+
// itself (create/update) or already has it from a prior call (list) — same
|
|
2295
|
+
// "caller already knows what it sent" reasoning as attachment redaction, just
|
|
2296
|
+
// for the text body instead of base64. get_draft deliberately keeps the full
|
|
2297
|
+
// body — it's the "let me look at this one draft" call, not a repeated-edit
|
|
2298
|
+
// or bulk-listing one.
|
|
2299
|
+
export function truncateDraftBodyForResponse(draft) {
|
|
2300
|
+
if (draft.body.length <= DRAFT_BODY_PREVIEW_LENGTH) {
|
|
2301
|
+
return draft;
|
|
2302
|
+
}
|
|
2303
|
+
return {
|
|
2304
|
+
...draft,
|
|
2305
|
+
body: `${draft.body.slice(0, DRAFT_BODY_PREVIEW_LENGTH)}…`,
|
|
2306
|
+
bodyLength: draft.body.length,
|
|
2307
|
+
bodyTruncated: true,
|
|
2308
|
+
};
|
|
2309
|
+
}
|
|
2280
2310
|
// Same fix as redactDraftAttachmentsForListing, for list_scheduled_sends — a
|
|
2281
2311
|
// queued send's payload carries the same full base64 EmailAttachmentInput
|
|
2282
2312
|
// content (found live: ~955k tokens for a single 1 MiB attachment on ONE
|
|
@@ -4041,9 +4071,9 @@ export function createServer(config, options = {}) {
|
|
|
4041
4071
|
return presentDraft(createDraftBundle, remoteSync ? { ...synced.draft, remoteSync } : synced.draft);
|
|
4042
4072
|
});
|
|
4043
4073
|
// Same fix as update_draft's identical bloat — see its comment. The
|
|
4044
|
-
// caller already knows what it attached
|
|
4045
|
-
// the full
|
|
4046
|
-
return createTextResult(redactDraftAttachmentsForListing(result), false, [
|
|
4074
|
+
// caller already knows what it attached (and what body it just sent);
|
|
4075
|
+
// get_draft is the "let me see the full content" call, not this one.
|
|
4076
|
+
return createTextResult(truncateDraftBodyForResponse(redactDraftAttachmentsForListing(result)), false, [
|
|
4047
4077
|
draftSource(result),
|
|
4048
4078
|
...(result.remoteDraft?.emailId
|
|
4049
4079
|
? [
|
|
@@ -4096,6 +4126,14 @@ export function createServer(config, options = {}) {
|
|
|
4096
4126
|
subject: prefixedSubject(detail.subject, "Re:"),
|
|
4097
4127
|
body: buildReplyText(detail, body),
|
|
4098
4128
|
isHtml,
|
|
4129
|
+
// Found live (external review): a `from` naming a real alias NOT
|
|
4130
|
+
// itself a separately-configured account (e.g. a genuine alias
|
|
4131
|
+
// reachable only via header override, same as send_email's own
|
|
4132
|
+
// fallback) picked the right draftStore bundle above but never
|
|
4133
|
+
// actually stored the address on the draft — draft.from came back
|
|
4134
|
+
// undefined, so a later send_draft used the account's default
|
|
4135
|
+
// sender instead of the alias the caller asked for.
|
|
4136
|
+
from: optionalString(args, "from"),
|
|
4099
4137
|
inReplyTo: detail.messageId,
|
|
4100
4138
|
references: detail.messageId ? [detail.messageId] : undefined,
|
|
4101
4139
|
attachments,
|
|
@@ -4118,7 +4156,7 @@ export function createServer(config, options = {}) {
|
|
|
4118
4156
|
return presentDraft(createReplyDraftBundle, remoteSync ? { ...synced.draft, remoteSync } : synced.draft);
|
|
4119
4157
|
});
|
|
4120
4158
|
// Same fix as create_draft/update_draft's identical bloat — see their comments.
|
|
4121
|
-
return createTextResult(redactDraftAttachmentsForListing(result), false, [
|
|
4159
|
+
return createTextResult(truncateDraftBodyForResponse(redactDraftAttachmentsForListing(result)), false, [
|
|
4122
4160
|
draftSource(result),
|
|
4123
4161
|
emailSource(detail),
|
|
4124
4162
|
...(result.remoteDraft?.emailId
|
|
@@ -4171,6 +4209,8 @@ export function createServer(config, options = {}) {
|
|
|
4171
4209
|
subject: prefixedSubject(detail.subject, "Fwd:"),
|
|
4172
4210
|
body: buildForwardText(detail, optionalString(args, "body")),
|
|
4173
4211
|
isHtml: normalizeBoolean(args.isHtml, false),
|
|
4212
|
+
// Same fix as create_reply_draft — see its comment.
|
|
4213
|
+
from: optionalString(args, "from"),
|
|
4174
4214
|
attachments,
|
|
4175
4215
|
sourceEmailId: detail.id,
|
|
4176
4216
|
sourceMessageId: detail.messageId,
|
|
@@ -4191,7 +4231,7 @@ export function createServer(config, options = {}) {
|
|
|
4191
4231
|
return presentDraft(createForwardDraftBundle, remoteSync ? { ...synced.draft, remoteSync } : synced.draft);
|
|
4192
4232
|
});
|
|
4193
4233
|
// Same fix as create_draft/update_draft's identical bloat — see their comments.
|
|
4194
|
-
return createTextResult(redactDraftAttachmentsForListing(result), false, [
|
|
4234
|
+
return createTextResult(truncateDraftBodyForResponse(redactDraftAttachmentsForListing(result)), false, [
|
|
4195
4235
|
draftSource(result),
|
|
4196
4236
|
emailSource(detail),
|
|
4197
4237
|
...(result.remoteDraft?.emailId
|
|
@@ -4210,10 +4250,23 @@ export function createServer(config, options = {}) {
|
|
|
4210
4250
|
// drafts only — a non-primary account's drafts aren't listed here yet. Use
|
|
4211
4251
|
// get_draft with that account's prefixed draftId if you already have one.
|
|
4212
4252
|
const drafts = await draftStore.listDrafts(normalizeBoolean(args.includeSent, false));
|
|
4253
|
+
// Found live (external review): every draft's full body was returned
|
|
4254
|
+
// alongside the already-redacted attachments — confirmed live at ~261k
|
|
4255
|
+
// tokens for 107 drafts. Bodies are now truncated the same way a
|
|
4256
|
+
// mutation response's body is (see truncateDraftBodyForResponse). limit/
|
|
4257
|
+
// offset are optional and additive — omitting them still returns every
|
|
4258
|
+
// draft (just with truncated bodies/attachments), so this doesn't change
|
|
4259
|
+
// behavior for a caller not using the new params.
|
|
4260
|
+
const offset = normalizeLimit(args.offset, 0, 0, 10_000);
|
|
4261
|
+
const limit = typeof args.limit === "number" ? normalizeLimit(args.limit, drafts.length, 1, 10_000) : undefined;
|
|
4262
|
+
const page = limit !== undefined ? drafts.slice(offset, offset + limit) : drafts.slice(offset);
|
|
4213
4263
|
return createTextResult({
|
|
4214
4264
|
total: drafts.length,
|
|
4215
|
-
|
|
4216
|
-
|
|
4265
|
+
offset,
|
|
4266
|
+
returned: page.length,
|
|
4267
|
+
hasMore: offset + page.length < drafts.length,
|
|
4268
|
+
drafts: page.map((draft) => truncateDraftBodyForResponse(redactDraftAttachmentsForListing(draft))),
|
|
4269
|
+
}, false, page.map(draftSource));
|
|
4217
4270
|
}
|
|
4218
4271
|
case "list_remote_drafts": {
|
|
4219
4272
|
// Scope limitation (follow-up round): stays scoped to the primary account's
|
|
@@ -4304,10 +4357,13 @@ export function createServer(config, options = {}) {
|
|
|
4304
4357
|
// subject/body — the attachments usually aren't touched by this call at all, so
|
|
4305
4358
|
// re-echoing their full base64 `content` (serialized twice by createTextResult,
|
|
4306
4359
|
// same issue redactDraftAttachmentsForListing already fixed for list_drafts)
|
|
4307
|
-
// burns tokens on every single edit for a draft that has any attachment.
|
|
4308
|
-
//
|
|
4309
|
-
//
|
|
4310
|
-
|
|
4360
|
+
// burns tokens on every single edit for a draft that has any attachment. Same
|
|
4361
|
+
// reasoning for the body itself — confirmed live at ~40k tokens for a single
|
|
4362
|
+
// subject-only edit of a ~202 KB draft (see truncateDraftBodyForResponse). The
|
|
4363
|
+
// caller already knows what it attached and what body it just sent; get_draft
|
|
4364
|
+
// remains full-content for the "let me look at this draft" case, which is a
|
|
4365
|
+
// single call rather than a loop.
|
|
4366
|
+
return createTextResult(truncateDraftBodyForResponse(redactDraftAttachmentsForListing(result)), false, [
|
|
4311
4367
|
draftSource(result),
|
|
4312
4368
|
...(result.remoteDraft?.emailId
|
|
4313
4369
|
? [
|
|
@@ -4327,7 +4383,7 @@ export function createServer(config, options = {}) {
|
|
|
4327
4383
|
const synced = await withAudit(auditService, name, args, async () => syncDraftToRemote(syncDraftBundle.draftStore, syncDraftBundle.smtpService, syncDraftBundle.imapService, draft));
|
|
4328
4384
|
const presentedSynced = presentDraft(syncDraftBundle, synced.draft);
|
|
4329
4385
|
// Same fix as create_draft/update_draft's identical bloat — see their comments.
|
|
4330
|
-
return createTextResult({ ...redactDraftAttachmentsForListing(presentedSynced), remoteSync: synced.remoteSync }, false, [
|
|
4386
|
+
return createTextResult({ ...truncateDraftBodyForResponse(redactDraftAttachmentsForListing(presentedSynced)), remoteSync: synced.remoteSync }, false, [
|
|
4331
4387
|
draftSource(presentedSynced),
|
|
4332
4388
|
...(presentedSynced.remoteDraft?.emailId
|
|
4333
4389
|
? [
|
|
@@ -4647,7 +4703,26 @@ export function createServer(config, options = {}) {
|
|
|
4647
4703
|
// requested offset/limit to that merged superset instead of per account.
|
|
4648
4704
|
const primarySlug = accountManager.primary().account.slug;
|
|
4649
4705
|
const requestedOffset = getEmailsInput.offset ?? 0;
|
|
4650
|
-
|
|
4706
|
+
// +1 beyond what's strictly needed to fill the page: whether that extra
|
|
4707
|
+
// item actually comes back is what tells us hasMore, independent of any
|
|
4708
|
+
// filter (beforeUid etc.) or of how the raw mailbox total compares to the
|
|
4709
|
+
// page window. Two things were tried and each broke a different case:
|
|
4710
|
+
// (1) using mergedAll.length > offset+limit as hasMore, with NO extra
|
|
4711
|
+
// overfetch — a lopsided distribution (e.g. 300 messages in one account,
|
|
4712
|
+
// 0 in another) fetches exactly offset+limit from the big account, so
|
|
4713
|
+
// mergedAll.length can never exceed that window even though hundreds
|
|
4714
|
+
// more exist, reporting hasMore:false wrongly.
|
|
4715
|
+
// (2) using the raw summed mailbox `total` for hasMore instead — correct
|
|
4716
|
+
// for that case, but wrong under a restrictive filter like beforeUid:
|
|
4717
|
+
// `total` is the UNFILTERED mailbox message count, not the count of
|
|
4718
|
+
// messages actually matching the filter, so a beforeUid narrowing 300
|
|
4719
|
+
// messages down to 2 matches still compared against total=300 and
|
|
4720
|
+
// reported hasMore:true with nothing left to page to.
|
|
4721
|
+
// Fetching one extra item fixes both: it directly observes whether a
|
|
4722
|
+
// NEXT matching item exists, under whatever filter is active, rather
|
|
4723
|
+
// than inferring it from a count that can be either capped-by-fetch or
|
|
4724
|
+
// filter-blind depending on which one you pick.
|
|
4725
|
+
const perAccountFetchLimit = requestedOffset + effectiveLimit + 1;
|
|
4651
4726
|
const perAccount = await Promise.all(accountManager.all().map(async (bundle) => {
|
|
4652
4727
|
const result = await bundle.imapService.getEmails({ ...getEmailsInput, offset: 0, limit: perAccountFetchLimit });
|
|
4653
4728
|
return { bundle, result };
|
|
@@ -6492,6 +6567,8 @@ export function createServer(config, options = {}) {
|
|
|
6492
6567
|
subject: prefixedSubject(detail.subject, "Re:"),
|
|
6493
6568
|
body: buildReplyText(detail, body),
|
|
6494
6569
|
isHtml,
|
|
6570
|
+
// Same fix as create_reply_draft — see its comment.
|
|
6571
|
+
from: optionalString(args, "from"),
|
|
6495
6572
|
inReplyTo: detail.messageId,
|
|
6496
6573
|
references: detail.messageId ? [detail.messageId] : undefined,
|
|
6497
6574
|
attachments,
|
|
@@ -6515,7 +6592,7 @@ export function createServer(config, options = {}) {
|
|
|
6515
6592
|
return { ...presented, threadId: thread.id };
|
|
6516
6593
|
});
|
|
6517
6594
|
// Same fix as create_draft/update_draft's identical bloat — see their comments.
|
|
6518
|
-
return createTextResult(redactDraftAttachmentsForListing(result), false, [
|
|
6595
|
+
return createTextResult(truncateDraftBodyForResponse(redactDraftAttachmentsForListing(result)), false, [
|
|
6519
6596
|
draftSource(result),
|
|
6520
6597
|
threadSource(thread),
|
|
6521
6598
|
emailSource(detail),
|