@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.
Files changed (116) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/lib/storage-broker/dist/__tests__/cf-exec.test.js +188 -3
  3. package/payload/platform/lib/storage-broker/dist/__tests__/cf-exec.test.js.map +1 -1
  4. package/payload/platform/lib/storage-broker/dist/__tests__/object-limits.test.d.ts +2 -0
  5. package/payload/platform/lib/storage-broker/dist/__tests__/object-limits.test.d.ts.map +1 -0
  6. package/payload/platform/lib/storage-broker/dist/__tests__/object-limits.test.js +59 -0
  7. package/payload/platform/lib/storage-broker/dist/__tests__/object-limits.test.js.map +1 -0
  8. package/payload/platform/lib/storage-broker/dist/cf-exec.d.ts +12 -1
  9. package/payload/platform/lib/storage-broker/dist/cf-exec.d.ts.map +1 -1
  10. package/payload/platform/lib/storage-broker/dist/cf-exec.js +97 -0
  11. package/payload/platform/lib/storage-broker/dist/cf-exec.js.map +1 -1
  12. package/payload/platform/lib/storage-broker/dist/house-credential.d.ts.map +1 -1
  13. package/payload/platform/lib/storage-broker/dist/house-credential.js +4 -2
  14. package/payload/platform/lib/storage-broker/dist/house-credential.js.map +1 -1
  15. package/payload/platform/lib/storage-broker/dist/index.d.ts +1 -0
  16. package/payload/platform/lib/storage-broker/dist/index.d.ts.map +1 -1
  17. package/payload/platform/lib/storage-broker/dist/index.js +1 -0
  18. package/payload/platform/lib/storage-broker/dist/index.js.map +1 -1
  19. package/payload/platform/lib/storage-broker/dist/object-limits.d.ts +53 -0
  20. package/payload/platform/lib/storage-broker/dist/object-limits.d.ts.map +1 -0
  21. package/payload/platform/lib/storage-broker/dist/object-limits.js +72 -0
  22. package/payload/platform/lib/storage-broker/dist/object-limits.js.map +1 -0
  23. package/payload/platform/lib/storage-broker/src/__tests__/cf-exec.test.ts +211 -5
  24. package/payload/platform/lib/storage-broker/src/__tests__/object-limits.test.ts +76 -0
  25. package/payload/platform/lib/storage-broker/src/cf-exec.ts +148 -6
  26. package/payload/platform/lib/storage-broker/src/house-credential.ts +4 -2
  27. package/payload/platform/lib/storage-broker/src/index.ts +1 -0
  28. package/payload/platform/lib/storage-broker/src/object-limits.ts +75 -0
  29. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +5 -5
  30. package/payload/platform/plugins/cloudflare/bin/cf-token.sh +4 -3
  31. package/payload/platform/plugins/cloudflare/references/api.md +1 -1
  32. package/payload/platform/plugins/docs/references/outlook-guide.md +4 -4
  33. package/payload/platform/plugins/outlook/.claude-plugin/plugin.json +1 -1
  34. package/payload/platform/plugins/outlook/PLUGIN.md +2 -2
  35. package/payload/platform/plugins/outlook/mcp/dist/__tests__/attach.test.d.ts +2 -0
  36. package/payload/platform/plugins/outlook/mcp/dist/__tests__/attach.test.d.ts.map +1 -0
  37. package/payload/platform/plugins/outlook/mcp/dist/__tests__/attach.test.js +138 -0
  38. package/payload/platform/plugins/outlook/mcp/dist/__tests__/attach.test.js.map +1 -0
  39. package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-attachments.test.d.ts +2 -0
  40. package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-attachments.test.d.ts.map +1 -0
  41. package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-attachments.test.js +121 -0
  42. package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-attachments.test.js.map +1 -0
  43. package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-edit-attachments.test.d.ts +2 -0
  44. package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-edit-attachments.test.d.ts.map +1 -0
  45. package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-edit-attachments.test.js +102 -0
  46. package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-edit-attachments.test.js.map +1 -0
  47. package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-edit.test.js +1 -1
  48. package/payload/platform/plugins/outlook/mcp/dist/__tests__/draft-edit.test.js.map +1 -1
  49. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-send-attachments.test.d.ts +2 -0
  50. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-send-attachments.test.d.ts.map +1 -0
  51. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-send-attachments.test.js +209 -0
  52. package/payload/platform/plugins/outlook/mcp/dist/__tests__/mail-send-attachments.test.js.map +1 -0
  53. package/payload/platform/plugins/outlook/mcp/dist/index.js +10 -7
  54. package/payload/platform/plugins/outlook/mcp/dist/index.js.map +1 -1
  55. package/payload/platform/plugins/outlook/mcp/dist/lib/attach.d.ts +37 -0
  56. package/payload/platform/plugins/outlook/mcp/dist/lib/attach.d.ts.map +1 -0
  57. package/payload/platform/plugins/outlook/mcp/dist/lib/attach.js +79 -0
  58. package/payload/platform/plugins/outlook/mcp/dist/lib/attach.js.map +1 -0
  59. package/payload/platform/plugins/outlook/mcp/dist/lib/message.d.ts +8 -0
  60. package/payload/platform/plugins/outlook/mcp/dist/lib/message.d.ts.map +1 -1
  61. package/payload/platform/plugins/outlook/mcp/dist/lib/message.js +4 -0
  62. package/payload/platform/plugins/outlook/mcp/dist/lib/message.js.map +1 -1
  63. package/payload/platform/plugins/outlook/mcp/dist/lib/outbound-attachments.d.ts +31 -8
  64. package/payload/platform/plugins/outlook/mcp/dist/lib/outbound-attachments.d.ts.map +1 -1
  65. package/payload/platform/plugins/outlook/mcp/dist/lib/outbound-attachments.js +40 -13
  66. package/payload/platform/plugins/outlook/mcp/dist/lib/outbound-attachments.js.map +1 -1
  67. package/payload/platform/plugins/outlook/mcp/dist/lib/upload-session.d.ts +9 -5
  68. package/payload/platform/plugins/outlook/mcp/dist/lib/upload-session.d.ts.map +1 -1
  69. package/payload/platform/plugins/outlook/mcp/dist/lib/upload-session.js +12 -8
  70. package/payload/platform/plugins/outlook/mcp/dist/lib/upload-session.js.map +1 -1
  71. package/payload/platform/plugins/outlook/mcp/dist/tools/draft-edit.d.ts +29 -4
  72. package/payload/platform/plugins/outlook/mcp/dist/tools/draft-edit.d.ts.map +1 -1
  73. package/payload/platform/plugins/outlook/mcp/dist/tools/draft-edit.js +46 -13
  74. package/payload/platform/plugins/outlook/mcp/dist/tools/draft-edit.js.map +1 -1
  75. package/payload/platform/plugins/outlook/mcp/dist/tools/draft.d.ts +8 -2
  76. package/payload/platform/plugins/outlook/mcp/dist/tools/draft.d.ts.map +1 -1
  77. package/payload/platform/plugins/outlook/mcp/dist/tools/draft.js +13 -4
  78. package/payload/platform/plugins/outlook/mcp/dist/tools/draft.js.map +1 -1
  79. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-reply.d.ts.map +1 -1
  80. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-reply.js +3 -20
  81. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-reply.js.map +1 -1
  82. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-send.d.ts +27 -3
  83. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-send.d.ts.map +1 -1
  84. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-send.js +53 -8
  85. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-send.js.map +1 -1
  86. package/payload/platform/plugins/outlook/references/graph-surfaces.md +29 -6
  87. package/payload/platform/plugins/outlook/skills/outlook/SKILL.md +22 -5
  88. package/payload/platform/plugins/storage-broker/PLUGIN.md +41 -2
  89. package/payload/platform/plugins/storage-broker/mcp/dist/__tests__/confine-path.test.d.ts +2 -0
  90. package/payload/platform/plugins/storage-broker/mcp/dist/__tests__/confine-path.test.d.ts.map +1 -0
  91. package/payload/platform/plugins/storage-broker/mcp/dist/__tests__/confine-path.test.js +85 -0
  92. package/payload/platform/plugins/storage-broker/mcp/dist/__tests__/confine-path.test.js.map +1 -0
  93. package/payload/platform/plugins/storage-broker/mcp/dist/__tests__/put-source.test.d.ts +2 -0
  94. package/payload/platform/plugins/storage-broker/mcp/dist/__tests__/put-source.test.d.ts.map +1 -0
  95. package/payload/platform/plugins/storage-broker/mcp/dist/__tests__/put-source.test.js +77 -0
  96. package/payload/platform/plugins/storage-broker/mcp/dist/__tests__/put-source.test.js.map +1 -0
  97. package/payload/platform/plugins/storage-broker/mcp/dist/confine-path.d.ts +12 -0
  98. package/payload/platform/plugins/storage-broker/mcp/dist/confine-path.d.ts.map +1 -0
  99. package/payload/platform/plugins/storage-broker/mcp/dist/confine-path.js +107 -0
  100. package/payload/platform/plugins/storage-broker/mcp/dist/confine-path.js.map +1 -0
  101. package/payload/platform/plugins/storage-broker/mcp/dist/index.js +86 -0
  102. package/payload/platform/plugins/storage-broker/mcp/dist/index.js.map +1 -1
  103. package/payload/platform/plugins/storage-broker/mcp/dist/put-source.d.ts +11 -0
  104. package/payload/platform/plugins/storage-broker/mcp/dist/put-source.d.ts.map +1 -0
  105. package/payload/platform/plugins/storage-broker/mcp/dist/put-source.js +35 -0
  106. package/payload/platform/plugins/storage-broker/mcp/dist/put-source.js.map +1 -0
  107. package/payload/platform/scripts/logs-read-jsonl.test.sh +118 -0
  108. package/payload/platform/scripts/logs-read.sh +63 -9
  109. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
  110. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +4 -0
  111. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
  112. package/payload/server/{chunk-F4D35LKL.js → chunk-POBXIHOF.js} +34 -0
  113. package/payload/server/{chunk-64FGYKNZ.js → chunk-Q6W4U6HL.js} +104 -0
  114. package/payload/server/maxy-edge.js +1 -1
  115. package/payload/server/server.js +206 -6
  116. 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;;;;GAIG;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;CAClB;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"}
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;;;;GAIG;AAuBH,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
+ {"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 for outlook-mail-reply. Mirrors the email
3
- * plugin's account-scope check (realpath under the account directory, regular
4
- * file, size cap), then classifies each file by how it must reach the reply
5
- * draft:
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 reply and the equivalent IMAP reply carry the same maximum.
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 `mail-reply` can choose the path. Path validation still happens before any
17
- * Graph write, so a bad path leaves no orphan draft; bytes are read at send
18
- * time by `toInlineAttachment` (inline) or the upload session (session).
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;;;;;;;;;;;;;;;;;;GAkBG;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,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,CAgDtB;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
+ {"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 for outlook-mail-reply. Mirrors the email
3
- * plugin's account-scope check (realpath under the account directory, regular
4
- * file, size cap), then classifies each file by how it must reach the reply
5
- * draft:
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 reply and the equivalent IMAP reply carry the same maximum.
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 `mail-reply` can choose the path. Path validation still happens before any
17
- * Graph write, so a bad path leaves no orphan draft; bytes are read at send
18
- * time by `toInlineAttachment` (inline) or the upload session (session).
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 Error(`Attachment not found: ${p}`);
111
+ throw new AttachmentRefusedError(`Attachment not found: ${p}`, "bad-path", basename(p));
85
112
  }
