@dawnlit/outlook-bridge 1.1.1 → 2.0.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 (139) hide show
  1. package/README.md +150 -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 +81 -43
  9. package/dist/errors.js +98 -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 +95 -112
  22. package/dist/mac/bounces.js.map +1 -1
  23. package/dist/mac/cleanup.d.ts +11 -25
  24. package/dist/mac/cleanup.js +50 -76
  25. package/dist/mac/cleanup.js.map +1 -1
  26. package/dist/mac/drafts.d.ts +13 -34
  27. package/dist/mac/drafts.js +95 -169
  28. package/dist/mac/drafts.js.map +1 -1
  29. package/dist/mac/folders.d.ts +10 -21
  30. package/dist/mac/folders.js +33 -47
  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 +18 -38
  39. package/dist/mac/read.js +154 -210
  40. package/dist/mac/read.js.map +1 -1
  41. package/dist/mac/run.d.ts +35 -39
  42. package/dist/mac/run.js +97 -102
  43. package/dist/mac/run.js.map +1 -1
  44. package/dist/mac/scripts.d.ts +78 -86
  45. package/dist/mac/scripts.js +125 -115
  46. package/dist/mac/scripts.js.map +1 -1
  47. package/dist/mac/send.d.ts +10 -20
  48. package/dist/mac/send.js +64 -86
  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 +75 -113
  55. package/dist/mac/templates.js.map +1 -1
  56. package/dist/mail.d.ts +77 -45
  57. package/dist/mail.js +166 -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 +28 -16
  66. package/dist/shared/attachmentMatch.js +60 -22
  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 +12 -6
  78. package/dist/shared/json.js +29 -23
  79. package/dist/shared/json.js.map +1 -1
  80. package/dist/shared/locate.d.ts +39 -0
  81. package/dist/shared/locate.js +129 -0
  82. package/dist/shared/locate.js.map +1 -0
  83. package/dist/shared/replyBody.d.ts +42 -32
  84. package/dist/shared/replyBody.js +84 -71
  85. package/dist/shared/replyBody.js.map +1 -1
  86. package/dist/templateBody.d.ts +63 -0
  87. package/dist/{outlookTemplateSections.js → templateBody.js} +72 -72
  88. package/dist/templateBody.js.map +1 -0
  89. package/dist/types.d.ts +360 -167
  90. package/dist/types.js +8 -9
  91. package/dist/types.js.map +1 -1
  92. package/dist/windows/accounts.d.ts +7 -12
  93. package/dist/windows/accounts.js +19 -34
  94. package/dist/windows/accounts.js.map +1 -1
  95. package/dist/windows/attachments.d.ts +9 -24
  96. package/dist/windows/attachments.js +94 -119
  97. package/dist/windows/attachments.js.map +1 -1
  98. package/dist/windows/bounces.d.ts +13 -26
  99. package/dist/windows/bounces.js +168 -200
  100. package/dist/windows/bounces.js.map +1 -1
  101. package/dist/windows/cleanup.d.ts +19 -23
  102. package/dist/windows/cleanup.js +92 -111
  103. package/dist/windows/cleanup.js.map +1 -1
  104. package/dist/windows/drafts.d.ts +16 -35
  105. package/dist/windows/drafts.js +167 -253
  106. package/dist/windows/drafts.js.map +1 -1
  107. package/dist/windows/folders.d.ts +8 -13
  108. package/dist/windows/folders.js +44 -52
  109. package/dist/windows/folders.js.map +1 -1
  110. package/dist/windows/index.d.ts +2 -27
  111. package/dist/windows/index.js +11 -66
  112. package/dist/windows/index.js.map +1 -1
  113. package/dist/windows/read.d.ts +24 -60
  114. package/dist/windows/read.js +261 -306
  115. package/dist/windows/read.js.map +1 -1
  116. package/dist/windows/run.d.ts +39 -39
  117. package/dist/windows/run.js +151 -111
  118. package/dist/windows/run.js.map +1 -1
  119. package/dist/windows/scripts.d.ts +65 -55
  120. package/dist/windows/scripts.js +109 -85
  121. package/dist/windows/scripts.js.map +1 -1
  122. package/dist/windows/send.d.ts +6 -11
  123. package/dist/windows/send.js +68 -88
  124. package/dist/windows/send.js.map +1 -1
  125. package/dist/windows/signatures.d.ts +4 -10
  126. package/dist/windows/signatures.js +30 -37
  127. package/dist/windows/signatures.js.map +1 -1
  128. package/dist/windows/templates.d.ts +12 -18
  129. package/dist/windows/templates.js +122 -149
  130. package/dist/windows/templates.js.map +1 -1
  131. package/package.json +4 -3
  132. package/dist/OutlookService.d.ts +0 -43
  133. package/dist/OutlookService.js +0 -137
  134. package/dist/OutlookService.js.map +0 -1
  135. package/dist/outlookTemplateSections.d.ts +0 -62
  136. package/dist/outlookTemplateSections.js.map +0 -1
  137. package/dist/shared/capabilities.d.ts +0 -3
  138. package/dist/shared/capabilities.js +0 -9
  139. package/dist/shared/capabilities.js.map +0 -1
