@dawnlit/outlook-bridge 1.1.1 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/README.md +152 -183
  2. package/dist/backend.d.ts +151 -0
  3. package/dist/backend.js +3 -0
  4. package/dist/backend.js.map +1 -0
  5. package/dist/bridge.d.ts +56 -0
  6. package/dist/bridge.js +507 -0
  7. package/dist/bridge.js.map +1 -0
  8. package/dist/errors.d.ts +79 -43
  9. package/dist/errors.js +93 -52
  10. package/dist/errors.js.map +1 -1
  11. package/dist/index.d.ts +10 -10
  12. package/dist/index.js +25 -52
  13. package/dist/index.js.map +1 -1
  14. package/dist/mac/accounts.d.ts +7 -2
  15. package/dist/mac/accounts.js +23 -6
  16. package/dist/mac/accounts.js.map +1 -1
  17. package/dist/mac/attachments.d.ts +5 -25
  18. package/dist/mac/attachments.js +40 -99
  19. package/dist/mac/attachments.js.map +1 -1
  20. package/dist/mac/bounces.d.ts +12 -27
  21. package/dist/mac/bounces.js +96 -117
  22. package/dist/mac/bounces.js.map +1 -1
  23. package/dist/mac/cleanup.d.ts +11 -25
  24. package/dist/mac/cleanup.js +44 -107
  25. package/dist/mac/cleanup.js.map +1 -1
  26. package/dist/mac/drafts.d.ts +15 -34
  27. package/dist/mac/drafts.js +113 -186
  28. package/dist/mac/drafts.js.map +1 -1
  29. package/dist/mac/folders.d.ts +12 -21
  30. package/dist/mac/folders.js +44 -59
  31. package/dist/mac/folders.js.map +1 -1
  32. package/dist/mac/index.d.ts +2 -22
  33. package/dist/mac/index.js +19 -81
  34. package/dist/mac/index.js.map +1 -1
  35. package/dist/mac/profile.d.ts +13 -0
  36. package/dist/mac/profile.js +149 -0
  37. package/dist/mac/profile.js.map +1 -0
  38. package/dist/mac/read.d.ts +21 -37
  39. package/dist/mac/read.js +198 -216
  40. package/dist/mac/read.js.map +1 -1
  41. package/dist/mac/run.d.ts +51 -38
  42. package/dist/mac/run.js +138 -103
  43. package/dist/mac/run.js.map +1 -1
  44. package/dist/mac/scripts.d.ts +90 -91
  45. package/dist/mac/scripts.js +167 -126
  46. package/dist/mac/scripts.js.map +1 -1
  47. package/dist/mac/send.d.ts +10 -20
  48. package/dist/mac/send.js +99 -89
  49. package/dist/mac/send.js.map +1 -1
  50. package/dist/mac/signatures.d.ts +2 -2
  51. package/dist/mac/signatures.js +9 -11
  52. package/dist/mac/signatures.js.map +1 -1
  53. package/dist/mac/templates.d.ts +14 -26
  54. package/dist/mac/templates.js +79 -120
  55. package/dist/mac/templates.js.map +1 -1
  56. package/dist/mail.d.ts +80 -46
  57. package/dist/mail.js +179 -73
  58. package/dist/mail.js.map +1 -1
  59. package/dist/runtime.d.ts +76 -43
  60. package/dist/runtime.js +103 -48
  61. package/dist/runtime.js.map +1 -1
  62. package/dist/shared/args.d.ts +48 -0
  63. package/dist/shared/args.js +216 -0
  64. package/dist/shared/args.js.map +1 -0
  65. package/dist/shared/attachmentMatch.d.ts +26 -20
  66. package/dist/shared/attachmentMatch.js +60 -23
  67. package/dist/shared/attachmentMatch.js.map +1 -1
  68. package/dist/shared/bounceReport.d.ts +11 -0
  69. package/dist/shared/bounceReport.js +45 -0
  70. package/dist/shared/bounceReport.js.map +1 -0
  71. package/dist/shared/bounceRules.d.ts +38 -10
  72. package/dist/shared/bounceRules.js +50 -32
  73. package/dist/shared/bounceRules.js.map +1 -1
  74. package/dist/shared/exec.d.ts +21 -0
  75. package/dist/shared/exec.js +47 -0
  76. package/dist/shared/exec.js.map +1 -0
  77. package/dist/shared/json.d.ts +17 -6
  78. package/dist/shared/json.js +35 -24
  79. package/dist/shared/json.js.map +1 -1
  80. package/dist/shared/locate.d.ts +31 -0
  81. package/dist/shared/locate.js +128 -0
  82. package/dist/shared/locate.js.map +1 -0
  83. package/dist/shared/replyBody.d.ts +31 -36
  84. package/dist/shared/replyBody.js +83 -72
  85. package/dist/shared/replyBody.js.map +1 -1
  86. package/dist/shared/templateLimits.d.ts +14 -0
  87. package/dist/shared/templateLimits.js +21 -0
  88. package/dist/shared/templateLimits.js.map +1 -0
  89. package/dist/templateBody.d.ts +69 -0
  90. package/dist/{outlookTemplateSections.js → templateBody.js} +80 -73
  91. package/dist/templateBody.js.map +1 -0
  92. package/dist/types.d.ts +381 -168
  93. package/dist/types.js +8 -9
  94. package/dist/types.js.map +1 -1
  95. package/dist/windows/accounts.d.ts +7 -12
  96. package/dist/windows/accounts.js +19 -34
  97. package/dist/windows/accounts.js.map +1 -1
  98. package/dist/windows/attachments.d.ts +9 -24
  99. package/dist/windows/attachments.js +94 -119
  100. package/dist/windows/attachments.js.map +1 -1
  101. package/dist/windows/bounces.d.ts +13 -26
  102. package/dist/windows/bounces.js +168 -200
  103. package/dist/windows/bounces.js.map +1 -1
  104. package/dist/windows/cleanup.d.ts +23 -23
  105. package/dist/windows/cleanup.js +99 -113
  106. package/dist/windows/cleanup.js.map +1 -1
  107. package/dist/windows/drafts.d.ts +16 -35
  108. package/dist/windows/drafts.js +156 -253
  109. package/dist/windows/drafts.js.map +1 -1
  110. package/dist/windows/folders.d.ts +8 -13
  111. package/dist/windows/folders.js +44 -52
  112. package/dist/windows/folders.js.map +1 -1
  113. package/dist/windows/index.d.ts +2 -27
  114. package/dist/windows/index.js +11 -66
  115. package/dist/windows/index.js.map +1 -1
  116. package/dist/windows/read.d.ts +24 -60
  117. package/dist/windows/read.js +265 -306
  118. package/dist/windows/read.js.map +1 -1
  119. package/dist/windows/run.d.ts +38 -40
  120. package/dist/windows/run.js +151 -112
  121. package/dist/windows/run.js.map +1 -1
  122. package/dist/windows/scripts.d.ts +65 -55
  123. package/dist/windows/scripts.js +109 -85
  124. package/dist/windows/scripts.js.map +1 -1
  125. package/dist/windows/send.d.ts +9 -9
  126. package/dist/windows/send.js +76 -88
  127. package/dist/windows/send.js.map +1 -1
  128. package/dist/windows/signatures.d.ts +4 -10
  129. package/dist/windows/signatures.js +30 -37
  130. package/dist/windows/signatures.js.map +1 -1
  131. package/dist/windows/templates.d.ts +12 -18
  132. package/dist/windows/templates.js +117 -150
  133. package/dist/windows/templates.js.map +1 -1
  134. package/package.json +5 -4
  135. package/dist/OutlookService.d.ts +0 -43
  136. package/dist/OutlookService.js +0 -137
  137. package/dist/OutlookService.js.map +0 -1
  138. package/dist/outlookTemplateSections.d.ts +0 -62
  139. package/dist/outlookTemplateSections.js.map +0 -1
  140. package/dist/shared/capabilities.d.ts +0 -3
  141. package/dist/shared/capabilities.js +0 -9
  142. package/dist/shared/capabilities.js.map +0 -1
