@rubytech/create-maxy-code 0.1.458 → 0.1.459
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/package.json +1 -1
- package/payload/platform/lib/storage-broker/dist/__tests__/cf-exec.test.js +188 -3
- package/payload/platform/lib/storage-broker/dist/__tests__/cf-exec.test.js.map +1 -1
- package/payload/platform/lib/storage-broker/dist/__tests__/object-limits.test.d.ts +2 -0
- package/payload/platform/lib/storage-broker/dist/__tests__/object-limits.test.d.ts.map +1 -0
- package/payload/platform/lib/storage-broker/dist/__tests__/object-limits.test.js +59 -0
- package/payload/platform/lib/storage-broker/dist/__tests__/object-limits.test.js.map +1 -0
- package/payload/platform/lib/storage-broker/dist/cf-exec.d.ts +12 -1
- package/payload/platform/lib/storage-broker/dist/cf-exec.d.ts.map +1 -1
- package/payload/platform/lib/storage-broker/dist/cf-exec.js +97 -0
- package/payload/platform/lib/storage-broker/dist/cf-exec.js.map +1 -1
- package/payload/platform/lib/storage-broker/dist/house-credential.d.ts.map +1 -1
- package/payload/platform/lib/storage-broker/dist/house-credential.js +4 -2
- package/payload/platform/lib/storage-broker/dist/house-credential.js.map +1 -1
- package/payload/platform/lib/storage-broker/dist/index.d.ts +1 -0
- package/payload/platform/lib/storage-broker/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/storage-broker/dist/index.js +1 -0
- package/payload/platform/lib/storage-broker/dist/index.js.map +1 -1
- package/payload/platform/lib/storage-broker/dist/object-limits.d.ts +53 -0
- package/payload/platform/lib/storage-broker/dist/object-limits.d.ts.map +1 -0
- package/payload/platform/lib/storage-broker/dist/object-limits.js +72 -0
- package/payload/platform/lib/storage-broker/dist/object-limits.js.map +1 -0
- package/payload/platform/lib/storage-broker/src/__tests__/cf-exec.test.ts +211 -5
- package/payload/platform/lib/storage-broker/src/__tests__/object-limits.test.ts +76 -0
- package/payload/platform/lib/storage-broker/src/cf-exec.ts +148 -6
- package/payload/platform/lib/storage-broker/src/house-credential.ts +4 -2
- package/payload/platform/lib/storage-broker/src/index.ts +1 -0
- package/payload/platform/lib/storage-broker/src/object-limits.ts +75 -0
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +5 -5
- package/payload/platform/plugins/cloudflare/bin/cf-token.sh +4 -3
- package/payload/platform/plugins/cloudflare/references/api.md +1 -1
- package/payload/platform/plugins/docs/references/outlook-guide.md +4 -4
- package/payload/platform/plugins/outlook/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/outlook/PLUGIN.md +2 -2
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/attach.test.d.ts +2 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/attach.test.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/attach.test.js +138 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/attach.test.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-attachments.test.d.ts +2 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-attachments.test.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-attachments.test.js +121 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-attachments.test.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-edit-attachments.test.d.ts +2 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-edit-attachments.test.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-edit-attachments.test.js +102 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-edit-attachments.test.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-edit.test.js +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-edit.test.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-send-attachments.test.d.ts +2 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-send-attachments.test.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-send-attachments.test.js +209 -0
- package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-send-attachments.test.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/index.js +10 -7
- package/payload/platform/plugins/outlook/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/lib/attach.d.ts +37 -0
- package/payload/platform/plugins/outlook/mcp/dist/lib/attach.d.ts.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/lib/attach.js +79 -0
- package/payload/platform/plugins/outlook/mcp/dist/lib/attach.js.map +1 -0
- package/payload/platform/plugins/outlook/mcp/dist/lib/message.d.ts +8 -0
- package/payload/platform/plugins/outlook/mcp/dist/lib/message.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/lib/message.js +4 -0
- package/payload/platform/plugins/outlook/mcp/dist/lib/message.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/lib/outbound-attachments.d.ts +31 -8
- package/payload/platform/plugins/outlook/mcp/dist/lib/outbound-attachments.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/lib/outbound-attachments.js +40 -13
- package/payload/platform/plugins/outlook/mcp/dist/lib/outbound-attachments.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/lib/upload-session.d.ts +9 -5
- package/payload/platform/plugins/outlook/mcp/dist/lib/upload-session.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/lib/upload-session.js +12 -8
- package/payload/platform/plugins/outlook/mcp/dist/lib/upload-session.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/draft-edit.d.ts +29 -4
- package/payload/platform/plugins/outlook/mcp/dist/tools/draft-edit.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/draft-edit.js +46 -13
- package/payload/platform/plugins/outlook/mcp/dist/tools/draft-edit.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/draft.d.ts +8 -2
- package/payload/platform/plugins/outlook/mcp/dist/tools/draft.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/draft.js +13 -4
- package/payload/platform/plugins/outlook/mcp/dist/tools/draft.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-reply.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-reply.js +3 -20
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-reply.js.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-send.d.ts +27 -3
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-send.d.ts.map +1 -1
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-send.js +53 -8
- package/payload/platform/plugins/outlook/mcp/dist/tools/mail-send.js.map +1 -1
- package/payload/platform/plugins/outlook/references/graph-surfaces.md +29 -6
- package/payload/platform/plugins/outlook/skills/outlook/SKILL.md +22 -5
- package/payload/platform/plugins/storage-broker/PLUGIN.md +41 -2
- package/payload/platform/plugins/storage-broker/mcp/dist/__tests__/confine-path.test.d.ts +2 -0
- package/payload/platform/plugins/storage-broker/mcp/dist/__tests__/confine-path.test.d.ts.map +1 -0
- package/payload/platform/plugins/storage-broker/mcp/dist/__tests__/confine-path.test.js +85 -0
- package/payload/platform/plugins/storage-broker/mcp/dist/__tests__/confine-path.test.js.map +1 -0
- package/payload/platform/plugins/storage-broker/mcp/dist/__tests__/put-source.test.d.ts +2 -0
- package/payload/platform/plugins/storage-broker/mcp/dist/__tests__/put-source.test.d.ts.map +1 -0
- package/payload/platform/plugins/storage-broker/mcp/dist/__tests__/put-source.test.js +77 -0
- package/payload/platform/plugins/storage-broker/mcp/dist/__tests__/put-source.test.js.map +1 -0
- package/payload/platform/plugins/storage-broker/mcp/dist/confine-path.d.ts +12 -0
- package/payload/platform/plugins/storage-broker/mcp/dist/confine-path.d.ts.map +1 -0
- package/payload/platform/plugins/storage-broker/mcp/dist/confine-path.js +107 -0
- package/payload/platform/plugins/storage-broker/mcp/dist/confine-path.js.map +1 -0
- package/payload/platform/plugins/storage-broker/mcp/dist/index.js +86 -0
- package/payload/platform/plugins/storage-broker/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/storage-broker/mcp/dist/put-source.d.ts +11 -0
- package/payload/platform/plugins/storage-broker/mcp/dist/put-source.d.ts.map +1 -0
- package/payload/platform/plugins/storage-broker/mcp/dist/put-source.js +35 -0
- package/payload/platform/plugins/storage-broker/mcp/dist/put-source.js.map +1 -0
- package/payload/platform/scripts/logs-read-jsonl.test.sh +118 -0
- package/payload/platform/scripts/logs-read.sh +63 -9
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +4 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
- package/payload/server/{chunk-F4D35LKL.js → chunk-POBXIHOF.js} +34 -0
- package/payload/server/{chunk-64FGYKNZ.js → chunk-Q6W4U6HL.js} +104 -0
- package/payload/server/maxy-edge.js +1 -1
- package/payload/server/server.js +206 -6
- package/payload/server/{src-S7C4P6TT.js → src-3I2RYZFB.js} +9 -1
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The shared per-file attach loop for every outbound path that can carry a
|
|
3
|
+
* file: outlook-mail-reply, outlook-mail-send (draft-send route), outlook-draft,
|
|
4
|
+
* and outlook-draft-edit. Extracted from mail-reply so the sequence is written
|
|
5
|
+
* once rather than a fourth time.
|
|
6
|
+
*
|
|
7
|
+
* Kept out of `outbound-attachments.ts` deliberately: that lib is pure node:fs
|
|
8
|
+
* with a pure test suite, and folding Graph calls into it would drag
|
|
9
|
+
* graph-client and upload-session across that boundary.
|
|
10
|
+
*
|
|
11
|
+
* `tool` names the calling tool and is threaded to the Graph call tag, the
|
|
12
|
+
* upload session's error prefix, and the log line's `event`, so one
|
|
13
|
+
* attachment's lifeline greps back to the tool that sent it.
|
|
14
|
+
*/
|
|
15
|
+
import { postGraph } from "./graph-client.js";
|
|
16
|
+
import { AttachmentRefusedError, resolveOutboundAttachments, toInlineAttachment, } from "./outbound-attachments.js";
|
|
17
|
+
import { uploadAttachmentSession } from "./upload-session.js";
|
|
18
|
+
import { log } from "./log.js";
|
|
19
|
+
/**
|
|
20
|
+
* Validate agent-supplied paths, emitting the `op: "refuse"` line for a per-path
|
|
21
|
+
* refusal before rethrowing.
|
|
22
|
+
*
|
|
23
|
+
* Throwing here — before any postGraph — IS the orphan-draft guard: the absence
|
|
24
|
+
* of a following `op: "attach"` for that call proves it held. Account-context
|
|
25
|
+
* failures are not per-path refusals and pass through unlogged: they name no
|
|
26
|
+
* file, so a refuse line for them would carry an empty `name`.
|
|
27
|
+
*/
|
|
28
|
+
export function resolveAttachmentsOrRefuse(accountId, paths, tool) {
|
|
29
|
+
try {
|
|
30
|
+
return resolveOutboundAttachments(accountId, paths);
|
|
31
|
+
}
|
|
32
|
+
catch (err) {
|
|
33
|
+
if (err instanceof AttachmentRefusedError) {
|
|
34
|
+
const fields = {
|
|
35
|
+
event: tool,
|
|
36
|
+
op: "refuse",
|
|
37
|
+
reason: err.reason,
|
|
38
|
+
name: err.file,
|
|
39
|
+
};
|
|
40
|
+
// Omitted rather than rendered `bytes=null` when the refusal carries no
|
|
41
|
+
// size (a bad path has none to report).
|
|
42
|
+
if (err.bytes !== undefined)
|
|
43
|
+
fields.bytes = err.bytes;
|
|
44
|
+
if (err.cap !== undefined)
|
|
45
|
+
fields.cap = err.cap;
|
|
46
|
+
log(fields);
|
|
47
|
+
}
|
|
48
|
+
throw err;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Attach each resolved file to an existing draft. The draft must already exist
|
|
53
|
+
* and every file must already have passed `resolveOutboundAttachments`. A file
|
|
54
|
+
* at or under the inline limit is added as one base64 fileAttachment POST; a
|
|
55
|
+
* larger file (to the 25 MB cap) streams through a Graph upload session.
|
|
56
|
+
*
|
|
57
|
+
* The `op: "attach"` line is emitted AFTER the POST or session returns, never
|
|
58
|
+
* before, so a logged attach means an attach that landed.
|
|
59
|
+
*/
|
|
60
|
+
export async function attachFilesToDraft(config, draftId, files, tool) {
|
|
61
|
+
for (const f of files) {
|
|
62
|
+
let chunks = 0;
|
|
63
|
+
if (f.mode === "session") {
|
|
64
|
+
chunks = await uploadAttachmentSession(config, draftId, f, tool);
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
await postGraph(config, `/me/messages/${encodeURIComponent(draftId)}/attachments`, toInlineAttachment(f), { tool });
|
|
68
|
+
}
|
|
69
|
+
log({
|
|
70
|
+
event: tool,
|
|
71
|
+
op: "attach",
|
|
72
|
+
id: f.name,
|
|
73
|
+
bytes: f.size,
|
|
74
|
+
path: f.mode,
|
|
75
|
+
chunks,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=attach.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attach.js","sourceRoot":"","sources":["../../src/lib/attach.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAE9C,OAAO,EACL,sBAAsB,EACtB,0BAA0B,EAC1B,kBAAkB,GACnB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAC;AAC9D,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAE/B;;;;;;;;GAQG;AACH,MAAM,UAAU,0BAA0B,CACxC,SAAiB,EACjB,KAA2B,EAC3B,IAAY;IAEZ,IAAI,CAAC;QACH,OAAO,0BAA0B,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IACtD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,sBAAsB,EAAE,CAAC;YAC1C,MAAM,MAAM,GAAgD;gBAC1D,KAAK,EAAE,IAAI;gBACX,EAAE,EAAE,QAAQ;gBACZ,MAAM,EAAE,GAAG,CAAC,MAAM;gBAClB,IAAI,EAAE,GAAG,CAAC,IAAI;aACf,CAAC;YACF,wEAAwE;YACxE,wCAAwC;YACxC,IAAI,GAAG,CAAC,KAAK,KAAK,SAAS;gBAAE,MAAM,CAAC,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC;YACtD,IAAI,GAAG,CAAC,GAAG,KAAK,SAAS;gBAAE,MAAM,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;YAChD,GAAG,CAAC,MAAM,CAAC,CAAC;QACd,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,MAAyB,EACzB,OAAe,EACf,KAA2B,EAC3B,IAAY;IAEZ,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,IAAI,MAAM,GAAG,CAAC,CAAC;QACf,IAAI,CAAC,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YACzB,MAAM,GAAG,MAAM,uBAAuB,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC;QACnE,CAAC;aAAM,CAAC;YACN,MAAM,SAAS,CACb,MAAM,EACN,gBAAgB,kBAAkB,CAAC,OAAO,CAAC,cAAc,EACzD,kBAAkB,CAAC,CAAC,CAAC,EACrB,EAAE,IAAI,EAAE,CACT,CAAC;QACJ,CAAC;QACD,GAAG,CAAC;YACF,KAAK,EAAE,IAAI;YACX,EAAE,EAAE,QAAQ;YACZ,EAAE,EAAE,CAAC,CAAC,IAAI;YACV,KAAK,EAAE,CAAC,CAAC,IAAI;YACb,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,MAAM;SACP,CAAC,CAAC;IACL,CAAC;AACH,CAAC"}
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
* Build a Microsoft Graph message resource from the tool input shape shared by
|
|
3
3
|
* outlook-mail-send and outlook-draft. Graph stores one body with a single
|
|
4
4
|
* contentType, so `isHtml` chooses HTML vs Text for the whole message.
|
|
5
|
+
*
|
|
6
|
+
* `MessageInput` is the TOOL INPUT shape, not the Graph message shape —
|
|
7
|
+
* `GraphMessage` below is the latter. That is why `attachments` lives here but
|
|
8
|
+
* never reaches `buildMessage`'s output.
|
|
5
9
|
*/
|
|
6
10
|
export interface MessageInput {
|
|
7
11
|
to: string[];
|
|
@@ -10,6 +14,10 @@ export interface MessageInput {
|
|
|
10
14
|
subject: string;
|
|
11
15
|
body: string;
|
|
12
16
|
isHtml?: boolean;
|
|
17
|
+
/** Absolute paths inside the account directory. Attachments are separate Graph
|
|
18
|
+
* POSTs against the created draft, NOT part of the message resource, so
|
|
19
|
+
* `buildMessage` deliberately ignores this field. */
|
|
20
|
+
attachments?: string[];
|
|
13
21
|
}
|
|
14
22
|
interface Recipient {
|
|
15
23
|
emailAddress: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message.d.ts","sourceRoot":"","sources":["../../src/lib/message.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"message.d.ts","sourceRoot":"","sources":["../../src/lib/message.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,EAAE,CAAC;IACb,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;0DAEsD;IACtD,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,UAAU,SAAS;IACjB,YAAY,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CACnC;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE;QAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IACxD,YAAY,EAAE,SAAS,EAAE,CAAC;IAC1B,YAAY,CAAC,EAAE,SAAS,EAAE,CAAC;IAC3B,aAAa,CAAC,EAAE,SAAS,EAAE,CAAC;CAC7B;AASD,wBAAgB,YAAY,CAAC,KAAK,EAAE,YAAY,GAAG,YAAY,CAe9D"}
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
* Build a Microsoft Graph message resource from the tool input shape shared by
|
|
3
3
|
* outlook-mail-send and outlook-draft. Graph stores one body with a single
|
|
4
4
|
* contentType, so `isHtml` chooses HTML vs Text for the whole message.
|
|
5
|
+
*
|
|
6
|
+
* `MessageInput` is the TOOL INPUT shape, not the Graph message shape —
|
|
7
|
+
* `GraphMessage` below is the latter. That is why `attachments` lives here but
|
|
8
|
+
* never reaches `buildMessage`'s output.
|
|
5
9
|
*/
|
|
6
10
|
function toRecipients(addrs) {
|
|
7
11
|
return (addrs ?? [])
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message.js","sourceRoot":"","sources":["../../src/lib/message.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"message.js","sourceRoot":"","sources":["../../src/lib/message.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA2BH,SAAS,YAAY,CAAC,KAA2B;IAC/C,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC;SACjB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;SACpB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;SAC3B,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,EAAE,YAAY,EAAE,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,KAAmB;IAC9C,MAAM,EAAE,GAAG,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAClC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;IACvE,CAAC;IACD,MAAM,EAAE,GAAG,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAClC,MAAM,GAAG,GAAG,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACpC,MAAM,OAAO,GAAiB;QAC5B,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,IAAI,EAAE,EAAE,WAAW,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,IAAI,EAAE;QAC1E,YAAY,EAAE,EAAE;KACjB,CAAC;IACF,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,CAAC,YAAY,GAAG,EAAE,CAAC;IAC7C,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,CAAC,aAAa,GAAG,GAAG,CAAC;IAChD,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Outbound attachment resolver
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
2
|
+
* Outbound attachment resolver, shared by every tool that can send a file:
|
|
3
|
+
* outlook-mail-reply, outlook-mail-send, outlook-draft, and outlook-draft-edit.
|
|
4
|
+
* Mirrors the email plugin's account-scope check (realpath under the account
|
|
5
|
+
* directory, regular file, size cap), then classifies each file by how it must
|
|
6
|
+
* reach the draft:
|
|
6
7
|
*
|
|
7
8
|
* - `inline` — at or under Graph's ~3 MB fileAttachment limit; sent as a
|
|
8
9
|
* single base64 `POST /messages/{id}/attachments`.
|
|
@@ -10,12 +11,16 @@
|
|
|
10
11
|
* through a Graph upload session (see `upload-session.ts`).
|
|
11
12
|
*
|
|
12
13
|
* The account cap (25 MB) matches the email plugin's outbound cap, so an
|
|
13
|
-
* Outlook
|
|
14
|
+
* Outlook message and the equivalent IMAP message carry the same maximum.
|
|
14
15
|
*
|
|
15
16
|
* Resolution reads no bytes — it returns per-file metadata (path, size, mode)
|
|
16
|
-
* so
|
|
17
|
-
*
|
|
18
|
-
*
|
|
17
|
+
* so the caller can choose the path. Path validation happens before any Graph
|
|
18
|
+
* write, so a bad path leaves no orphan draft; bytes are read at send time by
|
|
19
|
+
* `toInlineAttachment` (inline) or the upload session (session).
|
|
20
|
+
*
|
|
21
|
+
* This module stays pure node:fs on purpose — the Graph-side attach loop lives
|
|
22
|
+
* in `attach.ts` so this boundary carries no client, no network, and no I/O
|
|
23
|
+
* beyond the filesystem.
|
|
19
24
|
*/
|
|
20
25
|
/** Graph fileAttachment inline limit for POST /messages/{id}/attachments. */
|
|
21
26
|
export declare const OUTLOOK_ATTACHMENT_INLINE_MAX_BYTES: number;
|
|
@@ -27,6 +32,24 @@ export interface GraphFileAttachment {
|
|
|
27
32
|
contentType: string;
|
|
28
33
|
contentBytes: string;
|
|
29
34
|
}
|
|
35
|
+
/** Why a single path was refused. Carried as a field so callers classify a
|
|
36
|
+
* refusal on a field, never by parsing its message. */
|
|
37
|
+
export type RefusalReason = "bad-path" | "oversize";
|
|
38
|
+
/**
|
|
39
|
+
* A per-path refusal, raised before any Graph write. Carries the fields the
|
|
40
|
+
* `op: "refuse"` log line names.
|
|
41
|
+
*
|
|
42
|
+
* Account-context failures (ACCOUNT_DIR unset, account directory unreadable)
|
|
43
|
+
* are NOT refusals: they name no file and no per-file cause, so they stay plain
|
|
44
|
+
* Errors and emit no refuse line.
|
|
45
|
+
*/
|
|
46
|
+
export declare class AttachmentRefusedError extends Error {
|
|
47
|
+
readonly reason: RefusalReason;
|
|
48
|
+
readonly file: string;
|
|
49
|
+
readonly bytes?: number | undefined;
|
|
50
|
+
readonly cap?: number | undefined;
|
|
51
|
+
constructor(message: string, reason: RefusalReason, file: string, bytes?: number | undefined, cap?: number | undefined);
|
|
52
|
+
}
|
|
30
53
|
/** A validated, account-scoped file and the Graph path it must take. */
|
|
31
54
|
export interface OutboundAttachment {
|
|
32
55
|
/** realpath, verified under the account directory. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"outbound-attachments.d.ts","sourceRoot":"","sources":["../../src/lib/outbound-attachments.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"outbound-attachments.d.ts","sourceRoot":"","sources":["../../src/lib/outbound-attachments.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAKH,6EAA6E;AAC7E,eAAO,MAAM,mCAAmC,QAAkB,CAAC;AACnE,yEAAyE;AACzE,eAAO,MAAM,4BAA4B,QAAmB,CAAC;AAE7D,MAAM,WAAW,mBAAmB;IAClC,aAAa,EAAE,iCAAiC,CAAC;IACjD,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;wDACwD;AACxD,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,UAAU,CAAC;AAEpD;;;;;;;GAOG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;IAG7C,QAAQ,CAAC,MAAM,EAAE,aAAa;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM;IACrB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM;IACvB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM;gBAJrB,OAAO,EAAE,MAAM,EACN,MAAM,EAAE,aAAa,EACrB,IAAI,EAAE,MAAM,EACZ,KAAK,CAAC,EAAE,MAAM,YAAA,EACd,GAAG,CAAC,EAAE,MAAM,YAAA;CAKxB;AAED,wEAAwE;AACxE,MAAM,WAAW,kBAAkB;IACjC,sDAAsD;IACtD,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,QAAQ,GAAG,SAAS,CAAC;CAC5B;AAqBD;wEACwE;AACxE,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQlE;AAED;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CACxC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EAAE,GAAG,SAAS,GAC1B,kBAAkB,EAAE,CA4DtB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,kBAAkB,GAAG,mBAAmB,CAO/E;AAED,4EAA4E;AAC5E,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CAGlD"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Outbound attachment resolver
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
2
|
+
* Outbound attachment resolver, shared by every tool that can send a file:
|
|
3
|
+
* outlook-mail-reply, outlook-mail-send, outlook-draft, and outlook-draft-edit.
|
|
4
|
+
* Mirrors the email plugin's account-scope check (realpath under the account
|
|
5
|
+
* directory, regular file, size cap), then classifies each file by how it must
|
|
6
|
+
* reach the draft:
|
|
6
7
|
*
|
|
7
8
|
* - `inline` — at or under Graph's ~3 MB fileAttachment limit; sent as a
|
|
8
9
|
* single base64 `POST /messages/{id}/attachments`.
|
|
@@ -10,12 +11,16 @@
|
|
|
10
11
|
* through a Graph upload session (see `upload-session.ts`).
|
|
11
12
|
*
|
|
12
13
|
* The account cap (25 MB) matches the email plugin's outbound cap, so an
|
|
13
|
-
* Outlook
|
|
14
|
+
* Outlook message and the equivalent IMAP message carry the same maximum.
|
|
14
15
|
*
|
|
15
16
|
* Resolution reads no bytes — it returns per-file metadata (path, size, mode)
|
|
16
|
-
* so
|
|
17
|
-
*
|
|
18
|
-
*
|
|
17
|
+
* so the caller can choose the path. Path validation happens before any Graph
|
|
18
|
+
* write, so a bad path leaves no orphan draft; bytes are read at send time by
|
|
19
|
+
* `toInlineAttachment` (inline) or the upload session (session).
|
|
20
|
+
*
|
|
21
|
+
* This module stays pure node:fs on purpose — the Graph-side attach loop lives
|
|
22
|
+
* in `attach.ts` so this boundary carries no client, no network, and no I/O
|
|
23
|
+
* beyond the filesystem.
|
|
19
24
|
*/
|
|
20
25
|
import { readFileSync, realpathSync, statSync } from "node:fs";
|
|
21
26
|
import { basename, extname, join } from "node:path";
|
|
@@ -23,6 +28,28 @@ import { basename, extname, join } from "node:path";
|
|
|
23
28
|
export const OUTLOOK_ATTACHMENT_INLINE_MAX_BYTES = 3 * 1024 * 1024;
|
|
24
29
|
/** Per-file account cap; parity with the email plugin's outbound cap. */
|
|
25
30
|
export const OUTLOOK_ATTACHMENT_MAX_BYTES = 25 * 1024 * 1024;
|
|
31
|
+
/**
|
|
32
|
+
* A per-path refusal, raised before any Graph write. Carries the fields the
|
|
33
|
+
* `op: "refuse"` log line names.
|
|
34
|
+
*
|
|
35
|
+
* Account-context failures (ACCOUNT_DIR unset, account directory unreadable)
|
|
36
|
+
* are NOT refusals: they name no file and no per-file cause, so they stay plain
|
|
37
|
+
* Errors and emit no refuse line.
|
|
38
|
+
*/
|
|
39
|
+
export class AttachmentRefusedError extends Error {
|
|
40
|
+
reason;
|
|
41
|
+
file;
|
|
42
|
+
bytes;
|
|
43
|
+
cap;
|
|
44
|
+
constructor(message, reason, file, bytes, cap) {
|
|
45
|
+
super(message);
|
|
46
|
+
this.reason = reason;
|
|
47
|
+
this.file = file;
|
|
48
|
+
this.bytes = bytes;
|
|
49
|
+
this.cap = cap;
|
|
50
|
+
this.name = "AttachmentRefusedError";
|
|
51
|
+
}
|
|
52
|
+
}
|
|
26
53
|
const MIME = {
|
|
27
54
|
".pdf": "application/pdf",
|
|
28
55
|
".png": "image/png",
|
|
@@ -81,19 +108,19 @@ export function resolveOutboundAttachments(accountId, paths) {
|
|
|
81
108
|
}
|
|
82
109
|
catch (err) {
|
|
83
110
|
if (err.code === "ENOENT") {
|
|
84
|
-
throw new
|
|
111
|
+
throw new AttachmentRefusedError(`Attachment not found: ${p}`, "bad-path", basename(p));
|
|
85
112
|
}
|
|
86
|
-
throw new
|
|
113
|
+
throw new AttachmentRefusedError(`Cannot read attachment ${p}: ${err instanceof Error ? err.message : String(err)}`, "bad-path", basename(p));
|
|
87
114
|
}
|
|
88
115
|
if (!rp.startsWith(accountResolved + "/")) {
|
|
89
|
-
throw new
|
|
116
|
+
throw new AttachmentRefusedError(`Attachment ${p} is outside the account directory and cannot be sent.`, "bad-path", basename(rp));
|
|
90
117
|
}
|
|
91
118
|
const st = statSync(rp);
|
|
92
119
|
if (!st.isFile()) {
|
|
93
|
-
throw new
|
|
120
|
+
throw new AttachmentRefusedError(`Attachment ${p} is not a regular file.`, "bad-path", basename(rp));
|
|
94
121
|
}
|
|
95
122
|
if (st.size > OUTLOOK_ATTACHMENT_MAX_BYTES) {
|
|
96
|
-
throw new
|
|
123
|
+
throw new AttachmentRefusedError(`Attachment ${basename(rp)} is ${(st.size / 1024 / 1024).toFixed(1)} MB; Outlook reply attachments are capped at 25 MB per file.`, "oversize", basename(rp), st.size, OUTLOOK_ATTACHMENT_MAX_BYTES);
|
|
97
124
|
}
|
|
98
125
|
out.push({
|
|
99
126
|
path: rp,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"outbound-attachments.js","sourceRoot":"","sources":["../../src/lib/outbound-attachments.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"outbound-attachments.js","sourceRoot":"","sources":["../../src/lib/outbound-attachments.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Graph upload-session path for
|
|
2
|
+
* Graph upload-session path for outbound attachments above the inline limit.
|
|
3
|
+
* Shared by every tool that attaches a file; `tool` names the caller for the
|
|
4
|
+
* Graph call tag and the error prefixes, so a stalled session is greppable back
|
|
5
|
+
* to the tool that started it.
|
|
3
6
|
*
|
|
4
7
|
* Two steps, distinct in auth and host:
|
|
5
8
|
* 1. `POST /me/messages/{draftId}/attachments/createUploadSession` — through
|
|
@@ -20,9 +23,10 @@ import type { OutboundAttachment } from "./outbound-attachments.js";
|
|
|
20
23
|
* Graph requires for every chunk except the final remainder. */
|
|
21
24
|
export declare const UPLOAD_CHUNK_BYTES: number;
|
|
22
25
|
/**
|
|
23
|
-
* Upload one large attachment to an existing
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
+
* Upload one large attachment to an existing draft via a Graph upload session.
|
|
27
|
+
* Returns the number of chunks PUT (for observability). The draft must already
|
|
28
|
+
* exist; the attachment must have passed `resolveOutboundAttachments`. `tool`
|
|
29
|
+
* names the calling tool for the Graph call tag and the error prefixes.
|
|
26
30
|
*/
|
|
27
|
-
export declare function uploadAttachmentSession(config: GraphClientConfig, draftId: string, att: OutboundAttachment): Promise<number>;
|
|
31
|
+
export declare function uploadAttachmentSession(config: GraphClientConfig, draftId: string, att: OutboundAttachment, tool: string): Promise<number>;
|
|
28
32
|
//# sourceMappingURL=upload-session.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upload-session.d.ts","sourceRoot":"","sources":["../../src/lib/upload-session.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"upload-session.d.ts","sourceRoot":"","sources":["../../src/lib/upload-session.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAE3D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAEpE;iEACiE;AACjE,eAAO,MAAM,kBAAkB,QAAkB,CAAC;AAMlD;;;;;GAKG;AACH,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE,iBAAiB,EACzB,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,kBAAkB,EACvB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,MAAM,CAAC,CAoCjB"}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Graph upload-session path for
|
|
2
|
+
* Graph upload-session path for outbound attachments above the inline limit.
|
|
3
|
+
* Shared by every tool that attaches a file; `tool` names the caller for the
|
|
4
|
+
* Graph call tag and the error prefixes, so a stalled session is greppable back
|
|
5
|
+
* to the tool that started it.
|
|
3
6
|
*
|
|
4
7
|
* Two steps, distinct in auth and host:
|
|
5
8
|
* 1. `POST /me/messages/{draftId}/attachments/createUploadSession` — through
|
|
@@ -20,15 +23,16 @@ import { postGraph } from "./graph-client.js";
|
|
|
20
23
|
* Graph requires for every chunk except the final remainder. */
|
|
21
24
|
export const UPLOAD_CHUNK_BYTES = 320 * 1024 * 10;
|
|
22
25
|
/**
|
|
23
|
-
* Upload one large attachment to an existing
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
+
* Upload one large attachment to an existing draft via a Graph upload session.
|
|
27
|
+
* Returns the number of chunks PUT (for observability). The draft must already
|
|
28
|
+
* exist; the attachment must have passed `resolveOutboundAttachments`. `tool`
|
|
29
|
+
* names the calling tool for the Graph call tag and the error prefixes.
|
|
26
30
|
*/
|
|
27
|
-
export async function uploadAttachmentSession(config, draftId, att) {
|
|
28
|
-
const { json } = await postGraph(config, `/me/messages/${encodeURIComponent(draftId)}/attachments/createUploadSession`, { AttachmentItem: { attachmentType: "file", name: att.name, size: att.size, contentType: att.contentType } }, { tool
|
|
31
|
+
export async function uploadAttachmentSession(config, draftId, att, tool) {
|
|
32
|
+
const { json } = await postGraph(config, `/me/messages/${encodeURIComponent(draftId)}/attachments/createUploadSession`, { AttachmentItem: { attachmentType: "file", name: att.name, size: att.size, contentType: att.contentType } }, { tool });
|
|
29
33
|
const uploadUrl = json?.uploadUrl;
|
|
30
34
|
if (!uploadUrl) {
|
|
31
|
-
throw new Error(`outlook
|
|
35
|
+
throw new Error(`outlook-${tool}: createUploadSession for ${att.name} returned no uploadUrl.`);
|
|
32
36
|
}
|
|
33
37
|
const buf = readFileSync(att.path);
|
|
34
38
|
const total = buf.length;
|
|
@@ -44,7 +48,7 @@ export async function uploadAttachmentSession(config, draftId, att) {
|
|
|
44
48
|
});
|
|
45
49
|
if (!res.ok) {
|
|
46
50
|
const text = await res.text().catch(() => "");
|
|
47
|
-
throw new Error(`outlook
|
|
51
|
+
throw new Error(`outlook-${tool}: upload session PUT ${res.status} for ${att.name} (bytes ${start}-${end - 1}/${total}): ${text.slice(0, 300) || "no response body"}`);
|
|
48
52
|
}
|
|
49
53
|
chunks += 1;
|
|
50
54
|
start = end;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upload-session.js","sourceRoot":"","sources":["../../src/lib/upload-session.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"upload-session.js","sourceRoot":"","sources":["../../src/lib/upload-session.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAG9C;iEACiE;AACjE,MAAM,CAAC,MAAM,kBAAkB,GAAG,GAAG,GAAG,IAAI,GAAG,EAAE,CAAC;AAMlD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,MAAyB,EACzB,OAAe,EACf,GAAuB,EACvB,IAAY;IAEZ,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,SAAS,CAC9B,MAAM,EACN,gBAAgB,kBAAkB,CAAC,OAAO,CAAC,kCAAkC,EAC7E,EAAE,cAAc,EAAE,EAAE,cAAc,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,CAAC,WAAW,EAAE,EAAE,EAC5G,EAAE,IAAI,EAAE,CACT,CAAC;IACF,MAAM,SAAS,GAAI,IAA6B,EAAE,SAAS,CAAC;IAC5D,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CACb,WAAW,IAAI,6BAA6B,GAAG,CAAC,IAAI,yBAAyB,CAC9E,CAAC;IACJ,CAAC;IAED,MAAM,GAAG,GAAG,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACnC,MAAM,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC;IACzB,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,OAAO,KAAK,GAAG,KAAK,EAAE,CAAC;QACrB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,kBAAkB,EAAE,KAAK,CAAC,CAAC;QACxD,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QACvC,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,SAAS,EAAE;YACjC,MAAM,EAAE,KAAK;YACb,OAAO,EAAE,EAAE,eAAe,EAAE,SAAS,KAAK,IAAI,GAAG,GAAG,CAAC,IAAI,KAAK,EAAE,EAAE;YAClE,IAAI,EAAE,KAAK;SACZ,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;YAC9C,MAAM,IAAI,KAAK,CACb,WAAW,IAAI,wBAAwB,GAAG,CAAC,MAAM,QAAQ,GAAG,CAAC,IAAI,WAAW,KAAK,IAAI,GAAG,GAAG,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,kBAAkB,EAAE,CACtJ,CAAC;QACJ,CAAC;QACD,MAAM,IAAI,CAAC,CAAC;QACZ,KAAK,GAAG,GAAG,CAAC;IACd,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -7,12 +7,32 @@ export interface DraftEditArgs {
|
|
|
7
7
|
subject?: string;
|
|
8
8
|
body?: string;
|
|
9
9
|
isHtml?: boolean;
|
|
10
|
+
/** Absolute paths inside the account directory. ADDITIVE — files are added to
|
|
11
|
+
* whatever the draft already carries; this tool never removes an attachment. */
|
|
12
|
+
attachments?: string[];
|
|
10
13
|
}
|
|
11
14
|
/**
|
|
12
|
-
* Update an existing draft in place via PATCH /me/messages/{draftId}
|
|
13
|
-
* drafts are mutable, so no delete-and-reappend. Only
|
|
14
|
-
*
|
|
15
|
-
*
|
|
15
|
+
* Update an existing draft in place via PATCH /me/messages/{draftId}, and/or add
|
|
16
|
+
* attachments to it. Graph drafts are mutable, so no delete-and-reappend. Only
|
|
17
|
+
* the supplied fields are patched. Graph rejects a PATCH on a sent (non-draft)
|
|
18
|
+
* message — that error is surfaced to the caller unchanged.
|
|
19
|
+
*
|
|
20
|
+
* Attachments are ADDITIVE: files are added to whatever the draft already
|
|
21
|
+
* carries. Removing or replacing an attachment is not supported here.
|
|
22
|
+
*
|
|
23
|
+
* "At least one change" counts attachments as well as patchable fields, so
|
|
24
|
+
* attaching a file to an otherwise-final draft is a valid call on its own; that
|
|
25
|
+
* case issues no PATCH at all. Paths validate before the PATCH, so a bad path
|
|
26
|
+
* leaves the draft untouched rather than half-edited.
|
|
27
|
+
*
|
|
28
|
+
* A Graph-side failure is a different matter: the PATCH and the attaches are
|
|
29
|
+
* separate calls and Graph has no transaction across them, so an attach that
|
|
30
|
+
* fails AFTER a successful PATCH leaves the field edits applied while this
|
|
31
|
+
* function throws. The caller is told the edit failed; the subject/recipients it
|
|
32
|
+
* asked for are nonetheless changed. Re-running with the same arguments is safe
|
|
33
|
+
* for the fields (PATCH is idempotent) but WILL duplicate any attachment that
|
|
34
|
+
* already landed, because attaching is additive. Only path validation is
|
|
35
|
+
* all-or-nothing here.
|
|
16
36
|
*
|
|
17
37
|
* The id in the PATCH response is authoritative for where the draft now lives,
|
|
18
38
|
* so it is returned rather than the caller's `draftId` — mirroring `runDraft`,
|
|
@@ -20,9 +40,14 @@ export interface DraftEditArgs {
|
|
|
20
40
|
* plugin-wide (IMMUTABLE_ID_PREFER), so the two normally match; returning the
|
|
21
41
|
* reported id means the tool never asserts a handle it has not confirmed, and
|
|
22
42
|
* `rotated=true` in the log makes any divergence visible (Task 1688).
|
|
43
|
+
*
|
|
44
|
+
* That is also why the attach targets the REPORTED id, not the caller's: if the
|
|
45
|
+
* id rotated, the caller's handle no longer addresses the draft and attaching to
|
|
46
|
+
* it would 404 or, worse, hit a stale item.
|
|
23
47
|
*/
|
|
24
48
|
export declare function runDraftEdit(config: GraphClientConfig, args: DraftEditArgs): Promise<{
|
|
25
49
|
draftId: string;
|
|
26
50
|
updated: true;
|
|
51
|
+
attachments: string[];
|
|
27
52
|
}>;
|
|
28
53
|
//# sourceMappingURL=draft-edit.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"draft-edit.d.ts","sourceRoot":"","sources":["../../src/tools/draft-edit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"draft-edit.d.ts","sourceRoot":"","sources":["../../src/tools/draft-edit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAKhE,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;qFACiF;IACjF,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,iBAAiB,EACzB,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,IAAI,CAAC;IAAC,WAAW,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CA8CpE"}
|
|
@@ -1,13 +1,31 @@
|
|
|
1
1
|
import { patchGraph } from "../lib/graph-client.js";
|
|
2
|
+
import { attachFilesToDraft, resolveAttachmentsOrRefuse } from "../lib/attach.js";
|
|
2
3
|
import { log } from "../lib/log.js";
|
|
3
4
|
function recip(list) {
|
|
4
5
|
return list.map((address) => ({ emailAddress: { address } }));
|
|
5
6
|
}
|
|
6
7
|
/**
|
|
7
|
-
* Update an existing draft in place via PATCH /me/messages/{draftId}
|
|
8
|
-
* drafts are mutable, so no delete-and-reappend. Only
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* Update an existing draft in place via PATCH /me/messages/{draftId}, and/or add
|
|
9
|
+
* attachments to it. Graph drafts are mutable, so no delete-and-reappend. Only
|
|
10
|
+
* the supplied fields are patched. Graph rejects a PATCH on a sent (non-draft)
|
|
11
|
+
* message — that error is surfaced to the caller unchanged.
|
|
12
|
+
*
|
|
13
|
+
* Attachments are ADDITIVE: files are added to whatever the draft already
|
|
14
|
+
* carries. Removing or replacing an attachment is not supported here.
|
|
15
|
+
*
|
|
16
|
+
* "At least one change" counts attachments as well as patchable fields, so
|
|
17
|
+
* attaching a file to an otherwise-final draft is a valid call on its own; that
|
|
18
|
+
* case issues no PATCH at all. Paths validate before the PATCH, so a bad path
|
|
19
|
+
* leaves the draft untouched rather than half-edited.
|
|
20
|
+
*
|
|
21
|
+
* A Graph-side failure is a different matter: the PATCH and the attaches are
|
|
22
|
+
* separate calls and Graph has no transaction across them, so an attach that
|
|
23
|
+
* fails AFTER a successful PATCH leaves the field edits applied while this
|
|
24
|
+
* function throws. The caller is told the edit failed; the subject/recipients it
|
|
25
|
+
* asked for are nonetheless changed. Re-running with the same arguments is safe
|
|
26
|
+
* for the fields (PATCH is idempotent) but WILL duplicate any attachment that
|
|
27
|
+
* already landed, because attaching is additive. Only path validation is
|
|
28
|
+
* all-or-nothing here.
|
|
11
29
|
*
|
|
12
30
|
* The id in the PATCH response is authoritative for where the draft now lives,
|
|
13
31
|
* so it is returned rather than the caller's `draftId` — mirroring `runDraft`,
|
|
@@ -15,6 +33,10 @@ function recip(list) {
|
|
|
15
33
|
* plugin-wide (IMMUTABLE_ID_PREFER), so the two normally match; returning the
|
|
16
34
|
* reported id means the tool never asserts a handle it has not confirmed, and
|
|
17
35
|
* `rotated=true` in the log makes any divergence visible (Task 1688).
|
|
36
|
+
*
|
|
37
|
+
* That is also why the attach targets the REPORTED id, not the caller's: if the
|
|
38
|
+
* id rotated, the caller's handle no longer addresses the draft and attaching to
|
|
39
|
+
* it would 404 or, worse, hit a stale item.
|
|
18
40
|
*/
|
|
19
41
|
export async function runDraftEdit(config, args) {
|
|
20
42
|
const patch = {};
|
|
@@ -29,24 +51,35 @@ export async function runDraftEdit(config, args) {
|
|
|
29
51
|
patch.ccRecipients = recip(args.cc);
|
|
30
52
|
if (args.bcc !== undefined)
|
|
31
53
|
patch.bccRecipients = recip(args.bcc);
|
|
32
|
-
|
|
33
|
-
|
|
54
|
+
const hasAttachments = (args.attachments?.length ?? 0) > 0;
|
|
55
|
+
if (Object.keys(patch).length === 0 && !hasAttachments) {
|
|
56
|
+
throw new Error("outlook-draft-edit: pass at least one field to change (to, cc, bcc, subject, body, or attachments).");
|
|
34
57
|
}
|
|
35
|
-
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
58
|
+
// Before any Graph write: a bad path must leave the draft untouched.
|
|
59
|
+
const files = resolveAttachmentsOrRefuse(config.accountId, args.attachments, "draft-edit");
|
|
60
|
+
let draftId = args.draftId;
|
|
61
|
+
let rotated = false;
|
|
62
|
+
if (Object.keys(patch).length > 0) {
|
|
63
|
+
const path = `/me/messages/${encodeURIComponent(args.draftId)}`;
|
|
64
|
+
const { json } = await patchGraph(config, path, patch, { tool: "draft-edit", target: path });
|
|
65
|
+
const reported = json?.id;
|
|
66
|
+
if (!reported) {
|
|
67
|
+
throw new Error("outlook-draft-edit: Graph accepted the edit but returned no id.");
|
|
68
|
+
}
|
|
69
|
+
rotated = reported !== args.draftId;
|
|
70
|
+
draftId = reported;
|
|
40
71
|
}
|
|
72
|
+
await attachFilesToDraft(config, draftId, files, "draft-edit");
|
|
41
73
|
log({
|
|
42
74
|
event: "draft-edit",
|
|
43
75
|
op: "draft-edit",
|
|
44
76
|
account: config.accountId,
|
|
45
77
|
idIn: args.draftId,
|
|
46
78
|
idOut: draftId,
|
|
47
|
-
rotated
|
|
79
|
+
rotated,
|
|
48
80
|
fields: Object.keys(patch).join(","),
|
|
81
|
+
attachments: files.length,
|
|
49
82
|
});
|
|
50
|
-
return { draftId, updated: true };
|
|
83
|
+
return { draftId, updated: true, attachments: files.map((f) => f.name) };
|
|
51
84
|
}
|
|
52
85
|
//# sourceMappingURL=draft-edit.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"draft-edit.js","sourceRoot":"","sources":["../../src/tools/draft-edit.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"draft-edit.js","sourceRoot":"","sources":["../../src/tools/draft-edit.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,15 +2,21 @@ import type { GraphClientConfig } from "../lib/graph-client.js";
|
|
|
2
2
|
import { type MessageInput } from "../lib/message.js";
|
|
3
3
|
export interface DraftResult {
|
|
4
4
|
draftId: string;
|
|
5
|
+
attachments: string[];
|
|
5
6
|
}
|
|
6
7
|
/**
|
|
7
|
-
* Create a draft via Graph `POST /me/messages
|
|
8
|
-
*
|
|
8
|
+
* Create a draft via Graph `POST /me/messages`, then attach any files to it, so
|
|
9
|
+
* the returned id names a Drafts-folder message that already carries them and is
|
|
10
|
+
* ready for outlook-draft-send.
|
|
9
11
|
*
|
|
10
12
|
* That id is durable only because the plugin opts into immutable ids
|
|
11
13
|
* (IMMUTABLE_ID_PREFER in graph-client). A regular Outlook id is NOT stable — it
|
|
12
14
|
* rotates when the item is moved or re-saved, including by the operator's own
|
|
13
15
|
* mail client, and the old value then 404s (Task 1688).
|
|
16
|
+
*
|
|
17
|
+
* Attachment paths validate BEFORE the create, so a bad path leaves no orphan
|
|
18
|
+
* draft. An attach failing Graph-side after the create does leave one; it is
|
|
19
|
+
* operator-visible in the Drafts folder — the same exposure mail-reply carries.
|
|
14
20
|
*/
|
|
15
21
|
export declare function runDraft(config: GraphClientConfig, input: MessageInput): Promise<DraftResult>;
|
|
16
22
|
//# sourceMappingURL=draft.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"draft.d.ts","sourceRoot":"","sources":["../../src/tools/draft.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAEhE,OAAO,EAAgB,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"draft.d.ts","sourceRoot":"","sources":["../../src/tools/draft.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAEhE,OAAO,EAAgB,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAIpE,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,QAAQ,CAC5B,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC,WAAW,CAAC,CAmBtB"}
|