86
- throw new Error(`Cannot read attachment ${p}: ${err instanceof Error ? err.message : String(err)}`);
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 Error(`Attachment ${p} is outside the account directory and cannot be sent.`);
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 Error(`Attachment ${p} is not a regular file.`);
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 Error(`Attachment ${basename(rp)} is ${(st.size / 1024 / 1024).toFixed(1)} MB; Outlook reply attachments are capped at 25 MB per file.`);
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":"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"}
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 reply attachments above the inline limit.
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 reply draft via a Graph upload
24
- * session. Returns the number of chunks PUT (for observability). The draft must
25
- * already exist; the attachment must have passed `resolveOutboundAttachments`.
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;;;;;;;;;;;;;;;GAeG;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;;;;GAIG;AACH,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE,iBAAiB,EACzB,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,kBAAkB,GACtB,OAAO,CAAC,MAAM,CAAC,CAoCjB"}
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 reply attachments above the inline limit.
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 reply draft via a Graph upload
24
- * session. Returns the number of chunks PUT (for observability). The draft must
25
- * already exist; the attachment must have passed `resolveOutboundAttachments`.
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: "mail-reply" });
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-mail-reply: createUploadSession for ${att.name} returned no uploadUrl.`);
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-mail-reply: upload session PUT ${res.status} for ${att.name} (bytes ${start}-${end - 1}/${total}): ${text.slice(0, 300) || "no response body"}`);
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;;;;;;;;;;;;;;;GAeG;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;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,MAAyB,EACzB,OAAe,EACf,GAAuB;IAEvB,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,YAAY,EAAE,CACvB,CAAC;IACF,MAAM,SAAS,GAAI,IAA6B,EAAE,SAAS,CAAC;IAC5D,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CACb,+CAA+C,GAAG,CAAC,IAAI,yBAAyB,CACjF,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,0CAA0C,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,CACzJ,CAAC;QACJ,CAAC;QACD,MAAM,IAAI,CAAC,CAAC;QACZ,KAAK,GAAG,GAAG,CAAC;IACd,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
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}. Graph
13
- * drafts are mutable, so no delete-and-reappend. Only the supplied fields are
14
- * patched; at least one editable field is required. Graph rejects a PATCH on a
15
- * sent (non-draft) message — that error is surfaced to the caller unchanged.
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;AAIhE,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;CAClB;AAMD;;;;;;;;;;;;GAYG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,iBAAiB,EACzB,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,IAAI,CAAA;CAAE,CAAC,CAgC7C"}
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}. Graph
8
- * drafts are mutable, so no delete-and-reappend. Only the supplied fields are
9
- * patched; at least one editable field is required. Graph rejects a PATCH on a
10
- * sent (non-draft) message — that error is surfaced to the caller unchanged.
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
- if (Object.keys(patch).length === 0) {
33
- throw new Error("outlook-draft-edit: pass at least one field to change (to, cc, bcc, subject, or body).");
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
- const path = `/me/messages/${encodeURIComponent(args.draftId)}`;
36
- const { json } = await patchGraph(config, path, patch, { tool: "draft-edit", target: path });
37
- const draftId = json?.id;
38
- if (!draftId) {
39
- throw new Error("outlook-draft-edit: Graph accepted the edit but returned no id.");
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: draftId !== args.draftId,
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;AAYpC,SAAS,KAAK,CAAC,IAAc;IAC3B,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,EAAE,YAAY,EAAE,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAChE,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,MAAyB,EACzB,IAAmB;IAEnB,MAAM,KAAK,GAA4B,EAAE,CAAC;IAC1C,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS;QAAE,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;IAC7D,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC5B,KAAK,CAAC,IAAI,GAAG,EAAE,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;IAClF,CAAC;IACD,IAAI,IAAI,CAAC,EAAE,KAAK,SAAS;QAAE,KAAK,CAAC,YAAY,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC/D,IAAI,IAAI,CAAC,EAAE,KAAK,SAAS;QAAE,KAAK,CAAC,YAAY,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC/D,IAAI,IAAI,CAAC,GAAG,KAAK,SAAS;QAAE,KAAK,CAAC,aAAa,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAElE,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACpC,MAAM,IAAI,KAAK,CACb,wFAAwF,CACzF,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,gBAAgB,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;IAChE,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,UAAU,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7F,MAAM,OAAO,GAAI,IAA+B,EAAE,EAAE,CAAC;IACrD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,iEAAiE,CAAC,CAAC;IACrF,CAAC;IACD,GAAG,CAAC;QACF,KAAK,EAAE,YAAY;QACnB,EAAE,EAAE,YAAY;QAChB,OAAO,EAAE,MAAM,CAAC,SAAS;QACzB,IAAI,EAAE,IAAI,CAAC,OAAO;QAClB,KAAK,EAAE,OAAO;QACd,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC,OAAO;QACjC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;KACrC,CAAC,CAAC;IACH,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AACpC,CAAC"}
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,kBAAkB,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAClF,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAepC,SAAS,KAAK,CAAC,IAAc;IAC3B,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,EAAE,YAAY,EAAE,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAChE,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,MAAyB,EACzB,IAAmB;IAEnB,MAAM,KAAK,GAA4B,EAAE,CAAC;IAC1C,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS;QAAE,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;IAC7D,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC5B,KAAK,CAAC,IAAI,GAAG,EAAE,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;IAClF,CAAC;IACD,IAAI,IAAI,CAAC,EAAE,KAAK,SAAS;QAAE,KAAK,CAAC,YAAY,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC/D,IAAI,IAAI,CAAC,EAAE,KAAK,SAAS;QAAE,KAAK,CAAC,YAAY,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC/D,IAAI,IAAI,CAAC,GAAG,KAAK,SAAS;QAAE,KAAK,CAAC,aAAa,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAElE,MAAM,cAAc,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;IAC3D,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC;QACvD,MAAM,IAAI,KAAK,CACb,qGAAqG,CACtG,CAAC;IACJ,CAAC;IAED,qEAAqE;IACrE,MAAM,KAAK,GAAG,0BAA0B,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;IAE3F,IAAI,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;IAC3B,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClC,MAAM,IAAI,GAAG,gBAAgB,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QAChE,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,UAAU,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7F,MAAM,QAAQ,GAAI,IAA+B,EAAE,EAAE,CAAC;QACtD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,KAAK,CAAC,iEAAiE,CAAC,CAAC;QACrF,CAAC;QACD,OAAO,GAAG,QAAQ,KAAK,IAAI,CAAC,OAAO,CAAC;QACpC,OAAO,GAAG,QAAQ,CAAC;IACrB,CAAC;IAED,MAAM,kBAAkB,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC;IAE/D,GAAG,CAAC;QACF,KAAK,EAAE,YAAY;QACnB,EAAE,EAAE,YAAY;QAChB,OAAO,EAAE,MAAM,CAAC,SAAS;QACzB,IAAI,EAAE,IAAI,CAAC,OAAO;QAClB,KAAK,EAAE,OAAO;QACd,OAAO;QACP,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;QACpC,WAAW,EAAE,KAAK,CAAC,MAAM;KAC1B,CAAC,CAAC;IACH,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;AAC3E,CAAC"}
@@ -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`. Graph returns 201 with the
8
- * created message, whose `id` is the handle passed to outlook-draft-send.
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;AAGpE,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;GAQG;AACH,wBAAsB,QAAQ,CAC5B,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC,WAAW,CAAC,CAgBtB"}
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"}