@dawnlit/outlook-bridge 1.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.
- package/LICENSE +190 -0
- package/README.md +253 -0
- package/dist/OutlookService.d.ts +43 -0
- package/dist/OutlookService.js +137 -0
- package/dist/OutlookService.js.map +1 -0
- package/dist/errors.d.ts +112 -0
- package/dist/errors.js +140 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +71 -0
- package/dist/index.js.map +1 -0
- package/dist/mac/accounts.d.ts +5 -0
- package/dist/mac/accounts.js +17 -0
- package/dist/mac/accounts.js.map +1 -0
- package/dist/mac/attachments.d.ts +28 -0
- package/dist/mac/attachments.js +120 -0
- package/dist/mac/attachments.js.map +1 -0
- package/dist/mac/bounces.d.ts +32 -0
- package/dist/mac/bounces.js +285 -0
- package/dist/mac/bounces.js.map +1 -0
- package/dist/mac/cleanup.d.ts +29 -0
- package/dist/mac/cleanup.js +219 -0
- package/dist/mac/cleanup.js.map +1 -0
- package/dist/mac/drafts.d.ts +27 -0
- package/dist/mac/drafts.js +214 -0
- package/dist/mac/drafts.js.map +1 -0
- package/dist/mac/folders.d.ts +28 -0
- package/dist/mac/folders.js +127 -0
- package/dist/mac/folders.js.map +1 -0
- package/dist/mac/index.d.ts +22 -0
- package/dist/mac/index.js +119 -0
- package/dist/mac/index.js.map +1 -0
- package/dist/mac/read.d.ts +46 -0
- package/dist/mac/read.js +406 -0
- package/dist/mac/read.js.map +1 -0
- package/dist/mac/run.d.ts +64 -0
- package/dist/mac/run.js +250 -0
- package/dist/mac/run.js.map +1 -0
- package/dist/mac/scripts.d.ts +137 -0
- package/dist/mac/scripts.js +337 -0
- package/dist/mac/scripts.js.map +1 -0
- package/dist/mac/send.d.ts +23 -0
- package/dist/mac/send.js +135 -0
- package/dist/mac/send.js.map +1 -0
- package/dist/mac/signatures.d.ts +4 -0
- package/dist/mac/signatures.js +36 -0
- package/dist/mac/signatures.js.map +1 -0
- package/dist/mac/templates.d.ts +34 -0
- package/dist/mac/templates.js +266 -0
- package/dist/mac/templates.js.map +1 -0
- package/dist/mail.d.ts +72 -0
- package/dist/mail.js +131 -0
- package/dist/mail.js.map +1 -0
- package/dist/outlookTemplateSections.d.ts +62 -0
- package/dist/outlookTemplateSections.js +313 -0
- package/dist/outlookTemplateSections.js.map +1 -0
- package/dist/runtime.d.ts +76 -0
- package/dist/runtime.js +123 -0
- package/dist/runtime.js.map +1 -0
- package/dist/shared/attachmentMatch.d.ts +32 -0
- package/dist/shared/attachmentMatch.js +50 -0
- package/dist/shared/attachmentMatch.js.map +1 -0
- package/dist/shared/bounceRules.d.ts +33 -0
- package/dist/shared/bounceRules.js +104 -0
- package/dist/shared/bounceRules.js.map +1 -0
- package/dist/shared/capabilities.d.ts +3 -0
- package/dist/shared/capabilities.js +9 -0
- package/dist/shared/capabilities.js.map +1 -0
- package/dist/shared/json.d.ts +11 -0
- package/dist/shared/json.js +45 -0
- package/dist/shared/json.js.map +1 -0
- package/dist/shared/replyBody.d.ts +49 -0
- package/dist/shared/replyBody.js +113 -0
- package/dist/shared/replyBody.js.map +1 -0
- package/dist/types.d.ts +365 -0
- package/dist/types.js +13 -0
- package/dist/types.js.map +1 -0
- package/dist/windows/accounts.d.ts +2 -0
- package/dist/windows/accounts.js +22 -0
- package/dist/windows/accounts.js.map +1 -0
- package/dist/windows/attachments.d.ts +28 -0
- package/dist/windows/attachments.js +141 -0
- package/dist/windows/attachments.js.map +1 -0
- package/dist/windows/bounces.d.ts +34 -0
- package/dist/windows/bounces.js +267 -0
- package/dist/windows/bounces.js.map +1 -0
- package/dist/windows/cleanup.d.ts +29 -0
- package/dist/windows/cleanup.js +165 -0
- package/dist/windows/cleanup.js.map +1 -0
- package/dist/windows/drafts.d.ts +29 -0
- package/dist/windows/drafts.js +253 -0
- package/dist/windows/drafts.js.map +1 -0
- package/dist/windows/folders.d.ts +16 -0
- package/dist/windows/folders.js +88 -0
- package/dist/windows/folders.js.map +1 -0
- package/dist/windows/index.d.ts +27 -0
- package/dist/windows/index.js +100 -0
- package/dist/windows/index.js.map +1 -0
- package/dist/windows/read.d.ts +54 -0
- package/dist/windows/read.js +372 -0
- package/dist/windows/read.js.map +1 -0
- package/dist/windows/run.d.ts +54 -0
- package/dist/windows/run.js +161 -0
- package/dist/windows/run.js.map +1 -0
- package/dist/windows/scripts.d.ts +56 -0
- package/dist/windows/scripts.js +163 -0
- package/dist/windows/scripts.js.map +1 -0
- package/dist/windows/send.d.ts +11 -0
- package/dist/windows/send.js +114 -0
- package/dist/windows/send.js.map +1 -0
- package/dist/windows/signatures.d.ts +14 -0
- package/dist/windows/signatures.js +69 -0
- package/dist/windows/signatures.js.map +1 -0
- package/dist/windows/templates.d.ts +25 -0
- package/dist/windows/templates.js +246 -0
- package/dist/windows/templates.js.map +1 -0
- package/package.json +50 -0
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Section + placeholder composition for the operator's Outlook template emails.
|
|
4
|
+
*
|
|
5
|
+
* A template email is a normal saved mail the operator edits in Outlook, so the
|
|
6
|
+
* greeting, closing and signature are theirs. Where one template serves several
|
|
7
|
+
* reply types, the variants live inside it between markers:
|
|
8
|
+
*
|
|
9
|
+
* Hello,
|
|
10
|
+
* [[QUOTE]] Thank you for your quote... [[/QUOTE]]
|
|
11
|
+
* [[NOQUOTE]] Thank you for letting us know... [[/NOQUOTE]]
|
|
12
|
+
* [[CLARIFY]] {{QUESTIONS}} [[/CLARIFY]]
|
|
13
|
+
* Best regards, <signature>
|
|
14
|
+
*
|
|
15
|
+
* Composing keeps the requested section, drops the others, and substitutes any
|
|
16
|
+
* {{PLACEHOLDER}} — so the shared wording is written once and the caller only
|
|
17
|
+
* names a section instead of carrying (and editing) 40-50k of Word HTML.
|
|
18
|
+
*
|
|
19
|
+
* Everything here works on the raw HTML string rather than a parsed tree: Word's
|
|
20
|
+
* markup carries conditional comments and namespaced tags that a round-trip
|
|
21
|
+
* through a parser would rewrite, and the reply body must stay byte-identical to
|
|
22
|
+
* what the operator wrote.
|
|
23
|
+
*/
|
|
24
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
+
exports.findTemplateMarkers = findTemplateMarkers;
|
|
26
|
+
exports.replaceToken = replaceToken;
|
|
27
|
+
exports.removeTokenLine = removeTokenLine;
|
|
28
|
+
exports.findTokens = findTokens;
|
|
29
|
+
exports.findUnfilledTokens = findUnfilledTokens;
|
|
30
|
+
exports.composeTemplateBody = composeTemplateBody;
|
|
31
|
+
const errors_1 = require("./errors");
|
|
32
|
+
/** Marker/placeholder names: what an operator can reasonably type in Outlook. */
|
|
33
|
+
const NAME = '[A-Za-z0-9_-]{1,40}';
|
|
34
|
+
/**
|
|
35
|
+
* What Word may inject *between two characters of a marker*: tags (it splits runs
|
|
36
|
+
* across <span>s freely), comments, non-breaking spaces, and the newlines it wraps
|
|
37
|
+
* long lines with — sometimes mid-word. So `[[QUOTE]]` is matched character by
|
|
38
|
+
* character with this between, never as a literal string.
|
|
39
|
+
*/
|
|
40
|
+
const GAP = '(?:<!--[\\s\\S]*?-->|<[^>]*>| | |\\s)*';
|
|
41
|
+
/** Block elements a marker can sit alone inside; the whole block goes when it does. */
|
|
42
|
+
const BLOCK_TAGS = ['p', 'div', 'li'];
|
|
43
|
+
/**
|
|
44
|
+
* Block elements that make up one *line* of a template, for a placeholder whose
|
|
45
|
+
* empty value takes its whole line out (see `removeTokenLine`). Ordered
|
|
46
|
+
* outermost-first: Word puts a <p> inside every table cell, so a token in a
|
|
47
|
+
* details table has to drop the <tr> — dropping the <p> would leave the row's
|
|
48
|
+
* label cell sitting beside a blank one.
|
|
49
|
+
*
|
|
50
|
+
* <div> is deliberately absent: it is rarely a line and often the wrapper around
|
|
51
|
+
* the entire body, so a token sitting directly in one would take the whole email
|
|
52
|
+
* with it. Falling back to deleting just the token is the safer miss.
|
|
53
|
+
*/
|
|
54
|
+
const LINE_TAGS = ['tr', 'li', 'p'];
|
|
55
|
+
function escapeRe(s) {
|
|
56
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Tag-tolerant matcher for one literal marker, e.g. `[[/QUOTE]]` or `{{QUESTIONS}}`.
|
|
60
|
+
*
|
|
61
|
+
* Memoized: the pattern interleaves `GAP` between every character, so a 15-character
|
|
62
|
+
* token compiles to several hundred characters, and the replace loops ask for the
|
|
63
|
+
* same token repeatedly while walking a template.
|
|
64
|
+
*/
|
|
65
|
+
const markerRegexCache = new Map();
|
|
66
|
+
function markerRegex(token) {
|
|
67
|
+
let regex = markerRegexCache.get(token);
|
|
68
|
+
if (!regex) {
|
|
69
|
+
regex = new RegExp(token.split('').map(escapeRe).join(GAP), 'i');
|
|
70
|
+
markerRegexCache.set(token, regex);
|
|
71
|
+
}
|
|
72
|
+
return regex;
|
|
73
|
+
}
|
|
74
|
+
/** HTML → rough plain text, enough to spot markers and to test a block for emptiness. */
|
|
75
|
+
function stripToText(html) {
|
|
76
|
+
return html
|
|
77
|
+
.replace(/<!--[\s\S]*?-->/g, '')
|
|
78
|
+
.replace(/<[^>]*>/g, '')
|
|
79
|
+
.replace(/ | /gi, ' ');
|
|
80
|
+
}
|
|
81
|
+
/** Find the markers in a template body (HTML or the plain-text body Outlook derives). */
|
|
82
|
+
function findTemplateMarkers(body) {
|
|
83
|
+
const text = stripToText(body || '');
|
|
84
|
+
const opened = [];
|
|
85
|
+
const closed = new Set();
|
|
86
|
+
const seen = new Set();
|
|
87
|
+
const sectionRe = new RegExp(`\\[\\[\\s*(/?)\\s*(${NAME})\\s*\\]\\]`, 'g');
|
|
88
|
+
let m;
|
|
89
|
+
while ((m = sectionRe.exec(text)) !== null) {
|
|
90
|
+
const name = m[2].toUpperCase();
|
|
91
|
+
if (m[1]) {
|
|
92
|
+
closed.add(name);
|
|
93
|
+
}
|
|
94
|
+
else if (!seen.has(name)) {
|
|
95
|
+
seen.add(name);
|
|
96
|
+
opened.push(name);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
const placeholders = [];
|
|
100
|
+
const placeholderRe = new RegExp(`\\{\\{\\s*(${NAME})\\s*\\}\\}`, 'g');
|
|
101
|
+
while ((m = placeholderRe.exec(text)) !== null) {
|
|
102
|
+
const name = m[1].toUpperCase();
|
|
103
|
+
if (!placeholders.includes(name))
|
|
104
|
+
placeholders.push(name);
|
|
105
|
+
}
|
|
106
|
+
return { sections: opened.filter(n => closed.has(n)), placeholders };
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Every `[[...]]` / `{{...}}` token still in a body, matched pairs or not — the
|
|
110
|
+
* last check before a composed reply is handed to Outlook, so a marker the
|
|
111
|
+
* operator half-deleted stops the run instead of going out to a carrier.
|
|
112
|
+
*/
|
|
113
|
+
function markerTokens(body) {
|
|
114
|
+
const text = stripToText(body || '');
|
|
115
|
+
const re = new RegExp(`\\[\\[\\s*/?\\s*${NAME}\\s*\\]\\]|\\{\\{\\s*${NAME}\\s*\\}\\}`, 'g');
|
|
116
|
+
const found = [];
|
|
117
|
+
let m;
|
|
118
|
+
while ((m = re.exec(text)) !== null) {
|
|
119
|
+
const token = m[0].replace(/\s+/g, '');
|
|
120
|
+
if (!found.includes(token))
|
|
121
|
+
found.push(token);
|
|
122
|
+
}
|
|
123
|
+
return found;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* The nearest enclosing block element of [start, end), or null when the marker
|
|
127
|
+
* isn't inside one. The closing tag is the first of the same name after the
|
|
128
|
+
* marker — Word doesn't nest <p>, and where the guess is wrong the emptiness
|
|
129
|
+
* test below simply fails and the caller falls back to the marker's own span.
|
|
130
|
+
*/
|
|
131
|
+
function enclosingBlock(html, start, end, tags = BLOCK_TAGS) {
|
|
132
|
+
let best = null;
|
|
133
|
+
for (const tag of tags) {
|
|
134
|
+
const openRe = new RegExp(`<${tag}(?:\\s[^>]*)?>`, 'gi');
|
|
135
|
+
let m;
|
|
136
|
+
while ((m = openRe.exec(html)) !== null) {
|
|
137
|
+
if (m.index >= start)
|
|
138
|
+
break;
|
|
139
|
+
if (!best || m.index > best.idx) {
|
|
140
|
+
best = { idx: m.index, contentStart: m.index + m[0].length, tag };
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
if (!best)
|
|
145
|
+
return null;
|
|
146
|
+
const closeRe = new RegExp(`</${best.tag}\\s*>`, 'gi');
|
|
147
|
+
closeRe.lastIndex = end;
|
|
148
|
+
const close = closeRe.exec(html);
|
|
149
|
+
if (!close)
|
|
150
|
+
return null;
|
|
151
|
+
return {
|
|
152
|
+
block: { start: best.idx, end: close.index + close[0].length },
|
|
153
|
+
contentStart: best.contentStart,
|
|
154
|
+
contentEnd: close.index,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* What to delete for a marker: the whole paragraph when the marker is alone in it
|
|
159
|
+
* (removing only the text would leave a blank line in the reply), otherwise just
|
|
160
|
+
* the marker's own characters.
|
|
161
|
+
*/
|
|
162
|
+
function markerSpan(html, start, end) {
|
|
163
|
+
const found = enclosingBlock(html, start, end);
|
|
164
|
+
if (!found || found.contentStart > start || found.contentEnd < end)
|
|
165
|
+
return { start, end };
|
|
166
|
+
const rest = html.slice(found.contentStart, start) + html.slice(end, found.contentEnd);
|
|
167
|
+
return stripToText(rest).trim() === '' ? found.block : { start, end };
|
|
168
|
+
}
|
|
169
|
+
function locate(html, token) {
|
|
170
|
+
const m = markerRegex(token).exec(html);
|
|
171
|
+
return m ? { start: m.index, end: m.index + m[0].length } : null;
|
|
172
|
+
}
|
|
173
|
+
// ── Single-token fill ───────────────────────────────────────────────
|
|
174
|
+
//
|
|
175
|
+
// The section machinery below is for templates that hold several variants of one
|
|
176
|
+
// reply. These three are for the simpler case: a template whose wording is fixed
|
|
177
|
+
// and whose details — a lane, a cargo weight — are typed somewhere else and dropped
|
|
178
|
+
// into `{Token}` placeholders. Same tag-tolerant matching, since the operator
|
|
179
|
+
// edits these templates in Outlook too.
|
|
180
|
+
/** Replace every occurrence of `token` with `value`, which is never rescanned. */
|
|
181
|
+
function replaceToken(html, token, value) {
|
|
182
|
+
let done = '';
|
|
183
|
+
let rest = html;
|
|
184
|
+
for (;;) {
|
|
185
|
+
const at = locate(rest, token);
|
|
186
|
+
if (!at)
|
|
187
|
+
return done + rest;
|
|
188
|
+
done += rest.slice(0, at.start) + value;
|
|
189
|
+
rest = rest.slice(at.end);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Remove `token` along with the line it sits on — the table row or paragraph,
|
|
194
|
+
* label included. For an optional detail this is the difference between the email
|
|
195
|
+
* not mentioning it at all and it carrying a heading with nothing under it.
|
|
196
|
+
* Falls back to deleting just the token when it isn't inside a line element.
|
|
197
|
+
*/
|
|
198
|
+
function removeTokenLine(html, token) {
|
|
199
|
+
let out = html;
|
|
200
|
+
for (;;) {
|
|
201
|
+
const at = locate(out, token);
|
|
202
|
+
if (!at)
|
|
203
|
+
return out;
|
|
204
|
+
const cut = lineSpan(out, at);
|
|
205
|
+
out = out.slice(0, cut.start) + out.slice(cut.end);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* The line to delete for a token at `at`: its enclosing row or paragraph, or the
|
|
210
|
+
* token's own span when it isn't in one.
|
|
211
|
+
*
|
|
212
|
+
* `enclosingBlock` returns the *nearest* opening tag before the token, which is
|
|
213
|
+
* only the enclosing one if it hasn't already been closed — a token in a
|
|
214
|
+
* paragraph after a table has a `<tr>` before it and a `</tr>` after it without
|
|
215
|
+
* ever being inside a row, and taking that span would delete the table.
|
|
216
|
+
*/
|
|
217
|
+
function lineSpan(html, at) {
|
|
218
|
+
for (const tag of LINE_TAGS) {
|
|
219
|
+
const found = enclosingBlock(html, at.start, at.end, [tag]);
|
|
220
|
+
if (!found)
|
|
221
|
+
continue;
|
|
222
|
+
const closedBefore = new RegExp(`</${tag}\\s*>`, 'i').test(html.slice(found.contentStart, at.start));
|
|
223
|
+
if (!closedBefore)
|
|
224
|
+
return found.block;
|
|
225
|
+
}
|
|
226
|
+
return at;
|
|
227
|
+
}
|
|
228
|
+
/** Which of `tokens` the template actually uses — what the caller has to supply. */
|
|
229
|
+
function findTokens(html, tokens) {
|
|
230
|
+
const text = stripToText(html || '');
|
|
231
|
+
return tokens.filter(token => markerRegex(token).test(text));
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* `{Token}`-shaped text still in a filled-in body: a placeholder misspelled in
|
|
235
|
+
* Outlook, or one the app has no field for. Reads the visible text only, so the
|
|
236
|
+
* braces in a Word <style> block are not mistaken for placeholders.
|
|
237
|
+
*/
|
|
238
|
+
function findUnfilledTokens(html) {
|
|
239
|
+
const text = stripToText((html || '').replace(/<(style|script)\b[^>]*>[\s\S]*?<\/\1>/gi, ''));
|
|
240
|
+
const found = [];
|
|
241
|
+
const re = /\{\s*([A-Za-z][A-Za-z0-9 _-]{0,30})\s*\}/g;
|
|
242
|
+
let m;
|
|
243
|
+
while ((m = re.exec(text)) !== null) {
|
|
244
|
+
const token = `{${m[1].trim()}}`;
|
|
245
|
+
if (!found.includes(token))
|
|
246
|
+
found.push(token);
|
|
247
|
+
}
|
|
248
|
+
return found;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Resolve a template body down to the one reply that goes out: keep `section`,
|
|
252
|
+
* drop the rest, fill the placeholders. Throws rather than guessing — a template
|
|
253
|
+
* the operator edited into an unusable state must stop the run, not quietly send
|
|
254
|
+
* a reply with `[[QUOTE]]` or an empty question list in it.
|
|
255
|
+
*/
|
|
256
|
+
function composeTemplateBody(html, options = {}) {
|
|
257
|
+
const label = options.label ? `Template '${options.label}'` : 'The template';
|
|
258
|
+
const wanted = (options.section || '').trim().toUpperCase();
|
|
259
|
+
const { sections, placeholders: available } = findTemplateMarkers(html);
|
|
260
|
+
if (wanted && !sections.includes(wanted)) {
|
|
261
|
+
throw new errors_1.InvalidRequestError(sections.length
|
|
262
|
+
? `${label} has no [[${wanted}]] section. Sections found: ${sections.join(', ')}.`
|
|
263
|
+
: `${label} has no [[${wanted}]]...[[/${wanted}]] markers — it holds a single body, so drop templateSection (or add the markers in Outlook).`);
|
|
264
|
+
}
|
|
265
|
+
if (!wanted && sections.length) {
|
|
266
|
+
throw new errors_1.InvalidRequestError(`${label} is split into sections (${sections.join(', ')}) — name one with templateSection, `
|
|
267
|
+
+ `otherwise the reply would go out with the markers and every variant in it.`);
|
|
268
|
+
}
|
|
269
|
+
// Deletions are collected first and applied right-to-left, so each span's
|
|
270
|
+
// indices still refer to the string it was measured against.
|
|
271
|
+
const cuts = [];
|
|
272
|
+
for (const name of sections) {
|
|
273
|
+
const open = locate(html, `[[${name}]]`);
|
|
274
|
+
const close = locate(html, `[[/${name}]]`);
|
|
275
|
+
if (!open || !close || close.start < open.end) {
|
|
276
|
+
throw new errors_1.InvalidRequestError(`${label} has a malformed [[${name}]] section — expected [[${name}]] ... [[/${name}]] in that order.`);
|
|
277
|
+
}
|
|
278
|
+
const openSpan = markerSpan(html, open.start, open.end);
|
|
279
|
+
const closeSpan = markerSpan(html, close.start, close.end);
|
|
280
|
+
if (name === wanted) {
|
|
281
|
+
cuts.push(openSpan, closeSpan); // keep the content, shed the markers
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
cuts.push({ start: openSpan.start, end: closeSpan.end });
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
let out = html;
|
|
288
|
+
for (const cut of cuts.sort((a, b) => b.start - a.start)) {
|
|
289
|
+
out = out.slice(0, cut.start) + out.slice(cut.end);
|
|
290
|
+
}
|
|
291
|
+
for (const [rawKey, value] of Object.entries(options.placeholders || {})) {
|
|
292
|
+
const key = rawKey.trim().toUpperCase();
|
|
293
|
+
if (!available.includes(key)) {
|
|
294
|
+
throw new errors_1.InvalidRequestError(`${label} has no {{${key}}} placeholder`
|
|
295
|
+
+ (available.length ? ` (found: ${available.map(p => `{{${p}}}`).join(', ')}).` : '.')
|
|
296
|
+
+ ` It may have been edited out in Outlook — ask the user rather than guessing where the text goes.`);
|
|
297
|
+
}
|
|
298
|
+
const m = markerRegex(`{{${key}}}`).exec(out);
|
|
299
|
+
// Absent from `out` but present in the template = it lived in a dropped
|
|
300
|
+
// section, which is the caller over-supplying, not an error.
|
|
301
|
+
if (m)
|
|
302
|
+
out = out.slice(0, m.index) + (value ?? '') + out.slice(m.index + m[0].length);
|
|
303
|
+
}
|
|
304
|
+
const leftover = markerTokens(out);
|
|
305
|
+
if (leftover.length) {
|
|
306
|
+
const hint = leftover.every(t => t.startsWith('{{'))
|
|
307
|
+
? `Pass a value for each in templatePlaceholders.`
|
|
308
|
+
: `Check the template in Outlook — every [[SECTION]] needs its [[/SECTION]].`;
|
|
309
|
+
throw new errors_1.InvalidRequestError(`${label} still contains unresolved markers after composing: ${leftover.join(', ')}. ${hint} The reply was not created.`);
|
|
310
|
+
}
|
|
311
|
+
return out;
|
|
312
|
+
}
|
|
313
|
+
//# sourceMappingURL=outlookTemplateSections.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outlookTemplateSections.js","sourceRoot":"","sources":["../src/outlookTemplateSections.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/** One completed script run, handed to the `debug` hook. */
|
|
2
|
+
export interface BridgeDebugEvent {
|
|
3
|
+
/** Which interpreter ran it. */
|
|
4
|
+
runner: 'powershell' | 'osascript';
|
|
5
|
+
/** The generated script, verbatim — the thing you actually want when a run fails. */
|
|
6
|
+
script: string;
|
|
7
|
+
durationMs: number;
|
|
8
|
+
/** Present only when the run failed. */
|
|
9
|
+
error?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface BridgeOptions {
|
|
12
|
+
/**
|
|
13
|
+
* Default ceiling (ms) on a single script run; 0 disables it. Calls that
|
|
14
|
+
* already carry a specific budget (a full-mailbox scan, a purge) keep their
|
|
15
|
+
* own and ignore this.
|
|
16
|
+
*/
|
|
17
|
+
timeoutMs?: number;
|
|
18
|
+
/**
|
|
19
|
+
* Max bytes a script may write to stdout before the run is killed. A read
|
|
20
|
+
* that returns message bodies is what pushes against this — raise it before
|
|
21
|
+
* scanning a mailbox that returns thousands of matches.
|
|
22
|
+
*/
|
|
23
|
+
maxBufferBytes?: number;
|
|
24
|
+
/** Directory for generated scripts and for saved attachments when the caller
|
|
25
|
+
* names no destination. Defaults to the OS temp directory. */
|
|
26
|
+
tempDir?: string;
|
|
27
|
+
/**
|
|
28
|
+
* Cancels in-flight runs: the interpreter is killed and the call rejects with
|
|
29
|
+
* an `AbortedError`. A timeout only caps a run's length — this is how a UI
|
|
30
|
+
* with a Cancel button, or a shutting-down process, calls one off early.
|
|
31
|
+
*
|
|
32
|
+
* Most useful scoped to the calls you want to cancel rather than set process
|
|
33
|
+
* wide: `bridge.withOptions({ signal }).searchInboxByFilter(...)`.
|
|
34
|
+
*/
|
|
35
|
+
signal?: AbortSignal;
|
|
36
|
+
/** `true` logs every generated script to stderr; a function receives each run
|
|
37
|
+
* instead. Defaults to on when OUTLOOK_BRIDGE_DEBUG is set to a non-empty,
|
|
38
|
+
* non-'0' value. */
|
|
39
|
+
debug?: boolean | ((event: BridgeDebugEvent) => void);
|
|
40
|
+
}
|
|
41
|
+
export type ResolvedConfig = Required<Pick<BridgeOptions, 'timeoutMs' | 'maxBufferBytes' | 'tempDir'>> & Pick<BridgeOptions, 'debug' | 'signal'>;
|
|
42
|
+
/** Merge caller options over a base, ignoring the keys they left out. */
|
|
43
|
+
export declare function mergeOptions(base: ResolvedConfig, options?: BridgeOptions): ResolvedConfig;
|
|
44
|
+
/**
|
|
45
|
+
* Override the process-wide defaults. Merges, so naming one option leaves the
|
|
46
|
+
* rest alone. Call before the first automation call.
|
|
47
|
+
*
|
|
48
|
+
* Affects every caller in the process. Prefer `createOutlookBridge(options)` in
|
|
49
|
+
* anything that shares a process with code you don't own.
|
|
50
|
+
*/
|
|
51
|
+
export declare function configure(options: BridgeOptions): void;
|
|
52
|
+
/** The settings in force for the current call — the enclosing scope's, else global. */
|
|
53
|
+
export declare function getConfig(): Readonly<ResolvedConfig>;
|
|
54
|
+
/** The process-wide defaults, ignoring any active scope. */
|
|
55
|
+
export declare function getGlobalConfig(): Readonly<ResolvedConfig>;
|
|
56
|
+
/** Run `fn` with `config` in force for it and everything it awaits. */
|
|
57
|
+
export declare function withConfig<T>(config: ResolvedConfig, fn: () => T): T;
|
|
58
|
+
/** Report one finished script run to the configured debug hook. */
|
|
59
|
+
export declare function reportRun(event: BridgeDebugEvent): void;
|
|
60
|
+
/**
|
|
61
|
+
* Path for a scratch file in the configured temp directory. The random suffix
|
|
62
|
+
* matters: two concurrent calls landing in the same millisecond would otherwise
|
|
63
|
+
* pick the same name and overwrite each other's script mid-run.
|
|
64
|
+
*/
|
|
65
|
+
export declare function tempFile(kind: string, extension: string): string;
|
|
66
|
+
/**
|
|
67
|
+
* A fresh directory for one call's saved attachments.
|
|
68
|
+
*
|
|
69
|
+
* Deliberately per-call rather than one shared folder: attachments are saved
|
|
70
|
+
* under the name the sender gave them, so two emails that both carry
|
|
71
|
+
* "invoice.pdf" would otherwise silently overwrite each other — and so would two
|
|
72
|
+
* unrelated programs using this package on the same machine.
|
|
73
|
+
*/
|
|
74
|
+
export declare function makeAttachmentDir(): string;
|
|
75
|
+
/** Resolve a caller-supplied destination, creating it when absent. */
|
|
76
|
+
export declare function resolveDestDir(destDir?: string): string;
|
package/dist/runtime.js
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
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.mergeOptions = mergeOptions;
|
|
7
|
+
exports.configure = configure;
|
|
8
|
+
exports.getConfig = getConfig;
|
|
9
|
+
exports.getGlobalConfig = getGlobalConfig;
|
|
10
|
+
exports.withConfig = withConfig;
|
|
11
|
+
exports.reportRun = reportRun;
|
|
12
|
+
exports.tempFile = tempFile;
|
|
13
|
+
exports.makeAttachmentDir = makeAttachmentDir;
|
|
14
|
+
exports.resolveDestDir = resolveDestDir;
|
|
15
|
+
// Process-wide knobs and shared scratch-file handling for the generated
|
|
16
|
+
// PowerShell / AppleScript runs.
|
|
17
|
+
//
|
|
18
|
+
// Every call in this package works by generating a script and shelling out to an
|
|
19
|
+
// interpreter, which leaves a consumer four things they cannot otherwise reach:
|
|
20
|
+
// how long a run may take, how much it may print, how to call it off, and what
|
|
21
|
+
// the script actually said when it failed. Those are the settings here.
|
|
22
|
+
const async_hooks_1 = require("async_hooks");
|
|
23
|
+
const fs_1 = __importDefault(require("fs"));
|
|
24
|
+
const os_1 = __importDefault(require("os"));
|
|
25
|
+
const path_1 = __importDefault(require("path"));
|
|
26
|
+
const envDebug = process.env.OUTLOOK_BRIDGE_DEBUG;
|
|
27
|
+
/** The process-wide defaults, as mutated by `configure()`. */
|
|
28
|
+
const globalConfig = {
|
|
29
|
+
timeoutMs: 120000,
|
|
30
|
+
maxBufferBytes: 8 * 1024 * 1024,
|
|
31
|
+
tempDir: os_1.default.tmpdir(),
|
|
32
|
+
debug: !!envDebug && envDebug !== '0',
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Per-instance config, scoped to an async call tree.
|
|
36
|
+
*
|
|
37
|
+
* `createOutlookBridge()` hands each instance its own settings, but the platform
|
|
38
|
+
* services are 3,000 lines of module-level functions that read `getConfig()`
|
|
39
|
+
* directly. Threading a config parameter through all of them would touch every
|
|
40
|
+
* line for no behavioural gain; an AsyncLocalStorage lets an instance wrap its
|
|
41
|
+
* calls instead, and the store follows across every `await` inside one. Two
|
|
42
|
+
* bridges with different timeouts can then run concurrently in one process,
|
|
43
|
+
* which is the thing a second consumer actually needs and the global could never
|
|
44
|
+
* give them.
|
|
45
|
+
*/
|
|
46
|
+
const scoped = new async_hooks_1.AsyncLocalStorage();
|
|
47
|
+
/** Merge caller options over a base, ignoring the keys they left out. */
|
|
48
|
+
function mergeOptions(base, options = {}) {
|
|
49
|
+
const next = { ...base };
|
|
50
|
+
if (options.timeoutMs !== undefined)
|
|
51
|
+
next.timeoutMs = Math.max(0, options.timeoutMs);
|
|
52
|
+
if (options.maxBufferBytes !== undefined)
|
|
53
|
+
next.maxBufferBytes = Math.max(1, options.maxBufferBytes);
|
|
54
|
+
if (options.tempDir !== undefined)
|
|
55
|
+
next.tempDir = options.tempDir;
|
|
56
|
+
if (options.signal !== undefined)
|
|
57
|
+
next.signal = options.signal;
|
|
58
|
+
if (options.debug !== undefined)
|
|
59
|
+
next.debug = options.debug;
|
|
60
|
+
return next;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Override the process-wide defaults. Merges, so naming one option leaves the
|
|
64
|
+
* rest alone. Call before the first automation call.
|
|
65
|
+
*
|
|
66
|
+
* Affects every caller in the process. Prefer `createOutlookBridge(options)` in
|
|
67
|
+
* anything that shares a process with code you don't own.
|
|
68
|
+
*/
|
|
69
|
+
function configure(options) {
|
|
70
|
+
Object.assign(globalConfig, mergeOptions(globalConfig, options));
|
|
71
|
+
}
|
|
72
|
+
/** The settings in force for the current call — the enclosing scope's, else global. */
|
|
73
|
+
function getConfig() {
|
|
74
|
+
return scoped.getStore() ?? globalConfig;
|
|
75
|
+
}
|
|
76
|
+
/** The process-wide defaults, ignoring any active scope. */
|
|
77
|
+
function getGlobalConfig() {
|
|
78
|
+
return globalConfig;
|
|
79
|
+
}
|
|
80
|
+
/** Run `fn` with `config` in force for it and everything it awaits. */
|
|
81
|
+
function withConfig(config, fn) {
|
|
82
|
+
return scoped.run(config, fn);
|
|
83
|
+
}
|
|
84
|
+
/** Report one finished script run to the configured debug hook. */
|
|
85
|
+
function reportRun(event) {
|
|
86
|
+
const { debug } = getConfig();
|
|
87
|
+
if (!debug)
|
|
88
|
+
return;
|
|
89
|
+
if (typeof debug === 'function') {
|
|
90
|
+
debug(event);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const outcome = event.error ? `FAILED: ${event.error}` : 'ok';
|
|
94
|
+
process.stderr.write(`[outlook-bridge] ${event.runner} ${event.durationMs}ms ${outcome}\n${event.script}\n`);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Path for a scratch file in the configured temp directory. The random suffix
|
|
98
|
+
* matters: two concurrent calls landing in the same millisecond would otherwise
|
|
99
|
+
* pick the same name and overwrite each other's script mid-run.
|
|
100
|
+
*/
|
|
101
|
+
function tempFile(kind, extension) {
|
|
102
|
+
const unique = `${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
|
|
103
|
+
return path_1.default.join(getConfig().tempDir, `outlook-bridge-${kind}-${unique}.${extension}`);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* A fresh directory for one call's saved attachments.
|
|
107
|
+
*
|
|
108
|
+
* Deliberately per-call rather than one shared folder: attachments are saved
|
|
109
|
+
* under the name the sender gave them, so two emails that both carry
|
|
110
|
+
* "invoice.pdf" would otherwise silently overwrite each other — and so would two
|
|
111
|
+
* unrelated programs using this package on the same machine.
|
|
112
|
+
*/
|
|
113
|
+
function makeAttachmentDir() {
|
|
114
|
+
return fs_1.default.mkdtempSync(path_1.default.join(getConfig().tempDir, 'outlook-bridge-attachments-'));
|
|
115
|
+
}
|
|
116
|
+
/** Resolve a caller-supplied destination, creating it when absent. */
|
|
117
|
+
function resolveDestDir(destDir) {
|
|
118
|
+
if (!destDir)
|
|
119
|
+
return makeAttachmentDir();
|
|
120
|
+
fs_1.default.mkdirSync(destDir, { recursive: true });
|
|
121
|
+
return destDir;
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":";;;;;AAkFA,oCAQC;AASD,8BAEC;AAGD,8BAEC;AAGD,0CAEC;AAGD,gCAEC;AAGD,8BAWC;AAOD,4BAGC;AAUD,8CAEC;AAGD,wCAIC;AA/JD,wEAAwE;AACxE,iCAAiC;AACjC,EAAE;AACF,iFAAiF;AACjF,gFAAgF;AAChF,+EAA+E;AAC/E,wEAAwE;AACxE,6CAAgD;AAChD,4CAAoB;AACpB,4CAAoB;AACpB,gDAAwB;AA+CxB,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC;AAElD,8DAA8D;AAC9D,MAAM,YAAY,GAAmB;IACjC,SAAS,EAAE,MAAO;IAClB,cAAc,EAAE,CAAC,GAAG,IAAI,GAAG,IAAI;IAC/B,OAAO,EAAE,YAAE,CAAC,MAAM,EAAE;IACpB,KAAK,EAAE,CAAC,CAAC,QAAQ,IAAI,QAAQ,KAAK,GAAG;CACxC,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,GAAG,IAAI,+BAAiB,EAAkB,CAAC;AAEvD,yEAAyE;AACzE,SAAgB,YAAY,CAAC,IAAoB,EAAE,UAAyB,EAAE;IAC1E,MAAM,IAAI,GAAmB,EAAE,GAAG,IAAI,EAAE,CAAC;IACzC,IAAI,OAAO,CAAC,SAAS,KAAK,SAAS;QAAE,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;IACrF,IAAI,OAAO,CAAC,cAAc,KAAK,SAAS;QAAE,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;IACpG,IAAI,OAAO,CAAC,OAAO,KAAK,SAAS;QAAE,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAClE,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS;QAAE,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAC/D,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS;QAAE,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;IAC5D,OAAO,IAAI,CAAC;AAChB,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,SAAS,CAAC,OAAsB;IAC5C,MAAM,CAAC,MAAM,CAAC,YAAY,EAAE,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC;AACrE,CAAC;AAED,uFAAuF;AACvF,SAAgB,SAAS;IACrB,OAAO,MAAM,CAAC,QAAQ,EAAE,IAAI,YAAY,CAAC;AAC7C,CAAC;AAED,4DAA4D;AAC5D,SAAgB,eAAe;IAC3B,OAAO,YAAY,CAAC;AACxB,CAAC;AAED,uEAAuE;AACvE,SAAgB,UAAU,CAAI,MAAsB,EAAE,EAAW;IAC7D,OAAO,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AAClC,CAAC;AAED,mEAAmE;AACnE,SAAgB,SAAS,CAAC,KAAuB;IAC7C,MAAM,EAAE,KAAK,EAAE,GAAG,SAAS,EAAE,CAAC;IAC9B,IAAI,CAAC,KAAK;QAAE,OAAO;IACnB,IAAI,OAAO,KAAK,KAAK,UAAU,EAAE,CAAC;QAC9B,KAAK,CAAC,KAAK,CAAC,CAAC;QACb,OAAO;IACX,CAAC;IACD,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,WAAW,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAC9D,OAAO,CAAC,MAAM,CAAC,KAAK,CAChB,oBAAoB,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,UAAU,MAAM,OAAO,KAAK,KAAK,CAAC,MAAM,IAAI,CACzF,CAAC;AACN,CAAC;AAED;;;;GAIG;AACH,SAAgB,QAAQ,CAAC,IAAY,EAAE,SAAiB;IACpD,MAAM,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;IAC1E,OAAO,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,OAAO,EAAE,kBAAkB,IAAI,IAAI,MAAM,IAAI,SAAS,EAAE,CAAC,CAAC;AAC3F,CAAC;AAED;;;;;;;GAOG;AACH,SAAgB,iBAAiB;IAC7B,OAAO,YAAE,CAAC,WAAW,CAAC,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,OAAO,EAAE,6BAA6B,CAAC,CAAC,CAAC;AACzF,CAAC;AAED,sEAAsE;AACtE,SAAgB,cAAc,CAAC,OAAgB;IAC3C,IAAI,CAAC,OAAO;QAAE,OAAO,iBAAiB,EAAE,CAAC;IACzC,YAAE,CAAC,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3C,OAAO,OAAO,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Collapse whitespace runs (non-breaking spaces included) and trim, so a
|
|
3
|
+
* trivially reformatted filename still resolves. Both platforms' regex engines
|
|
4
|
+
* treat `\s` as covering U+00A0, which is the character a mail client is most
|
|
5
|
+
* likely to have substituted.
|
|
6
|
+
*/
|
|
7
|
+
export declare function normalizeAttachmentName(name: string): string;
|
|
8
|
+
/**
|
|
9
|
+
* Index of the attachment matching `wanted`, or -1.
|
|
10
|
+
*
|
|
11
|
+
* Exact first, then whitespace-normalized and case-insensitive — in that order,
|
|
12
|
+
* so an email carrying two names differing only in case still resolves the one
|
|
13
|
+
* that was actually asked for.
|
|
14
|
+
*/
|
|
15
|
+
export declare function findAttachmentIndex(names: readonly string[], wanted: string): number;
|
|
16
|
+
/**
|
|
17
|
+
* The "attachment not found" message, worded once for both platforms.
|
|
18
|
+
*
|
|
19
|
+
* Every field arrives already stringified, which is what lets the Windows script
|
|
20
|
+
* build the identical sentence: it passes PowerShell interpolations
|
|
21
|
+
* (`$($item.Subject)`) where macOS passes the values it read.
|
|
22
|
+
*/
|
|
23
|
+
export declare function attachmentNotFoundMessage(init: {
|
|
24
|
+
fileName: string;
|
|
25
|
+
senderEmail: string;
|
|
26
|
+
subject: string;
|
|
27
|
+
receivedTime: string;
|
|
28
|
+
/** The attachments the email does carry, already joined for display. */
|
|
29
|
+
present: string;
|
|
30
|
+
/** What this platform calls the id, for the closing advice. */
|
|
31
|
+
idLabel: string;
|
|
32
|
+
}): string;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Matching an attachment by name, and the error when nothing matches.
|
|
3
|
+
//
|
|
4
|
+
// Both are shared because the error is the useful half. Resolving an email by id
|
|
5
|
+
// happily returns a DIFFERENT message when the id is stale or wrong — common
|
|
6
|
+
// precisely when many replies share one subject — so a bare "not found" points
|
|
7
|
+
// the caller at the wrong problem. Naming the email actually resolved, and the
|
|
8
|
+
// attachments it does carry, is what makes the mistake visible.
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.normalizeAttachmentName = normalizeAttachmentName;
|
|
11
|
+
exports.findAttachmentIndex = findAttachmentIndex;
|
|
12
|
+
exports.attachmentNotFoundMessage = attachmentNotFoundMessage;
|
|
13
|
+
/**
|
|
14
|
+
* Collapse whitespace runs (non-breaking spaces included) and trim, so a
|
|
15
|
+
* trivially reformatted filename still resolves. Both platforms' regex engines
|
|
16
|
+
* treat `\s` as covering U+00A0, which is the character a mail client is most
|
|
17
|
+
* likely to have substituted.
|
|
18
|
+
*/
|
|
19
|
+
function normalizeAttachmentName(name) {
|
|
20
|
+
return name.replace(/\s+/g, ' ').trim();
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Index of the attachment matching `wanted`, or -1.
|
|
24
|
+
*
|
|
25
|
+
* Exact first, then whitespace-normalized and case-insensitive — in that order,
|
|
26
|
+
* so an email carrying two names differing only in case still resolves the one
|
|
27
|
+
* that was actually asked for.
|
|
28
|
+
*/
|
|
29
|
+
function findAttachmentIndex(names, wanted) {
|
|
30
|
+
const exact = names.indexOf(wanted);
|
|
31
|
+
if (exact !== -1)
|
|
32
|
+
return exact;
|
|
33
|
+
const normalized = normalizeAttachmentName(wanted).toLowerCase();
|
|
34
|
+
return names.findIndex(name => normalizeAttachmentName(name).toLowerCase() === normalized);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* The "attachment not found" message, worded once for both platforms.
|
|
38
|
+
*
|
|
39
|
+
* Every field arrives already stringified, which is what lets the Windows script
|
|
40
|
+
* build the identical sentence: it passes PowerShell interpolations
|
|
41
|
+
* (`$($item.Subject)`) where macOS passes the values it read.
|
|
42
|
+
*/
|
|
43
|
+
function attachmentNotFoundMessage(init) {
|
|
44
|
+
return `Attachment '${init.fileName}' not found. `
|
|
45
|
+
+ `Resolved email: from=${init.senderEmail}; subject=${init.subject}; received=${init.receivedTime}. `
|
|
46
|
+
+ `Attachments present: ${init.present}. `
|
|
47
|
+
+ `If this is not the email you expected, the ${init.idLabel} is likely wrong or stale - `
|
|
48
|
+
+ `re-run readInboxEmails to get a current ${init.idLabel}.`;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=attachmentMatch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attachmentMatch.js","sourceRoot":"","sources":["../../src/shared/attachmentMatch.ts"],"names":[],"mappings":";AAAA,sEAAsE;AACtE,EAAE;AACF,iFAAiF;AACjF,6EAA6E;AAC7E,+EAA+E;AAC/E,+EAA+E;AAC/E,gEAAgE;;AAQhE,0DAEC;AASD,kDAKC;AASD,8DAeC;AA9CD;;;;;GAKG;AACH,SAAgB,uBAAuB,CAAC,IAAY;IAChD,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;AAC5C,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,mBAAmB,CAAC,KAAwB,EAAE,MAAc;IACxE,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACpC,IAAI,KAAK,KAAK,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IAC/B,MAAM,UAAU,GAAG,uBAAuB,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC;IACjE,OAAO,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,uBAAuB,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,KAAK,UAAU,CAAC,CAAC;AAC/F,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,yBAAyB,CAAC,IASzC;IACG,OAAO,eAAe,IAAI,CAAC,QAAQ,eAAe;UAC5C,wBAAwB,IAAI,CAAC,WAAW,aAAa,IAAI,CAAC,OAAO,cAAc,IAAI,CAAC,YAAY,IAAI;UACpG,wBAAwB,IAAI,CAAC,OAAO,IAAI;UACxC,8CAA8C,IAAI,CAAC,OAAO,8BAA8B;UACxF,2CAA2C,IAAI,CAAC,OAAO,GAAG,CAAC;AACrE,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/** Subject fragments that only a mail system writes. Matched case-insensitively. */
|
|
2
|
+
export declare const BOUNCE_SUBJECT_PHRASES: readonly string[];
|
|
3
|
+
/** Fragments of a sender ADDRESS that fingerprint a mail-delivery daemon. */
|
|
4
|
+
export declare const BOUNCE_DAEMON_ADDRESSES: readonly string[];
|
|
5
|
+
/** Fragments of a sender DISPLAY NAME that fingerprint a mail-delivery daemon. */
|
|
6
|
+
export declare const BOUNCE_DAEMON_NAMES: readonly string[];
|
|
7
|
+
/** MessageClass prefix Exchange stamps on a non-delivery report. */
|
|
8
|
+
export declare const NDR_MESSAGE_CLASS_PREFIX = "REPORT.IPM.Note.NDR";
|
|
9
|
+
/**
|
|
10
|
+
* Why this item is a bounce, or '' if it isn't.
|
|
11
|
+
*
|
|
12
|
+
* Order matches the Windows script's: the structural signal (an NDR message
|
|
13
|
+
* class) outranks the sender fingerprint, which outranks the subject phrase —
|
|
14
|
+
* so the reason a caller is shown is the strongest one that applied, not the
|
|
15
|
+
* first one that happened to be tested.
|
|
16
|
+
*/
|
|
17
|
+
export declare function bounceReason(item: {
|
|
18
|
+
subject?: string;
|
|
19
|
+
senderName?: string;
|
|
20
|
+
senderEmail?: string;
|
|
21
|
+
/** True when the item's MessageClass marks it a non-delivery report (Windows only). */
|
|
22
|
+
isNonDeliveryReport?: boolean;
|
|
23
|
+
}): string;
|
|
24
|
+
/** The address pattern both platforms scan a bounce body with. */
|
|
25
|
+
export declare const BODY_ADDRESS_PATTERN = "[A-Za-z0-9._%+\\-]+@[A-Za-z0-9.\\-]+\\.[A-Za-z]{2,}";
|
|
26
|
+
/**
|
|
27
|
+
* The addresses a bounce body names as having failed — best effort, since a
|
|
28
|
+
* bounce body is prose with no agreed structure.
|
|
29
|
+
*
|
|
30
|
+
* The account's own address and the daemon's are dropped: both appear in nearly
|
|
31
|
+
* every bounce, and neither is a send that failed.
|
|
32
|
+
*/
|
|
33
|
+
export declare function failedRecipients(body: string, accountAddress: string): string[];
|