@@ -1,34 +1,35 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.listOutlookDrafts = listOutlookDrafts;
4
- exports.sendAllDrafts = sendAllDrafts;
5
- exports.deleteOutlookDrafts = deleteOutlookDrafts;
6
4
  exports.sendDrafts = sendDrafts;
7
- // Drafts: which ones belong to an account, and sending, listing or deleting them.
5
+ exports.deleteOutlookDrafts = deleteOutlookDrafts;
6
+ exports.sendAllDrafts = sendAllDrafts;
7
+ // Drafts: which ones belong to an account, and listing, sending or deleting them.
8
+ //
9
+ // Where Windows scans two Drafts folders and proves each item's sending
10
+ // account, macOS resolves the one Drafts folder belonging to the account —
11
+ // through the account object, or by the folder's own id for a mailbox the
12
+ // dictionary won't name (see profile.ts) — so a draft found there belongs to
13
+ // the account by construction.
8
14
  //
9
- // Where Windows has to scan two Drafts folders and prove each item's
10
- // SendUsingAccount, macOS asks the account for its own Drafts folder directly —
11
- // `drafts of targetAcct` is already account-scoped, so a draft found there
12
- // belongs to this account by construction. That is the same rule the Windows
13
- // scan reaches by a longer route, not a weaker one.
15
+ // What the folder can't vouch for is an item's own binding, which is why the
16
+ // guards compare against the requested address as a literal rather than asking
17
+ // `targetAcct`: there may be no account object to ask.
14
18
  const run_1 = require("./run");
15
19
  const scripts_1 = require("./scripts");