@@ -0,0 +1,56 @@
1
+ import type { Backend } from './backend';
2
+ import { type BridgeOptions, type ResolvedConfig } from './runtime';
3
+ import type { BridgeCapability, CapabilityMap, OutlookBridge } from './types';
4
+ export declare const OPERATIONS: readonly (keyof OutlookBridge)[];
5
+ /**
6
+ * The operations over one backend. A null backend is a platform without Outlook
7
+ * automation: every operation rejects with UNSUPPORTED_PLATFORM before looking
8
+ * at its arguments, since nothing about them could make it work.
9
+ */
10
+ export declare function createOperations(backendOrNull: Backend | null): OutlookBridge;
11
+ /**
12
+ * A bridge carrying its own settings, plus capability discovery.
13
+ *
14
+ * The exported functions are the same operations under the process-wide
15
+ * settings; an instance is what to use when the process holds more than one
16
+ * caller, or when a call needs its own timeout or AbortSignal.
17
+ */
18
+ export interface OutlookBridgeInstance extends OutlookBridge {
19
+ /** The settings this bridge runs with. */
20
+ readonly options: ResolvedConfig;
21
+ /** Which operations work on this machine. */
22
+ capabilities(): CapabilityMap;
23
+ /** Whether one operation works on this machine. */
24
+ supports(operation: BridgeCapability): boolean;
25
+ /**
26
+ * A bridge like this one with some settings changed — how one call gets its
27
+ * own budget or cancellation: `bridge.withOptions({ signal }).readInboxEmails(...)`.
28
+ */
29
+ withOptions(options: BridgeOptions): OutlookBridgeInstance;
30
+ }
31
+ /**
32
+ * A bridge over `backend` whose every call runs with `config` in force.
33
+ *
34
+ * The platform code reads settings through `getConfig()`, so the config is put
35
+ * in place around each call rather than passed into it: `withConfig` scopes it
36
+ * to the call's whole async subtree, which is why two bridges with different
37
+ * settings can run concurrently without seeing each other's.
38
+ */
39
+ export declare function createBridge(backend: Backend | null, config: ResolvedConfig): OutlookBridgeInstance;
40
+ /**
41
+ * A bridge with its own settings, isolated from `configure()` and from every
42
+ * other bridge. Options left out take the process-wide values as they stand
43
+ * when this is called.
44
+ *
45
+ * ```ts
46
+ * const outlook = createOutlookBridge({ timeoutMs: 30_000 });
47
+ * const recent = await outlook.readInboxEmails('me@example.com', { daysBack: 7 });
48
+ * ```
49
+ */
50
+ export declare function createOutlookBridge(options?: BridgeOptions): OutlookBridgeInstance;
51
+ /** Which operations work on this machine: all of them on Windows and macOS, none elsewhere. */
52
+ export declare function capabilities(): CapabilityMap;
53
+ /** Whether one operation works on this machine. */
54
+ export declare function supports(operation: BridgeCapability): boolean;
55
+ /** The operations under the process-wide settings — what the package exports as plain functions. */
56
+ export declare const defaultBridge: OutlookBridge;
package/dist/bridge.js ADDED
@@ -0,0 +1,507 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.defaultBridge = exports.OPERATIONS = void 0;
7
+ exports.createOperations = createOperations;
8
+ exports.createBridge = createBridge;
9
+ exports.createOutlookBridge = createOutlookBridge;
10
+ exports.capabilities = capabilities;
11
+ exports.supports = supports;
12
+ // The public operations, implemented once for both platforms.
13
+ //
14
+ // Each operation checks its arguments, applies its defaults, does whatever work
15
+ // is the same everywhere — composing a reply from a template, splitting a body
16
+ // from its quoted thread, choosing where attachments go — and hands a finished
17
+ // request to this machine's backend. Keeping that here means a default, a
18
+ // range or a validation rule can't come to differ between Windows and macOS.
19
+ const fs_1 = __importDefault(require("fs"));
20
+ const path_1 = __importDefault(require("path"));
21
+ const windows_1 = require("./windows");
22
+ const mac_1 = require("./mac");
23
+ const args_1 = require("./shared/args");
24
+ const replyBody_1 = require("./shared/replyBody");
25
+ const locate_1 = require("./shared/locate");
26
+ const bounceReport_1 = require("./shared/bounceReport");
27
+ const mail_1 = require("./mail");
28
+ const errors_1 = require("./errors");
29
+ const runtime_1 = require("./runtime");
30
+ /** Every default, stated once. */
31
+ const DEFAULTS = {
32
+ daysBack: 60,
33
+ inboxLimit: 50,
34
+ previewChars: 600,
35
+ bodyMaxChars: 8000,
36
+ quotedMaxChars: 4000,
37
+ folderDepth: 2,
38
+ draftsLimit: 100,
39
+ draftsPreviewChars: 300,
40
+ bounceDaysBack: 30,
41
+ sentGroupsLimit: 3000,
42
+ templateFolder: 'Templates',
43
+ templatesLimit: 20,
44
+ };
45
+ /** The widest window any scan accepts, in days. */
46
+ const MAX_DAYS = 3650;
47
+ /**
48
+ * Every operation name. `satisfies` makes this list fail to compile the moment
49
+ * it and the OutlookBridge interface disagree, in either direction.
50
+ */
51
+ const OPERATION_NAMES = {
52
+ getOutlookAccounts: true,
53
+ sendOutlookEmail: true,
54
+ replyOutlookEmail: true,
55
+ readInboxEmails: true,
56
+ searchInboxByFilter: true,
57
+ readSelectedEmail: true,
58
+ readEmailBody: true,
59
+ openOutlookEmail: true,
60
+ locateEmail: true,
61
+ listInboxFolders: true,
62
+ moveOutlookEmails: true,
63
+ listOutlookDrafts: true,
64
+ sendDrafts: true,
65
+ sendAllDrafts: true,
66
+ deleteOutlookDrafts: true,
67
+ deleteOutlookEmails: true,
68
+ purgeDeletedItems: true,
69
+ saveEmailAttachment: true,
70
+ saveEmailAttachments: true,
71
+ cleanUndeliverableEmails: true,
72
+ collectBouncedRecipients: true,
73
+ readSentRecipientGroups: true,
74
+ readBounceReport: true,
75
+ listOutlookSignatures: true,
76
+ readOutlookSignatureHtml: true,
77
+ readTemplateEmails: true,
78
+ saveTemplateEmail: true,
79
+ editEmailTemplate: true,
80
+ };
81
+ exports.OPERATIONS = Object.freeze(Object.keys(OPERATION_NAMES));
82
+ /** This machine's backend, or null where Outlook can't be automated. */
83
+ function platformBackend() {
84
+ switch (process.platform) {
85
+ case 'win32':
86
+ return windows_1.windowsBackend;
87
+ case 'darwin':
88
+ return mac_1.macBackend;
89
+ default:
90
+ return null;
91
+ }
92
+ }
93
+ const PLATFORM_BACKEND = platformBackend();
94
+ function dispositionOf(sendImmediately, openDraftWindow) {
95
+ if ((0, args_1.flag)(sendImmediately, 'sendImmediately', false))
96
+ return 'send';
97
+ return (0, args_1.flag)(openDraftWindow, 'openDraftWindow', true) ? 'display' : 'save';
98
+ }
99
+ /** Attachment paths as absolute paths to files that exist — Outlook resolves a relative path against its own directory, not the caller's. */
100
+ function attachmentFiles(value) {
101
+ return (0, args_1.textList)(value, 'attachments').map(file => {
102
+ const absolute = path_1.default.resolve(file);
103
+ let isFile = false;
104
+ try {
105
+ isFile = fs_1.default.statSync(absolute).isFile();
106
+ }
107
+ catch {
108
+ // Reported below.
109
+ }
110
+ if (!isFile)
111
+ throw new errors_1.NotFoundError('file', `Attachment file '${absolute}' does not exist.`);
112
+ return absolute;
113
+ });
114
+ }
115
+ /**
116
+ * The operations over one backend. A null backend is a platform without Outlook
117
+ * automation: every operation rejects with UNSUPPORTED_PLATFORM before looking
118
+ * at its arguments, since nothing about them could make it work.
119
+ */
120
+ function createOperations(backendOrNull) {
121
+ const backend = () => {
122
+ if (!backendOrNull)
123
+ throw new errors_1.UnsupportedPlatformError(process.platform);
124
+ return backendOrNull;
125
+ };
126
+ async function saveEmailAttachments(email, fileNames, options) {
127
+ const platform = backend();
128
+ const target = (0, args_1.emailLocator)(email);
129
+ const names = (0, args_1.nameList)(fileNames, 'fileNames');
130
+ const destDir = (0, args_1.optionalText)((0, args_1.optionsObject)(options).destDir, 'destDir');
131
+ if (names.length === 0)
132
+ return [];
133
+ const destination = (0, runtime_1.attachmentDestination)(destDir === undefined ? undefined : path_1.default.resolve(destDir));
134
+ try {
135
+ return await platform.saveEmailAttachments({ email: target, fileNames: names, destDir: destination.dir });
136
+ }
137
+ catch (error) {
138
+ destination.discardIfUnused();
139
+ throw error;
140
+ }
141
+ }
142
+ return {
143
+ async getOutlookAccounts() {
144
+ return backend().getOutlookAccounts();
145
+ },
146
+ async sendOutlookEmail(params) {
147
+ const platform = backend();
148
+ const p = (0, args_1.requireObject)(params, 'params');
149
+ const signatureName = (0, args_1.optionalText)(p.signatureName, 'signatureName');
150
+ const request = {
151
+ account: (0, args_1.requiredText)(p.emailAccount, 'emailAccount'),
152
+ to: (0, args_1.recipientList)(p.to, 'to'),
153
+ cc: (0, args_1.recipientList)(p.cc, 'cc'),
154
+ bcc: (0, args_1.recipientList)(p.bcc, 'bcc'),
155
+ subject: (0, args_1.requiredContent)(p.subject, 'subject'),
156
+ htmlBody: (0, args_1.requiredContent)(p.htmlBody, 'htmlBody'),
157
+ attachments: attachmentFiles(p.attachments),
158
+ disposition: dispositionOf(p.sendImmediately, p.openDraftWindow),
159
+ };
160
+ if (request.disposition === 'send' && request.to.length + request.cc.length + request.bcc.length === 0) {
161
+ throw new errors_1.InvalidRequestError('An email sent immediately needs at least one recipient.');
162
+ }
163
+ if (signatureName) {
164
+ request.htmlBody = (0, replyBody_1.placeSignature)(request.htmlBody, await (0, replyBody_1.resolveSignatureHtml)(platform, signatureName));
165
+ }
166
+ await platform.sendOutlookEmail(request);
167
+ },
168
+ async replyOutlookEmail(params) {
169
+ const platform = backend();
170
+ const p = (0, args_1.requireObject)(params, 'params');
171
+ const account = (0, args_1.requiredText)(p.emailAccount, 'emailAccount');
172
+ const email = (0, args_1.emailLocator)({ entryId: p.entryId, storeId: p.storeId }, 'params');
173
+ const html = await (0, replyBody_1.composeReplyHtml)({
174
+ account,
175
+ htmlBody: (0, args_1.optionalContent)(p.htmlBody, 'htmlBody'),
176
+ templateSubject: (0, args_1.optionalText)(p.templateSubject, 'templateSubject'),
177
+ templateFolder: (0, args_1.optionalText)(p.templateFolder, 'templateFolder') ?? DEFAULTS.templateFolder,
178
+ templateSection: (0, args_1.optionalText)(p.templateSection, 'templateSection'),
179
+ templatePlaceholders: (0, args_1.stringRecord)(p.templatePlaceholders, 'templatePlaceholders'),
180
+ signatureName: (0, args_1.optionalText)(p.signatureName, 'signatureName'),
181
+ }, platform);
182
+ return platform.replyOutlookEmail({
183
+ account,
184
+ email,
185
+ html,
186
+ replyAll: (0, args_1.flag)(p.replyAll, 'replyAll', false),
187
+ disposition: dispositionOf(p.sendImmediately, p.openDraftWindow),
188
+ });
189
+ },
190
+ async readInboxEmails(emailAccount, options) {
191
+ const platform = backend();
192
+ const o = (0, args_1.optionsObject)(options);
193
+ const { ref, label } = (0, mail_1.folderOption)((0, args_1.optionalText)(o.folder, 'folder'));
194
+ return platform.readInboxEmails({
195
+ account: (0, args_1.requiredText)(emailAccount, 'emailAccount'),
196
+ folder: ref,
197
+ folderLabel: label,
198
+ daysBack: (0, args_1.count)(o.daysBack, 'daysBack', DEFAULTS.daysBack, 1, MAX_DAYS),
199
+ limit: (0, args_1.count)(o.limit, 'limit', DEFAULTS.inboxLimit, 1, 100_000),
200
+ previewChars: (0, args_1.count)(o.previewChars, 'previewChars', DEFAULTS.previewChars, 0, 1_000_000),
201
+ });
202
+ },
203
+ async searchInboxByFilter(emailAccount, filter) {
204
+ const platform = backend();
205
+ const f = (0, args_1.optionsObject)(filter, 'filter');
206
+ return platform.searchInboxByFilter({
207
+ account: (0, args_1.requiredText)(emailAccount, 'emailAccount'),
208
+ daysBack: (0, args_1.count)(f.daysBack, 'daysBack', DEFAULTS.daysBack, 1, MAX_DAYS),
209
+ subjectLike: (0, args_1.optionalText)(f.subjectLike, 'subjectLike'),
210
+ subjectPattern: (0, args_1.optionalRegExp)(f.subjectPattern, 'subjectPattern'),
211
+ excludeReplies: (0, args_1.flag)(f.excludeReplies, 'excludeReplies', false),
212
+ requireAttachment: (0, args_1.flag)(f.requireAttachment, 'requireAttachment', false),
213
+ includeFolders: (0, args_1.textList)(f.includeFolders, 'includeFolders'),
214
+ excludeFolders: (0, args_1.textList)(f.excludeFolders, 'excludeFolders'),
215
+ includeBody: (0, args_1.flag)(f.includeBody, 'includeBody', true),
216
+ });
217
+ },
218
+ async readSelectedEmail() {
219
+ return backend().readSelectedEmail();
220
+ },
221
+ async readEmailBody(email, options) {
222
+ const platform = backend();
223
+ const target = (0, args_1.emailLocator)(email);
224
+ const o = (0, args_1.optionsObject)(options);
225
+ const maxChars = (0, args_1.count)(o.maxChars, 'maxChars', DEFAULTS.bodyMaxChars, 1, 100_000_000);
226
+ const maxQuotedChars = (0, args_1.count)(o.maxQuotedChars, 'maxQuotedChars', DEFAULTS.quotedMaxChars, 0, 100_000_000);
227
+ const includeQuoted = (0, args_1.flag)(o.includeQuoted, 'includeQuoted', false);
228
+ const raw = await platform.readEmailBody(target);
229
+ // The quoted thread is context, never the sender's own answer, so it is
230
+ // capped by the tighter of the two limits.
231
+ const { body, quoted, separator } = (0, mail_1.splitQuotedOriginal)(raw.body);
232
+ return {
233
+ entryId: raw.entryId,
234
+ subject: raw.subject,
235
+ senderName: raw.senderName,
236
+ senderEmail: raw.senderEmail,
237
+ receivedTime: raw.receivedTime,
238
+ body: body.slice(0, maxChars),
239
+ truncated: body.length > maxChars,
240
+ bodyLength: body.length,
241
+ quoteSeparator: separator,
242
+ quotedLength: quoted.length,
243
+ quotedOriginal: includeQuoted ? quoted.slice(0, Math.min(maxChars, maxQuotedChars)) : '',
244
+ attachmentNames: [...raw.attachmentNames],
245
+ attachmentCount: raw.attachmentNames.length,
246
+ };
247
+ },
248
+ async openOutlookEmail(email) {
249
+ const platform = backend();
250
+ await platform.openOutlookEmail((0, args_1.emailLocator)(email));
251
+ },
252
+ async locateEmail(description, options) {
253
+ const platform = backend();
254
+ const d = (0, args_1.requireObject)(description, 'description');
255
+ const wanted = {
256
+ subject: (0, args_1.optionalText)(d.subject, 'subject'),
257
+ sender: (0, args_1.optionalText)(d.sender, 'sender'),
258
+ receivedTime: (0, args_1.optionalText)(d.receivedTime, 'receivedTime'),
259
+ };
260
+ (0, locate_1.requireDescribed)(wanted);
261
+ const emailAccount = (0, args_1.optionalText)(d.emailAccount, 'emailAccount');
262
+ const folderPath = (0, args_1.optionalText)(d.folderPath, 'folderPath');
263
+ const fallbackDays = (0, args_1.count)((0, args_1.optionsObject)(options).daysBack, 'daysBack', DEFAULTS.daysBack, 1, MAX_DAYS);
264
+ const search = {
265
+ daysBack: Math.min(MAX_DAYS, (0, locate_1.daysBackFor)(wanted.receivedTime, fallbackDays)),
266
+ subjectLike: (0, locate_1.subjectPrefilter)(wanted.subject),
267
+ excludeReplies: false,
268
+ requireAttachment: false,
269
+ includeFolders: [],
270
+ excludeFolders: [],
271
+ // Judging a match reads subjects, senders and times, so the bodies
272
+ // (the heavy part of a scan) are left behind.
273
+ includeBody: false,
274
+ };
275
+ const accounts = emailAccount
276
+ ? [emailAccount]
277
+ : (0, locate_1.accountSearchOrder)(await platform.getOutlookAccounts(), folderPath);
278
+ let searched = 0;
279
+ let firstFailure;
280
+ for (const account of accounts) {
281
+ let matches;
282
+ try {
283
+ matches = await platform.searchInboxByFilter({ account, ...search });
284
+ }
285
+ catch (error) {
286
+ if (error instanceof errors_1.AbortedError)
287
+ throw error;
288
+ // One mailbox that can't be read shouldn't decide the answer
289
+ // for the rest; only every one failing is an error.
290
+ firstFailure ??= error;
291
+ continue;
292
+ }
293
+ searched++;
294
+ const found = (0, locate_1.bestMatch)(wanted, matches);
295
+ if (found)
296
+ return found;
297
+ }
298
+ if (searched === 0 && firstFailure !== undefined)
299
+ throw firstFailure;
300
+ return null;
301
+ },
302
+ async listInboxFolders(emailAccount, options) {
303
+ const platform = backend();
304
+ const o = (0, args_1.optionsObject)(options);
305
+ return platform.listInboxFolders({
306
+ account: (0, args_1.requiredText)(emailAccount, 'emailAccount'),
307
+ maxDepth: (0, args_1.count)(o.maxDepth, 'maxDepth', DEFAULTS.folderDepth, 1, 10),
308
+ });
309
+ },
310
+ async moveOutlookEmails(emailAccount, entryIds, folder, options) {
311
+ const platform = backend();
312
+ const account = (0, args_1.requiredText)(emailAccount, 'emailAccount');
313
+ const ids = (0, args_1.entryIdList)(entryIds);
314
+ const { ref, label } = (0, mail_1.folderOption)((0, args_1.requiredText)(folder, 'folder'));
315
+ const createIfMissing = (0, args_1.flag)((0, args_1.optionsObject)(options).createIfMissing, 'createIfMissing', false);
316
+ if (ids.length === 0)
317
+ return { folderPath: '', folderCreated: false, moved: 0, failed: [] };
318
+ return platform.moveOutlookEmails({
319
+ account,
320
+ entryIds: ids,
321
+ folder: ref,
322
+ folderLabel: label,
323
+ createIfMissing
324
+ });
325
+ },
326
+ async listOutlookDrafts(emailAccount, options) {
327
+ const platform = backend();
328
+ const o = (0, args_1.optionsObject)(options);
329
+ return platform.listOutlookDrafts({
330
+ account: (0, args_1.requiredText)(emailAccount, 'emailAccount'),
331
+ limit: (0, args_1.count)(o.limit, 'limit', DEFAULTS.draftsLimit, 1, 100_000),
332
+ previewChars: (0, args_1.count)(o.previewChars, 'previewChars', DEFAULTS.draftsPreviewChars, 0, 1_000_000),
333
+ });
334
+ },
335
+ async sendDrafts(emailAccount, entryIds) {
336
+ const platform = backend();
337
+ const account = (0, args_1.requiredText)(emailAccount, 'emailAccount');
338
+ const ids = (0, args_1.entryIdList)(entryIds);
339
+ if (ids.length === 0)
340
+ return { sent: 0, failed: [] };
341
+ return platform.sendDrafts({ account, entryIds: ids });
342
+ },
343
+ async sendAllDrafts(emailAccount) {
344
+ const platform = backend();
345
+ return platform.sendAllDrafts({ account: (0, args_1.requiredText)(emailAccount, 'emailAccount') });
346
+ },
347
+ async deleteOutlookDrafts(emailAccount, entryIds) {
348
+ const platform = backend();
349
+ const account = (0, args_1.requiredText)(emailAccount, 'emailAccount');
350
+ const ids = (0, args_1.entryIdList)(entryIds);
351
+ if (ids.length === 0)
352
+ return { deleted: 0, failed: [] };
353
+ return platform.deleteOutlookDrafts({ account, entryIds: ids });
354
+ },
355
+ async deleteOutlookEmails(emailAccount, entryIds, options) {
356
+ const platform = backend();
357
+ const account = (0, args_1.requiredText)(emailAccount, 'emailAccount');
358
+ const ids = (0, args_1.entryIdList)(entryIds);
359
+ const o = (0, args_1.optionsObject)(options);
360
+ const allowProtected = (0, args_1.flag)(o.allowProtected, 'allowProtected', false);
361
+ const dryRun = (0, args_1.flag)(o.dryRun, 'dryRun', false);
362
+ if (ids.length === 0)
363
+ return { dryRun, deleted: 0, refused: 0, failed: 0, items: [] };
364
+ return platform.deleteOutlookEmails({ account, entryIds: ids, allowProtected, dryRun });
365
+ },
366
+ async purgeDeletedItems(emailAccount, options) {
367
+ const platform = backend();
368
+ const o = (0, args_1.optionsObject)(options);
369
+ return platform.purgeDeletedItems({
370
+ account: (0, args_1.requiredText)(emailAccount, 'emailAccount'),
371
+ olderThanDays: (0, args_1.count)(o.olderThanDays, 'olderThanDays', 0, 0, 36_500),
372
+ dryRun: (0, args_1.flag)(o.dryRun, 'dryRun', false),
373
+ });
374
+ },
375
+ async saveEmailAttachment(email, fileName, options) {
376
+ const [saved] = await saveEmailAttachments(email, [fileName], options);
377
+ if (!saved)
378
+ throw new errors_1.NotFoundError('attachment', `Attachment '${fileName}' was not saved.`);
379
+ return saved;
380
+ },
381
+ saveEmailAttachments,
382
+ async cleanUndeliverableEmails(emailAccount, options) {
383
+ const platform = backend();
384
+ const o = (0, args_1.optionsObject)(options);
385
+ return platform.cleanUndeliverableEmails({
386
+ account: (0, args_1.requiredText)(emailAccount, 'emailAccount'),
387
+ daysBack: (0, args_1.count)(o.daysBack, 'daysBack', DEFAULTS.bounceDaysBack, 1, MAX_DAYS),
388
+ // Deleting has to be asked for.
389
+ dryRun: (0, args_1.flag)(o.dryRun, 'dryRun', true),
390
+ });
391
+ },
392
+ async collectBouncedRecipients(emailAccount, options) {
393
+ const platform = backend();
394
+ const o = (0, args_1.optionsObject)(options);
395
+ return platform.collectBouncedRecipients({
396
+ account: (0, args_1.requiredText)(emailAccount, 'emailAccount'),
397
+ daysBack: (0, args_1.count)(o.daysBack, 'daysBack', DEFAULTS.bounceDaysBack, 1, MAX_DAYS),
398
+ includeDeletedItems: (0, args_1.flag)(o.includeDeletedItems, 'includeDeletedItems', true),
399
+ });
400
+ },
401
+ async readSentRecipientGroups(emailAccount, options) {
402
+ const platform = backend();
403
+ const o = (0, args_1.optionsObject)(options);
404
+ return platform.readSentRecipientGroups({
405
+ account: (0, args_1.requiredText)(emailAccount, 'emailAccount'),
406
+ daysBack: (0, args_1.count)(o.daysBack, 'daysBack', DEFAULTS.bounceDaysBack, 1, MAX_DAYS),
407
+ limit: (0, args_1.count)(o.limit, 'limit', DEFAULTS.sentGroupsLimit, 1, 100_000),
408
+ });
409
+ },
410
+ async readBounceReport(emailAccount, options) {
411
+ const platform = backend();
412
+ const account = (0, args_1.requiredText)(emailAccount, 'emailAccount');
413
+ const o = (0, args_1.optionsObject)(options);
414
+ const daysBack = (0, args_1.count)(o.daysBack, 'daysBack', DEFAULTS.bounceDaysBack, 1, MAX_DAYS);
415
+ const includeDeletedItems = (0, args_1.flag)(o.includeDeletedItems, 'includeDeletedItems', true);
416
+ const bounced = await platform.collectBouncedRecipients({ account, daysBack, includeDeletedItems });
417
+ const sent = await platform.readSentRecipientGroups({ account, daysBack, limit: DEFAULTS.sentGroupsLimit });
418
+ return (0, bounceReport_1.buildBounceReport)(account, daysBack, bounced, sent);
419
+ },
420
+ async listOutlookSignatures() {
421
+ return backend().listOutlookSignatures();
422
+ },
423
+ async readOutlookSignatureHtml(name) {
424
+ const platform = backend();
425
+ return platform.readOutlookSignatureHtml((0, args_1.requiredText)(name, 'name'));
426
+ },
427
+ async readTemplateEmails(emailAccount, options) {
428
+ const platform = backend();
429
+ const o = (0, args_1.optionsObject)(options);
430
+ return platform.readTemplateEmails({
431
+ account: (0, args_1.requiredText)(emailAccount, 'emailAccount'),
432
+ folder: (0, args_1.optionalText)(o.folder, 'folder') ?? DEFAULTS.templateFolder,
433
+ limit: (0, args_1.count)(o.limit, 'limit', DEFAULTS.templatesLimit, 1, 200),
434
+ includeBody: (0, args_1.flag)(o.includeBody, 'includeBody', true),
435
+ subject: (0, args_1.optionalText)(o.subject, 'subject'),
436
+ });
437
+ },
438
+ async saveTemplateEmail(emailAccount, template) {
439
+ const platform = backend();
440
+ const account = (0, args_1.requiredText)(emailAccount, 'emailAccount');
441
+ const t = (0, args_1.requireObject)(template, 'template');
442
+ return platform.saveTemplateEmail({
443
+ account,
444
+ folder: (0, args_1.optionalText)(t.folder, 'folder') ?? DEFAULTS.templateFolder,
445
+ subject: (0, args_1.requiredText)(t.subject, 'subject'),
446
+ htmlBody: (0, args_1.requiredContent)(t.htmlBody, 'htmlBody'),
447
+ });
448
+ },
449
+ async editEmailTemplate(label, currentHtml) {
450
+ const platform = backend();
451
+ return platform.editEmailTemplate({
452
+ label: (0, args_1.requiredText)(label, 'label'),
453
+ html: (0, args_1.requiredContent)(currentHtml, 'currentHtml'),
454
+ });
455
+ },
456
+ };
457
+ }
458
+ function capabilityMap(backend) {
459
+ return Object.freeze(Object.fromEntries(exports.OPERATIONS.map(name => [name, backend !== null])));
460
+ }
461
+ /**
462
+ * A bridge over `backend` whose every call runs with `config` in force.
463
+ *
464
+ * The platform code reads settings through `getConfig()`, so the config is put
465
+ * in place around each call rather than passed into it: `withConfig` scopes it
466
+ * to the call's whole async subtree, which is why two bridges with different
467
+ * settings can run concurrently without seeing each other's.
468
+ */
469
+ function createBridge(backend, config) {
470
+ const operations = createOperations(backend);
471
+ const map = capabilityMap(backend);
472
+ const instance = {
473
+ options: Object.freeze({ ...config }),
474
+ capabilities: () => map,
475
+ supports: (operation) => map[operation] === true,
476
+ withOptions: (options) => createBridge(backend, (0, runtime_1.mergeOptions)(config, options)),
477
+ };
478
+ for (const name of exports.OPERATIONS) {
479
+ instance[name] = (...args) => (0, runtime_1.withConfig)(config, () => operations[name](...args));
480
+ }
481
+ return instance;
482
+ }
483
+ /**
484
+ * A bridge with its own settings, isolated from `configure()` and from every
485
+ * other bridge. Options left out take the process-wide values as they stand
486
+ * when this is called.
487
+ *
488
+ * ```ts
489
+ * const outlook = createOutlookBridge({ timeoutMs: 30_000 });
490
+ * const recent = await outlook.readInboxEmails('me@example.com', { daysBack: 7 });
491
+ * ```
492
+ */
493
+ function createOutlookBridge(options = {}) {
494
+ return createBridge(PLATFORM_BACKEND, (0, runtime_1.mergeOptions)((0, runtime_1.getGlobalConfig)(), options));
495
+ }
496
+ const PLATFORM_CAPABILITIES = capabilityMap(PLATFORM_BACKEND);
497
+ /** Which operations work on this machine: all of them on Windows and macOS, none elsewhere. */
498
+ function capabilities() {
499
+ return PLATFORM_CAPABILITIES;
500
+ }
501
+ /** Whether one operation works on this machine. */
502
+ function supports(operation) {
503
+ return PLATFORM_CAPABILITIES[operation] === true;
504
+ }
505
+ /** The operations under the process-wide settings — what the package exports as plain functions. */
506
+ exports.defaultBridge = createOperations(PLATFORM_BACKEND);
507
+ //# sourceMappingURL=bridge.js.map