16
- /** The Drafts folder path this account's drafts are reported under. */
17
- function draftsPath(emailAccount) {
18
- return (0, scripts_1.macFolderPath)(emailAccount, 'Drafts', []);
19
- }
20
- /**
21
- * List the mail drafts belonging to `emailAccount`, newest first.
22
- *
23
- * Bodies are previewed, never returned whole — a templated reply body runs to
24
- * tens of thousands of characters and a folder's worth would blow the cap.
25
- */
26
- async function listOutlookDrafts(emailAccount, limit = 100, previewChars = 300) {
27
- const cap = Math.max(1, Math.floor(limit));
28
- const preview = Math.max(1, Math.floor(previewChars));
29
- const script = `tell application "Microsoft Outlook"
30
- ${(0, scripts_1.accountLookupSnippet)(emailAccount)}
31
- set draftsFolder to drafts of targetAcct
20
+ /** The account's drafts, newest first. Bodies are previewed, never returned whole. */
21
+ async function listOutlookDrafts(request) {
22
+ const acct = await (0, scripts_1.resolveMacAccount)(request.account);
23
+ const preview = request.previewChars > 0
24
+ ? ` set bodyText to ""
25
+ try
26
+ set bodyText to (plain text content of theMsg) as string
27
+ end try
28
+ if (length of bodyText) > ${(0, run_1.asInt)(request.previewChars)} then set bodyText to text 1 thru ${(0, run_1.asInt)(request.previewChars)} of bodyText`
29
+ : ' set bodyText to ""';
30
+ const raw = await (0, run_1.runOsaScript)(`tell application "Microsoft Outlook"
31
+ ${(0, scripts_1.accountLookupSnippet)(acct)}
32
+ ${(0, scripts_1.rootFolderSnippet)(acct, 'drafts', 'draftsFolder')}
32
33
  set out to ""
33
34
  repeat with theMsg in (messages of draftsFolder)
34
35
  set subj to ""
@@ -55,11 +56,7 @@ ${(0, scripts_1.accountLookupSnippet)(emailAccount)}
55
56
  end try
56
57
  end repeat
57
58
  end try
58
- set bodyText to ""
59
- try
60
- set bodyText to (plain text content of theMsg) as string
61
- end try
62
- if (length of bodyText) > ${preview} then set bodyText to text 1 thru ${preview} of bodyText
59
+ ${preview}
63
60
  set attCount to 0
64
61
  try
65
62
  set attCount to count of attachments of theMsg
@@ -68,21 +65,13 @@ ${(0, scripts_1.accountLookupSnippet)(emailAccount)}
68
65
  try
69
66
  set modAt to my isoDate(modification date of theMsg)
70
67
  end try
71
- set out to out & ${(0, run_1.asRow)([
72
- '(id of theMsg as string)',
73
- 'subj',
74
- 'my joinList(toNames, ", ")',
75
- 'my sanitizeList(toAddrs)',
76
- 'bodyText',
77
- '(attCount as string)',
78
- 'modAt',
79
- ])}
68
+ ${boundElsewhereSnippet(request.account, ' ')}
69
+ if not boundElsewhere then set out to out & ${(0, run_1.asRow)(['(id of theMsg as string)', 'subj', 'my joinList(toNames, ", ")', 'my sanitizeList(toAddrs)', 'bodyText', '(attCount as string)', 'modAt'])}
80
70
  end repeat
81
71
  return out
82
- end tell`;
83
- // One string for every row, rather than rebuilt per draft.
84
- const folderPath = draftsPath(emailAccount);
85
- const drafts = (0, run_1.splitRecords)(await (0, run_1.runOsaScript)(script, 120000)).map(record => {
72
+ end tell`, 'standard');
73
+ const folderPath = (0, scripts_1.macFolderPath)(request.account, 'Drafts', []);
74
+ const drafts = (0, run_1.splitRecords)(raw).map(record => {
86
75
  const parts = (0, run_1.splitFields)(record);
87
76
  return {
88
77
  entryId: (0, run_1.field)(parts, 0),
@@ -95,191 +84,129 @@ end tell`;
95
84
  folderPath,
96
85
  };
97
86
  });
98
- // 'yyyy-MM-dd HH:mm' is lexicographically ordered, so a string compare sorts it.
99
87
  drafts.sort((a, b) => b.lastModified.localeCompare(a.lastModified));
100
88
  return {
101
- account: emailAccount,
89
+ account: request.account,
102
90
  foldersScanned: [folderPath],
103
91
  count: drafts.length,
104
- truncated: drafts.length > cap,
105
- drafts: drafts.slice(0, cap),
92
+ truncated: drafts.length > request.limit,
93
+ drafts: drafts.slice(0, request.limit),
106
94
  };
107
95
  }
108
96
  /**
109
- * Send the mail drafts that belong to `emailAccount`.
110
- *
111
- * The ids are snapshotted before the first send: sending moves an item out of
112
- * Drafts, and mutating the collection mid-enumeration would skip every other one
113
- * — the same trap the Windows implementation avoids by snapshotting item refs.
97
+ * Set `boundElsewhere` to whether `theMsg`, a message in the account's Drafts
98
+ * folder, is set to send from some OTHER account. An unbound draft there is the
99
+ * account's own. Listing, sending all and the per-id guard all apply this one
100
+ * rule, as Windows' Test-DraftMatches is applied to all three.
114
101
  */
115
- async function sendAllDrafts(emailAccount) {
116
- const script = `tell application "Microsoft Outlook"
117
- ${(0, scripts_1.accountLookupSnippet)(emailAccount)}
118
- set draftsFolder to drafts of targetAcct
119
- set wanted to id of every message of draftsFolder
120
- set sentCount to 0
121
- set out to ""
122
- repeat with theId in wanted
123
- set subj to ""
124
- try
125
- set theMsg to missing value
126
- try
127
- set theMsg to message id theId
128
- end try
129
- if theMsg is missing value then error "draft is no longer in the Drafts folder"
130
- try
131
- set subj to (subject of theMsg) as string
132
- end try
133
- send theMsg
134
- set sentCount to sentCount + 1
135
- on error errText
136
- set out to out & ${(0, run_1.asRow)(['subj', 'errText'])}
137
- end try
138
- end repeat
139
- return ${(0, run_1.asRow)(['(sentCount as string)'])} & out
140
- end tell`;
141
- const records = (0, run_1.splitRecords)(await (0, run_1.runOsaScript)(script, 300000));
142
- return {
143
- sent: (0, run_1.intField)((0, run_1.splitFields)(records[0] || ''), 0),
144
- failed: records.slice(1).map(record => {
145
- const parts = (0, run_1.splitFields)(record);
146
- return { subject: (0, run_1.field)(parts, 0), error: (0, run_1.field)(parts, 1) };
147
- }),
148
- };
102
+ function boundElsewhereSnippet(emailAccount, indent) {
103
+ return `${indent}set boundTo to ""
104
+ ${indent}try
105
+ ${indent} set boundTo to (email address of (account of theMsg)) as string
106
+ ${indent}end try
107
+ ${indent}set boundElsewhere to (boundTo is not "" and boundTo is not ${(0, run_1.asString)(emailAccount)})`;
149
108
  }
150
109
  /**
151
- * Delete mail drafts by message id. `delete` files the item in Deleted Items
152
- * rather than destroying it, so a mistaken call stays recoverable from there —
153
- * matching the Windows contract.
154
- *
155
- * Every id must resolve to a message sitting in THIS account's Drafts folder
156
- * before anything is deleted; an id pointing at ordinary mail, or at another
157
- * account's draft, is refused and reported. Without that gate this would be a
158
- * general-purpose "delete any email by id" tool, which is not what it is for.
110
+ * The AppleScript that proves `theMsg` is one of this account's drafts before
111
+ * `verb` happens to it: it sits in the account's Drafts folder, and it is bound
112
+ * to this account or to none.
159
113
  */
160
- async function deleteOutlookDrafts(emailAccount, entryIds) {
161
- if (entryIds.length === 0)
162
- return { deleted: 0, failed: [] };
163
- const { valid, invalid } = (0, scripts_1.partitionMessageIds)(entryIds);
114
+ function ownDraftGuard(emailAccount, verb) {
115
+ return ` set inFolder to ""
116
+ try
117
+ set inFolder to (name of (folder of theMsg)) as string
118
+ end try
119
+ if inFolder is not draftsName or draftIds does not contain (id of theMsg) then error "item is not in this account's Drafts folder - refusing to ${verb}"
120
+ ${boundElsewhereSnippet(emailAccount, ' ')}
121
+ if boundElsewhere then error "draft is not bound to this account - refusing to ${verb}"`;
122
+ }
123
+ /** Run `verb` over named drafts of the account, each proved to be its own first. */
124
+ async function actOnDrafts(request, verb) {
125
+ const { valid, invalid } = (0, scripts_1.partitionMessageIds)(request.entryIds);
164
126
  if (valid.length === 0)
165
- return { deleted: 0, failed: invalid };
166
- const script = `tell application "Microsoft Outlook"
167
- ${(0, scripts_1.accountLookupSnippet)(emailAccount)}
168
- set draftsFolder to drafts of targetAcct
127
+ return { done: 0, failed: invalid };
128
+ const acct = await (0, scripts_1.resolveMacAccount)(request.account);
129
+ const raw = await (0, run_1.runOsaScript)(`tell application "Microsoft Outlook"
130
+ ${(0, scripts_1.accountLookupSnippet)(acct)}
131
+ ${(0, scripts_1.rootFolderSnippet)(acct, 'drafts', 'draftsFolder')}
169
132
  set draftsName to (name of draftsFolder) as string
170
133
  set draftIds to id of every message of draftsFolder
171
- set deletedCount to 0
134
+ set doneCount to 0
172
135
  set out to ""
173
- repeat with theId in {${valid.join(', ')}}
136
+ repeat with theId in ${(0, run_1.asIdList)(valid)}
137
+ set subj to ""
174
138
  try
175
139
  set theMsg to missing value
176
140
  try
177
141
  set theMsg to message id theId
178
142
  end try
179
143
  if theMsg is missing value then error "no such item in this account's Drafts folder"
180
- -- Prove it is in THIS account's Drafts before deleting: the folder it
181
- -- currently sits in, and the account it is bound to, must both match.
182
- set inFolder to ""
183
144
  try
184
- set inFolder to (name of (folder of theMsg)) as string
185
- end try
186
- if inFolder is not draftsName then error "item is not in this account's Drafts folder - refusing to delete"
187
- if draftIds does not contain (id of theMsg) then error "item is not in this account's Drafts folder - refusing to delete"
188
- set boundTo to ""
189
- try
190
- set boundTo to (email address of (account of theMsg)) as string
145
+ set subj to (subject of theMsg) as string
191
146
  end try
192
- if boundTo is not "" and boundTo is not (email address of targetAcct) then
193
- error "draft is not bound to this account - refusing to delete"
194
- end if
195
- delete theMsg
196
- set deletedCount to deletedCount + 1
147
+ ${ownDraftGuard(request.account, verb)}
148
+ ${verb} theMsg
149
+ set doneCount to doneCount + 1
197
150
  on error errText
198
- set out to out & ${(0, run_1.asRow)(['(theId as string)', 'errText'])}
151
+ set out to out & ${run_1.ITEM_FAILURE_ROW}
199
152
  end try
200
153
  end repeat
201
- return ${(0, run_1.asRow)(['(deletedCount as string)'])} & out
202
- end tell`;
203
- const records = (0, run_1.splitRecords)(await (0, run_1.runOsaScript)(script, 300000));
204
- return {
205
- deleted: (0, run_1.intField)((0, run_1.splitFields)(records[0] || ''), 0),
206
- failed: [
207
- ...invalid,
208
- ...records.slice(1).map(record => {
209
- const parts = (0, run_1.splitFields)(record);
210
- return { entryId: (0, run_1.field)(parts, 0), error: (0, run_1.field)(parts, 1) };
211
- }),
212
- ],
213
- };
154
+ return ${(0, run_1.asRow)(['(doneCount as string)'])} & out
155
+ end tell`, 'scan');
156
+ const { summary, failed } = (0, run_1.splitBatch)(raw);
157
+ return { done: (0, run_1.intField)(summary, 0), failed: [...invalid, ...failed] };
158
+ }
159
+ /** Send the named drafts. */
160
+ async function sendDrafts(request) {
161
+ const { done, failed } = await actOnDrafts(request, 'send');
162
+ return { sent: done, failed };
214
163
  }
215
164
  /**
216
- * Send a chosen subset of `emailAccount`'s drafts by message id — e.g. after
217
- * `listOutlookDrafts` and a user review pass — instead of `sendAllDrafts`'s
218
- * account-wide sweep.
219
- *
220
- * Same ownership gate as `deleteOutlookDrafts`: every id must resolve to a
221
- * message sitting in THIS account's Drafts folder before anything is sent. An
222
- * id pointing at ordinary mail, or at another account's draft, is refused and
223
- * reported rather than sent.
165
+ * Delete the named drafts. `delete` files an item in Deleted Items, so a
166
+ * mistaken call stays recoverable.
224
167
  */
225
- async function sendDrafts(emailAccount, entryIds) {
226
- if (entryIds.length === 0)
227
- return { sent: 0, failed: [] };
228
- const { valid, invalid } = (0, scripts_1.partitionMessageIds)(entryIds);
229
- if (valid.length === 0) {
230
- return { sent: 0, failed: invalid.map(f => ({ entryId: f.entryId, subject: '', error: f.error })) };
231
- }
232
- const script = `tell application "Microsoft Outlook"
233
- ${(0, scripts_1.accountLookupSnippet)(emailAccount)}
234
- set draftsFolder to drafts of targetAcct
235
- set draftsName to (name of draftsFolder) as string
236
- set draftIds to id of every message of draftsFolder
168
+ async function deleteOutlookDrafts(request) {
169
+ const { done, failed } = await actOnDrafts(request, 'delete');
170
+ return { deleted: done, failed };
171
+ }
172
+ /**
173
+ * Send every draft belonging to the account. The ids are snapshotted before the
174
+ * first send: sending moves an item out of Drafts, and mutating the collection
175
+ * mid-enumeration would skip every other one. A draft in the folder that is set
176
+ * to send from another account is not this account's, so it is skipped, as on
177
+ * Windows, rather than sent from that account.
178
+ */
179
+ async function sendAllDrafts(request) {
180
+ const acct = await (0, scripts_1.resolveMacAccount)(request.account);
181
+ const raw = await (0, run_1.runOsaScript)(`tell application "Microsoft Outlook"
182
+ ${(0, scripts_1.accountLookupSnippet)(acct)}
183
+ ${(0, scripts_1.rootFolderSnippet)(acct, 'drafts', 'draftsFolder')}
184
+ set wanted to id of every message of draftsFolder
237
185
  set sentCount to 0
238
186
  set out to ""
239
- repeat with theId in {${valid.join(', ')}}
187
+ repeat with theId in wanted
240
188
  set subj to ""
241
189
  try
242
190
  set theMsg to missing value
243
191
  try
244
192
  set theMsg to message id theId
245
193
  end try
246
- if theMsg is missing value then error "no such item in this account's Drafts folder"
247
- try
248
- set subj to (subject of theMsg) as string
249
- end try
250
- -- Prove it is in THIS account's Drafts before sending: the folder it
251
- -- currently sits in, and the account it is bound to, must both match.
252
- set inFolder to ""
253
- try
254
- set inFolder to (name of (folder of theMsg)) as string
255
- end try
256
- if inFolder is not draftsName then error "item is not in this account's Drafts folder - refusing to send"
257
- if draftIds does not contain (id of theMsg) then error "item is not in this account's Drafts folder - refusing to send"
258
- set boundTo to ""
259
- try
260
- set boundTo to (email address of (account of theMsg)) as string
261
- end try
262
- if boundTo is not "" and boundTo is not (email address of targetAcct) then
263
- error "draft is not bound to this account - refusing to send"
194
+ if theMsg is missing value then error "draft is no longer in the Drafts folder"
195
+ ${boundElsewhereSnippet(request.account, ' ')}
196
+ if not boundElsewhere then
197
+ try
198
+ set subj to (subject of theMsg) as string
199
+ end try
200
+ send theMsg
201
+ set sentCount to sentCount + 1
264
202
  end if
265
- send theMsg
266
- set sentCount to sentCount + 1
267
203
  on error errText
268
- set out to out & ${(0, run_1.asRow)(['(theId as string)', 'subj', 'errText'])}
204
+ set out to out & ${run_1.ITEM_FAILURE_ROW}
269
205
  end try
270
206
  end repeat
271
207
  return ${(0, run_1.asRow)(['(sentCount as string)'])} & out
272
- end tell`;
273
- const records = (0, run_1.splitRecords)(await (0, run_1.runOsaScript)(script, 300000));
274
- return {
275
- sent: (0, run_1.intField)((0, run_1.splitFields)(records[0] || ''), 0),
276
- failed: [
277
- ...invalid.map(f => ({ entryId: f.entryId, subject: '', error: f.error })),
278
- ...records.slice(1).map(record => {
279
- const parts = (0, run_1.splitFields)(record);
280
- return { entryId: (0, run_1.field)(parts, 0), subject: (0, run_1.field)(parts, 1), error: (0, run_1.field)(parts, 2) };
281
- }),
282
- ],
283
- };
208
+ end tell`, 'scan');
209
+ const { summary, failed } = (0, run_1.splitBatch)(raw);
210
+ return { sent: (0, run_1.intField)(summary, 0), failed };
284
211
  }
285
212
  //# sourceMappingURL=drafts.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"drafts.js","sourceRoot":"","sources":["../../src/mac/drafts.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"drafts.js","sourceRoot":"","sources":["../../src/mac/drafts.ts"],"names":[],"mappings":"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","sourcesContent":["// Drafts: which ones belong to an account, and listing, sending or deleting them.\n//\n// Where Windows scans two Drafts folders and proves each item's sending\n// account, macOS resolves the one Drafts folder belonging to the account —\n// through the account object, or by the folder's own id for a mailbox the\n// dictionary won't name (see profile.ts) — so a draft found there belongs to\n// the account by construction.\n//\n// What the folder can't vouch for is an item's own binding, which is why the\n// guards compare against the requested address as a literal rather than asking\n// `targetAcct`: there may be no account object to ask.\nimport {\n asIdList,\n asInt,\n asRow,\n asString,\n field,\n intField,\n ITEM_FAILURE_ROW,\n runOsaScript,\n splitBatch,\n splitFields,\n splitList,\n splitRecords,\n} from './run';\nimport {\n accountLookupSnippet,\n macFolderPath,\n partitionMessageIds,\n resolveMacAccount,\n rootFolderSnippet,\n} from './scripts';\nimport type { AccountRequest, EntryIdsRequest, ListDraftsRequest } from '../backend';\nimport type { DeleteDraftsResult, ItemFailure, ListDraftsResult, SendDraftsResult } from '../types';\n\n/** The account's drafts, newest first. Bodies are previewed, never returned whole. */\nexport async function listOutlookDrafts(request: ListDraftsRequest): Promise<ListDraftsResult> {\n const acct = await resolveMacAccount(request.account);\n const preview = request.previewChars > 0\n ? ` set bodyText to \"\"\n try\n set bodyText to (plain text content of theMsg) as string\n end try\n if (length of bodyText) > ${asInt(request.previewChars)} then set bodyText to text 1 thru ${asInt(request.previewChars)} of bodyText`\n : ' set bodyText to \"\"';\n const raw = await runOsaScript(`tell application \"Microsoft Outlook\"\n${accountLookupSnippet(acct)}\n${rootFolderSnippet(acct, 'drafts', 'draftsFolder')}\n set out to \"\"\n repeat with theMsg in (messages of draftsFolder)\n set subj to \"\"\n try\n set subj to (subject of theMsg) as string\n end try\n set toNames to {}\n set toAddrs to {}\n try\n repeat with r in (every to recipient of theMsg)\n try\n set ea to email address of r\n set oneAddr to \"\"\n set oneName to \"\"\n try\n set oneAddr to (address of ea) as string\n end try\n try\n set oneName to (name of ea) as string\n end try\n if oneName is \"\" then set oneName to oneAddr\n if oneName is not \"\" then set end of toNames to oneName\n if oneAddr is not \"\" then set end of toAddrs to oneAddr\n end try\n end repeat\n end try\n${preview}\n set attCount to 0\n try\n set attCount to count of attachments of theMsg\n end try\n set modAt to \"\"\n try\n set modAt to my isoDate(modification date of theMsg)\n end try\n${boundElsewhereSnippet(request.account, ' ')}\n if not boundElsewhere then set out to out & ${asRow(['(id of theMsg as string)', 'subj', 'my joinList(toNames, \", \")', 'my sanitizeList(toAddrs)', 'bodyText', '(attCount as string)', 'modAt'])}\n end repeat\n return out\nend tell`, 'standard');\n\n const folderPath = macFolderPath(request.account, 'Drafts', []);\n const drafts = splitRecords(raw).map(record => {\n const parts = splitFields(record);\n return {\n entryId: field(parts, 0),\n subject: field(parts, 1),\n to: field(parts, 2),\n toEmails: splitList(field(parts, 3)),\n bodyPreview: field(parts, 4).replace(/\\s+/g, ' ').trim(),\n hasAttachments: intField(parts, 5) > 0,\n lastModified: field(parts, 6),\n folderPath,\n };\n });\n drafts.sort((a, b) => b.lastModified.localeCompare(a.lastModified));\n return {\n account: request.account,\n foldersScanned: [folderPath],\n count: drafts.length,\n truncated: drafts.length > request.limit,\n drafts: drafts.slice(0, request.limit),\n };\n}\n\n/**\n * Set `boundElsewhere` to whether `theMsg`, a message in the account's Drafts\n * folder, is set to send from some OTHER account. An unbound draft there is the\n * account's own. Listing, sending all and the per-id guard all apply this one\n * rule, as Windows' Test-DraftMatches is applied to all three.\n */\nfunction boundElsewhereSnippet(emailAccount: string, indent: string): string {\n return `${indent}set boundTo to \"\"\n${indent}try\n${indent} set boundTo to (email address of (account of theMsg)) as string\n${indent}end try\n${indent}set boundElsewhere to (boundTo is not \"\" and boundTo is not ${asString(emailAccount)})`;\n}\n\n/**\n * The AppleScript that proves `theMsg` is one of this account's drafts before\n * `verb` happens to it: it sits in the account's Drafts folder, and it is bound\n * to this account or to none.\n */\nfunction ownDraftGuard(emailAccount: string, verb: 'send' | 'delete'): string {\n return ` set inFolder to \"\"\n try\n set inFolder to (name of (folder of theMsg)) as string\n end try\n if inFolder is not draftsName or draftIds does not contain (id of theMsg) then error \"item is not in this account's Drafts folder - refusing to ${verb}\"\n${boundElsewhereSnippet(emailAccount, ' ')}\n if boundElsewhere then error \"draft is not bound to this account - refusing to ${verb}\"`;\n}\n\n/** Run `verb` over named drafts of the account, each proved to be its own first. */\nasync function actOnDrafts(\n request: EntryIdsRequest,\n verb: 'send' | 'delete',\n): Promise<{ done: number; failed: ItemFailure[] }> {\n const { valid, invalid } = partitionMessageIds(request.entryIds);\n if (valid.length === 0) return { done: 0, failed: invalid };\n const acct = await resolveMacAccount(request.account);\n const raw = await runOsaScript(`tell application \"Microsoft Outlook\"\n${accountLookupSnippet(acct)}\n${rootFolderSnippet(acct, 'drafts', 'draftsFolder')}\n set draftsName to (name of draftsFolder) as string\n set draftIds to id of every message of draftsFolder\n set doneCount to 0\n set out to \"\"\n repeat with theId in ${asIdList(valid)}\n set subj to \"\"\n try\n set theMsg to missing value\n try\n set theMsg to message id theId\n end try\n if theMsg is missing value then error \"no such item in this account's Drafts folder\"\n try\n set subj to (subject of theMsg) as string\n end try\n${ownDraftGuard(request.account, verb)}\n ${verb} theMsg\n set doneCount to doneCount + 1\n on error errText\n set out to out & ${ITEM_FAILURE_ROW}\n end try\n end repeat\n return ${asRow(['(doneCount as string)'])} & out\nend tell`, 'scan');\n const { summary, failed } = splitBatch(raw);\n return { done: intField(summary, 0), failed: [...invalid, ...failed] };\n}\n\n/** Send the named drafts. */\nexport async function sendDrafts(request: EntryIdsRequest): Promise<SendDraftsResult> {\n const { done, failed } = await actOnDrafts(request, 'send');\n return { sent: done, failed };\n}\n\n/**\n * Delete the named drafts. `delete` files an item in Deleted Items, so a\n * mistaken call stays recoverable.\n */\nexport async function deleteOutlookDrafts(request: EntryIdsRequest): Promise<DeleteDraftsResult> {\n const { done, failed } = await actOnDrafts(request, 'delete');\n return { deleted: done, failed };\n}\n\n/**\n * Send every draft belonging to the account. The ids are snapshotted before the\n * first send: sending moves an item out of Drafts, and mutating the collection\n * mid-enumeration would skip every other one. A draft in the folder that is set\n * to send from another account is not this account's, so it is skipped, as on\n * Windows, rather than sent from that account.\n */\nexport async function sendAllDrafts(request: AccountRequest): Promise<SendDraftsResult> {\n const acct = await resolveMacAccount(request.account);\n const raw = await runOsaScript(`tell application \"Microsoft Outlook\"\n${accountLookupSnippet(acct)}\n${rootFolderSnippet(acct, 'drafts', 'draftsFolder')}\n set wanted to id of every message of draftsFolder\n set sentCount to 0\n set out to \"\"\n repeat with theId in wanted\n set subj to \"\"\n try\n set theMsg to missing value\n try\n set theMsg to message id theId\n end try\n if theMsg is missing value then error \"draft is no longer in the Drafts folder\"\n${boundElsewhereSnippet(request.account, ' ')}\n if not boundElsewhere then\n try\n set subj to (subject of theMsg) as string\n end try\n send theMsg\n set sentCount to sentCount + 1\n end if\n on error errText\n set out to out & ${ITEM_FAILURE_ROW}\n end try\n end repeat\n return ${asRow(['(sentCount as string)'])} & out\nend tell`, 'scan');\n const { summary, failed } = splitBatch(raw);\n return { sent: intField(summary, 0), failed };\n}\n"]}
@@ -1,28 +1,19 @@
1
+ import type { ListFoldersRequest, MoveRequest } from '../backend';
1
2
  import type { InboxFolderInfo, MoveEmailsResult } from '../types';
2
3
  /**
3
- * List the folders under an account's Inbox with their item counts.
4
- *
5
- * The recursive walk joins path segments with the LIST separator rather than a
6
- * backslash: a literal backslash would have to survive a JS template literal and
7
- * then an AppleScript string literal, and the `folderPath` shape is assembled in
8
- * TypeScript anyway (see macFolderPath).
4
+ * The folders under an account's Inbox with their message counts. Path segments
5
+ * travel joined by the LIST separator and are assembled into a folder path in
6
+ * TypeScript, rather than pushed through two layers of backslash escaping.
9
7
  */
10
- export declare function listInboxFolders(emailAccount: string, maxDepth?: number): Promise<InboxFolderInfo[]>;
8
+ export declare function listInboxFolders(request: ListFoldersRequest): Promise<InboxFolderInfo[]>;
11
9
  /**
12
- * Move emails (by message id) into any folder of the account — a filing folder
13
- * under the Inbox, or a well-known folder by name (see WELL_KNOWN_FOLDERS).
14
- *
15
- * **Moving to "Deleted Items" is how mail gets deleted reversibly**, which is why
16
- * this takes well-known roots at all: it means the destructive path and the filing
17
- * path are one tool, and the destructive one is undoable from the folder it lands in.
18
- *
19
- * `createIfMissing` builds the WHOLE missing chain, so a nested destination
20
- * ("Clients\\Acme\\2026") is one call rather than a manual mkdir first.
21
- * NOTE: moving changes a message's id — the passed ids are dead afterwards.
10
+ * File emails into a folder of the account. Moving rewrites each message's id.
22
11
  *
23
12
  * Outlook for Mac's `move` reports success even where it silently does nothing,
24
- * so the destination's message count is compared before and after. A run where
25
- * every move "succeeded" and yet the folder never grew fails loudly instead of
26
- * reporting mail that was never filed.
13
+ * so each move is confirmed by the destination growing, and one that didn't
14
+ * fails as its own item. A count compared once around the whole batch would let
15
+ * one real move cover for silent failures, and give no per-item results when it
16
+ * tripped. A message already in the destination counts as moved without being
17
+ * moved, as Windows' Move() to its own folder does.
27
18
  */
28
- export declare function moveOutlookEmails(emailAccount: string, entryIds: string[], folderName: string, createIfMissing?: boolean): Promise<MoveEmailsResult>;
19
+ export declare function moveOutlookEmails(request: MoveRequest): Promise<MoveEmailsResult>;
@@ -5,18 +5,14 @@ exports.moveOutlookEmails = moveOutlookEmails;
5
5
  // Listing the folders under an Inbox, and filing mail into one.
6
6
  const run_1 = require("./run");
7
7
  const scripts_1 = require("./scripts");
8
- const mail_1 = require("../mail");
9
8
  /**
10
- * List the folders under an account's Inbox with their item counts.
11
- *
12
- * The recursive walk joins path segments with the LIST separator rather than a
13
- * backslash: a literal backslash would have to survive a JS template literal and
14
- * then an AppleScript string literal, and the `folderPath` shape is assembled in
15
- * TypeScript anyway (see macFolderPath).
9
+ * The folders under an account's Inbox with their message counts. Path segments
10
+ * travel joined by the LIST separator and are assembled into a folder path in
11
+ * TypeScript, rather than pushed through two layers of backslash escaping.
16
12
  */
17
- async function listInboxFolders(emailAccount, maxDepth = 2) {
18
- const depth = (0, mail_1.clamp)(maxDepth, 1, 4);
19
- const script = `on walkFolders(theFolder, level, maxLevel, prefix)
13
+ async function listInboxFolders(request) {
14
+ const acct = await (0, scripts_1.resolveMacAccount)(request.account);
15
+ const raw = await (0, run_1.runOsaScript)(`on walkFolders(theFolder, level, maxLevel, prefix)
20
16
  set out to ""
21
17
  tell application "Microsoft Outlook"
22
18
  set subs to mail folders of theFolder
@@ -42,86 +38,75 @@ async function listInboxFolders(emailAccount, maxDepth = 2) {
42
38
  end walkFolders
43
39
 
44
40
  tell application "Microsoft Outlook"
45
- ${(0, scripts_1.accountLookupSnippet)(emailAccount)}
46
- set inb to inbox of targetAcct
41
+ ${(0, scripts_1.accountLookupSnippet)(acct)}
42
+ ${(0, scripts_1.rootFolderSnippet)(acct, 'inbox', 'inb')}
47
43
  end tell
48
- return my walkFolders(inb, 1, ${depth}, "")`;
49
- return (0, run_1.splitRecords)(await (0, run_1.runOsaScript)(script, 120000)).map(record => {
44
+ return my walkFolders(inb, 1, ${(0, run_1.asInt)(request.maxDepth)}, "")`, 'standard');
45
+ return (0, run_1.splitRecords)(raw).map(record => {
50
46
  const parts = (0, run_1.splitFields)(record);
51
- const segments = (0, run_1.splitList)((0, run_1.field)(parts, 1));
52
47
  return {
53
48
  name: (0, run_1.field)(parts, 0),
54
- folderPath: (0, scripts_1.macFolderPath)(emailAccount, 'Inbox', segments),
49
+ folderPath: (0, scripts_1.macFolderPath)(request.account, 'Inbox', (0, run_1.splitList)((0, run_1.field)(parts, 1))),
55
50
  itemCount: (0, run_1.intField)(parts, 2),
56
51
  depth: (0, run_1.intField)(parts, 3, 1),
57
52
  };
58
53
  });
59
54
  }
60
55
  /**
61
- * Move emails (by message id) into any folder of the account — a filing folder
62
- * under the Inbox, or a well-known folder by name (see WELL_KNOWN_FOLDERS).
63
- *
64
- * **Moving to "Deleted Items" is how mail gets deleted reversibly**, which is why
65
- * this takes well-known roots at all: it means the destructive path and the filing
66
- * path are one tool, and the destructive one is undoable from the folder it lands in.
67
- *
68
- * `createIfMissing` builds the WHOLE missing chain, so a nested destination
69
- * ("Clients\\Acme\\2026") is one call rather than a manual mkdir first.
70
- * NOTE: moving changes a message's id — the passed ids are dead afterwards.
56
+ * File emails into a folder of the account. Moving rewrites each message's id.
71
57
  *
72
58
  * Outlook for Mac's `move` reports success even where it silently does nothing,
73
- * so the destination's message count is compared before and after. A run where
74
- * every move "succeeded" and yet the folder never grew fails loudly instead of
75
- * reporting mail that was never filed.
59
+ * so each move is confirmed by the destination growing, and one that didn't
60
+ * fails as its own item. A count compared once around the whole batch would let
61
+ * one real move cover for silent failures, and give no per-item results when it
62
+ * tripped. A message already in the destination counts as moved without being
63
+ * moved, as Windows' Move() to its own folder does.
76
64
  */
77
- async function moveOutlookEmails(emailAccount, entryIds, folderName, createIfMissing = false) {
78
- if (entryIds.length === 0) {
79
- return { folderPath: '', folderCreated: false, moved: 0, failed: [] };
80
- }
81
- const ref = (0, mail_1.mailFolderRef)(folderName);
82
- const { valid, invalid } = (0, scripts_1.partitionMessageIds)(entryIds);
83
- const folderPath = (0, scripts_1.macFolderPath)(emailAccount, ref.rootLabel, ref.segments);
84
- if (valid.length === 0) {
65
+ async function moveOutlookEmails(request) {
66
+ const folderPath = (0, scripts_1.macFolderPath)(request.account, request.folder.rootLabel, request.folder.segments);
67
+ const { valid, invalid } = (0, scripts_1.partitionMessageIds)(request.entryIds);
68
+ if (valid.length === 0)
85
69
  return { folderPath, folderCreated: false, moved: 0, failed: invalid };
86
- }
87
- const script = `tell application "Microsoft Outlook"
88
- ${(0, scripts_1.accountLookupSnippet)(emailAccount)}
89
- ${(0, scripts_1.mailScopeSnippet)(ref, folderName, createIfMissing)}
90
- set countBefore to count of messages of scopeFolder
70
+ const acct = await (0, scripts_1.resolveMacAccount)(request.account);
71
+ const raw = await (0, run_1.runOsaScript)(`tell application "Microsoft Outlook"
72
+ ${(0, scripts_1.accountLookupSnippet)(acct)}
73
+ ${(0, scripts_1.mailScopeSnippet)(acct, request.folder, request.folderLabel, request.createIfMissing)}
74
+ set scopeId to id of scopeFolder
91
75
  set movedCount to 0
92
76
  set out to ""
93
- repeat with theId in {${valid.join(', ')}}
77
+ repeat with theId in ${(0, run_1.asIdList)(valid)}
78
+ set subj to ""
94
79
  try
95
80
  set theMsg to missing value
96
81
  try
97
82
  set theMsg to message id theId
98
83
  end try
99
84
  if theMsg is missing value then error "no message with that id in this Outlook"
100
- move theMsg to scopeFolder
85
+ try
86
+ set subj to (subject of theMsg) as string
87
+ end try
88
+ set fromId to missing value
89
+ try
90
+ set fromId to id of (folder of theMsg)
91
+ end try
92
+ if fromId is not scopeId then
93
+ set countBefore to count of messages of scopeFolder
94
+ move theMsg to scopeFolder
95
+ if (count of messages of scopeFolder) is not greater than countBefore then error "Outlook reported the move but '" & (name of scopeFolder) & "' did not grow - not filed"
96
+ end if
101
97
  set movedCount to movedCount + 1
102
98
  on error errText
103
- set out to out & ${(0, run_1.asRow)(['(theId as string)', 'errText'])}
99
+ set out to out & ${run_1.ITEM_FAILURE_ROW}
104
100
  end try
105
101
  end repeat
106
- set countAfter to count of messages of scopeFolder
107
- if movedCount > 0 and countAfter is not greater than countBefore then
108
- error "Outlook reported " & (movedCount as string) & " move(s) but '" & (name of scopeFolder) & "' did not grow - nothing was filed."
109
- end if
110
102
  return ${(0, run_1.asRow)(['(movedCount as string)', '(scopeCreated as string)'])} & out
111
- end tell`;
112
- const records = (0, run_1.splitRecords)(await (0, run_1.runOsaScript)(script, 300000));
113
- const summary = (0, run_1.splitFields)(records[0] || '');
103
+ end tell`, 'scan');
104
+ const { summary, failed } = (0, run_1.splitBatch)(raw);
114
105
  return {
115
106
  folderPath,
116
107
  folderCreated: (0, run_1.boolField)(summary, 1),
117
108
  moved: (0, run_1.intField)(summary, 0),
118
- failed: [
119
- ...invalid,
120
- ...records.slice(1).map(record => {
121
- const parts = (0, run_1.splitFields)(record);
122
- return { entryId: (0, run_1.field)(parts, 0), error: (0, run_1.field)(parts, 1) };
123
- }),
124
- ],
109
+ failed: [...invalid, ...failed],
125
110
  };
126
111
  }
127
112
  //# sourceMappingURL=folders.js.map