@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,104 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// What counts as a bounce, defined once for both platforms.
|
|
3
|
+
//
|
|
4
|
+
// Windows classifies inside the generated PowerShell (the item body is only
|
|
5
|
+
// touched once a cheaper signal has matched, which is what keeps a large-inbox
|
|
6
|
+
// scan affordable) while macOS classifies here in TypeScript after a bulk
|
|
7
|
+
// property read. Two implementations of the RULES, though, is how "what is a
|
|
8
|
+
// bounce" quietly comes to mean two different things — so the lists live here
|
|
9
|
+
// and the PowerShell arrays are generated from them (see windows/bounces.ts).
|
|
10
|
+
//
|
|
11
|
+
// Deliberately specific, multi-word, mail-system wording: ordinary mail that
|
|
12
|
+
// merely mentions a "delivery" must never be flagged, because the caller's next
|
|
13
|
+
// move is to delete what this matches.
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.BODY_ADDRESS_PATTERN = exports.NDR_MESSAGE_CLASS_PREFIX = exports.BOUNCE_DAEMON_NAMES = exports.BOUNCE_DAEMON_ADDRESSES = exports.BOUNCE_SUBJECT_PHRASES = void 0;
|
|
16
|
+
exports.bounceReason = bounceReason;
|
|
17
|
+
exports.failedRecipients = failedRecipients;
|
|
18
|
+
/** Subject fragments that only a mail system writes. Matched case-insensitively. */
|
|
19
|
+
exports.BOUNCE_SUBJECT_PHRASES = [
|
|
20
|
+
'undeliverable',
|
|
21
|
+
'message blocked',
|
|
22
|
+
'mail delivery failed',
|
|
23
|
+
'delivery status notification (failure)',
|
|
24
|
+
'delivery has failed',
|
|
25
|
+
'failure notice',
|
|
26
|
+
'undelivered mail returned to sender',
|
|
27
|
+
'returned mail',
|
|
28
|
+
];
|
|
29
|
+
/** Fragments of a sender ADDRESS that fingerprint a mail-delivery daemon. */
|
|
30
|
+
exports.BOUNCE_DAEMON_ADDRESSES = [
|
|
31
|
+
'mailer-daemon',
|
|
32
|
+
'mailer_daemon',
|
|
33
|
+
'postmaster@',
|
|
34
|
+
'mail-daemon',
|
|
35
|
+
'maildelivery',
|
|
36
|
+
];
|
|
37
|
+
/** Fragments of a sender DISPLAY NAME that fingerprint a mail-delivery daemon. */
|
|
38
|
+
exports.BOUNCE_DAEMON_NAMES = [
|
|
39
|
+
'mail delivery subsystem',
|
|
40
|
+
'mail delivery system',
|
|
41
|
+
'microsoft outlook',
|
|
42
|
+
'postmaster',
|
|
43
|
+
'mailer-daemon',
|
|
44
|
+
'mail administrator',
|
|
45
|
+
'internet mail delivery',
|
|
46
|
+
];
|
|
47
|
+
/** MessageClass prefix Exchange stamps on a non-delivery report. */
|
|
48
|
+
exports.NDR_MESSAGE_CLASS_PREFIX = 'REPORT.IPM.Note.NDR';
|
|
49
|
+
/** Addresses never reported as a failed recipient — they are the bounce's author. */
|
|
50
|
+
const DAEMON_SELF_ADDRESSES = ['mailer-daemon', 'postmaster', 'mail-daemon'];
|
|
51
|
+
/** At most this many failed recipients per bounce; a list bounce can name hundreds. */
|
|
52
|
+
const MAX_FAILED_RECIPIENTS = 5;
|
|
53
|
+
/**
|
|
54
|
+
* Why this item is a bounce, or '' if it isn't.
|
|
55
|
+
*
|
|
56
|
+
* Order matches the Windows script's: the structural signal (an NDR message
|
|
57
|
+
* class) outranks the sender fingerprint, which outranks the subject phrase —
|
|
58
|
+
* so the reason a caller is shown is the strongest one that applied, not the
|
|
59
|
+
* first one that happened to be tested.
|
|
60
|
+
*/
|
|
61
|
+
function bounceReason(item) {
|
|
62
|
+
if (item.isNonDeliveryReport)
|
|
63
|
+
return 'Non-delivery report (NDR)';
|
|
64
|
+
const senderEmail = (item.senderEmail || '').toLowerCase();
|
|
65
|
+
if (exports.BOUNCE_DAEMON_ADDRESSES.some(fragment => senderEmail.includes(fragment))) {
|
|
66
|
+
return 'From mail-delivery system';
|
|
67
|
+
}
|
|
68
|
+
const senderName = (item.senderName || '').toLowerCase();
|
|
69
|
+
if (exports.BOUNCE_DAEMON_NAMES.some(fragment => senderName.includes(fragment))) {
|
|
70
|
+
return 'From mail-delivery system';
|
|
71
|
+
}
|
|
72
|
+
const subject = (item.subject || '').toLowerCase();
|
|
73
|
+
const phrase = exports.BOUNCE_SUBJECT_PHRASES.find(p => subject.includes(p));
|
|
74
|
+
return phrase ? `Bounce subject phrase: '${phrase}'` : '';
|
|
75
|
+
}
|
|
76
|
+
/** The address pattern both platforms scan a bounce body with. */
|
|
77
|
+
exports.BODY_ADDRESS_PATTERN = '[A-Za-z0-9._%+\\-]+@[A-Za-z0-9.\\-]+\\.[A-Za-z]{2,}';
|
|
78
|
+
/**
|
|
79
|
+
* The addresses a bounce body names as having failed — best effort, since a
|
|
80
|
+
* bounce body is prose with no agreed structure.
|
|
81
|
+
*
|
|
82
|
+
* The account's own address and the daemon's are dropped: both appear in nearly
|
|
83
|
+
* every bounce, and neither is a send that failed.
|
|
84
|
+
*/
|
|
85
|
+
function failedRecipients(body, accountAddress) {
|
|
86
|
+
if (!body)
|
|
87
|
+
return [];
|
|
88
|
+
const target = (accountAddress || '').toLowerCase();
|
|
89
|
+
const found = [];
|
|
90
|
+
for (const match of body.matchAll(new RegExp(exports.BODY_ADDRESS_PATTERN, 'g'))) {
|
|
91
|
+
const address = match[0].toLowerCase().replace(/\.+$/, '');
|
|
92
|
+
if (address === target)
|
|
93
|
+
continue;
|
|
94
|
+
if (DAEMON_SELF_ADDRESSES.some(fragment => address.includes(fragment)))
|
|
95
|
+
continue;
|
|
96
|
+
if (found.includes(address))
|
|
97
|
+
continue;
|
|
98
|
+
found.push(address);
|
|
99
|
+
if (found.length >= MAX_FAILED_RECIPIENTS)
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
return found;
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=bounceRules.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bounceRules.js","sourceRoot":"","sources":["../../src/shared/bounceRules.ts"],"names":[],"mappings":";AAAA,4DAA4D;AAC5D,EAAE;AACF,4EAA4E;AAC5E,+EAA+E;AAC/E,0EAA0E;AAC1E,6EAA6E;AAC7E,8EAA8E;AAC9E,8EAA8E;AAC9E,EAAE;AACF,6EAA6E;AAC7E,gFAAgF;AAChF,uCAAuC;;;AAmDvC,oCAoBC;AAYD,4CAaC;AA9FD,oFAAoF;AACvE,QAAA,sBAAsB,GAAsB;IACrD,eAAe;IACf,iBAAiB;IACjB,sBAAsB;IACtB,wCAAwC;IACxC,qBAAqB;IACrB,gBAAgB;IAChB,qCAAqC;IACrC,eAAe;CAClB,CAAC;AAEF,6EAA6E;AAChE,QAAA,uBAAuB,GAAsB;IACtD,eAAe;IACf,eAAe;IACf,aAAa;IACb,aAAa;IACb,cAAc;CACjB,CAAC;AAEF,kFAAkF;AACrE,QAAA,mBAAmB,GAAsB;IAClD,yBAAyB;IACzB,sBAAsB;IACtB,mBAAmB;IACnB,YAAY;IACZ,eAAe;IACf,oBAAoB;IACpB,wBAAwB;CAC3B,CAAC;AAEF,oEAAoE;AACvD,QAAA,wBAAwB,GAAG,qBAAqB,CAAC;AAE9D,qFAAqF;AACrF,MAAM,qBAAqB,GAAG,CAAC,eAAe,EAAE,YAAY,EAAE,aAAa,CAAC,CAAC;AAE7E,uFAAuF;AACvF,MAAM,qBAAqB,GAAG,CAAC,CAAC;AAEhC;;;;;;;GAOG;AACH,SAAgB,YAAY,CAAC,IAM5B;IACG,IAAI,IAAI,CAAC,mBAAmB;QAAE,OAAO,2BAA2B,CAAC;IAEjE,MAAM,WAAW,GAAG,CAAC,IAAI,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;IAC3D,IAAI,+BAAuB,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,WAAW,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC;QAC3E,OAAO,2BAA2B,CAAC;IACvC,CAAC;IACD,MAAM,UAAU,GAAG,CAAC,IAAI,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;IACzD,IAAI,2BAAmB,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC;QACtE,OAAO,2BAA2B,CAAC;IACvC,CAAC;IACD,MAAM,OAAO,GAAG,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;IACnD,MAAM,MAAM,GAAG,8BAAsB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IACrE,OAAO,MAAM,CAAC,CAAC,CAAC,2BAA2B,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;AAC9D,CAAC;AAED,kEAAkE;AACrD,QAAA,oBAAoB,GAAG,qDAAqD,CAAC;AAE1F;;;;;;GAMG;AACH,SAAgB,gBAAgB,CAAC,IAAY,EAAE,cAAsB;IACjE,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,CAAC;IACrB,MAAM,MAAM,GAAG,CAAC,cAAc,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;IACpD,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,4BAAoB,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC;QACvE,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAC3D,IAAI,OAAO,KAAK,MAAM;YAAE,SAAS;QACjC,IAAI,qBAAqB,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YAAE,SAAS;QACjF,IAAI,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC;YAAE,SAAS;QACtC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACpB,IAAI,KAAK,CAAC,MAAM,IAAI,qBAAqB;YAAE,MAAM;IACrD,CAAC;IACD,OAAO,KAAK,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { BridgeCapability, CapabilityMap, OutlookBridge } from '../types';
|
|
2
|
+
/** A platform's capability map: every operation it implements, minus `notPorted`. */
|
|
3
|
+
export declare function capabilityMap(bridge: OutlookBridge, notPorted?: readonly BridgeCapability[]): CapabilityMap;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.capabilityMap = capabilityMap;
|
|
4
|
+
/** A platform's capability map: every operation it implements, minus `notPorted`. */
|
|
5
|
+
function capabilityMap(bridge, notPorted = []) {
|
|
6
|
+
const names = Object.keys(bridge);
|
|
7
|
+
return Object.freeze(Object.fromEntries(names.map(name => [name, !notPorted.includes(name)])));
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=capabilities.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capabilities.js","sourceRoot":"","sources":["../../src/shared/capabilities.ts"],"names":[],"mappings":";;AAeA,sCAQC;AATD,qFAAqF;AACrF,SAAgB,aAAa,CACzB,MAAqB,EACrB,YAAyC,EAAE;IAE3C,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAuB,CAAC;IACxD,OAAO,MAAM,CAAC,MAAM,CAChB,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAC1D,CAAC;AACvB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** Parse a script's stdout as an object, tolerating empty output and 'null'. */
|
|
2
|
+
export declare function parseObject(raw: string): Record<string, unknown>;
|
|
3
|
+
/** Parse a script's stdout as a list, absorbing ConvertTo-Json's unwrapping. */
|
|
4
|
+
export declare function parseArray(raw: string): unknown[];
|
|
5
|
+
/** One value as a list: an array stays, null becomes empty, anything else wraps. */
|
|
6
|
+
export declare function toArray(value: unknown): unknown[];
|
|
7
|
+
/** A record's field as a plain object, for mapping a list of rows. */
|
|
8
|
+
export declare function record(value: unknown): Record<string, unknown>;
|
|
9
|
+
export declare function str(value: unknown): string;
|
|
10
|
+
export declare function num(value: unknown): number;
|
|
11
|
+
export declare function strList(value: unknown): string[];
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Coercion helpers for the JSON the PowerShell scripts emit.
|
|
3
|
+
//
|
|
4
|
+
// PowerShell's ConvertTo-Json has two habits that a consumer must never see:
|
|
5
|
+
// it unwraps a single-element array to a bare object, and renders an empty one
|
|
6
|
+
// as null. Every list crossing that boundary therefore goes through `toArray`,
|
|
7
|
+
// and every scalar through a coercion that survives a missing property.
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.parseObject = parseObject;
|
|
10
|
+
exports.parseArray = parseArray;
|
|
11
|
+
exports.toArray = toArray;
|
|
12
|
+
exports.record = record;
|
|
13
|
+
exports.str = str;
|
|
14
|
+
exports.num = num;
|
|
15
|
+
exports.strList = strList;
|
|
16
|
+
/** Parse a script's stdout as an object, tolerating empty output and 'null'. */
|
|
17
|
+
function parseObject(raw) {
|
|
18
|
+
if (!raw || !raw.trim() || raw.trim() === 'null')
|
|
19
|
+
return {};
|
|
20
|
+
return JSON.parse(raw.trim());
|
|
21
|
+
}
|
|
22
|
+
/** Parse a script's stdout as a list, absorbing ConvertTo-Json's unwrapping. */
|
|
23
|
+
function parseArray(raw) {
|
|
24
|
+
if (!raw || !raw.trim() || raw.trim() === 'null')
|
|
25
|
+
return [];
|
|
26
|
+
return toArray(JSON.parse(raw.trim()));
|
|
27
|
+
}
|
|
28
|
+
/** One value as a list: an array stays, null becomes empty, anything else wraps. */
|
|
29
|
+
function toArray(value) {
|
|
30
|
+
return Array.isArray(value) ? value : value == null ? [] : [value];
|
|
31
|
+
}
|
|
32
|
+
/** A record's field as a plain object, for mapping a list of rows. */
|
|
33
|
+
function record(value) {
|
|
34
|
+
return (value ?? {});
|
|
35
|
+
}
|
|
36
|
+
function str(value) {
|
|
37
|
+
return value == null ? '' : String(value);
|
|
38
|
+
}
|
|
39
|
+
function num(value) {
|
|
40
|
+
return typeof value === 'number' ? value : 0;
|
|
41
|
+
}
|
|
42
|
+
function strList(value) {
|
|
43
|
+
return toArray(value).map(str).filter(Boolean);
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=json.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json.js","sourceRoot":"","sources":["../../src/shared/json.ts"],"names":[],"mappings":";AAAA,6DAA6D;AAC7D,EAAE;AACF,6EAA6E;AAC7E,+EAA+E;AAC/E,+EAA+E;AAC/E,wEAAwE;;AAGxE,kCAGC;AAGD,gCAGC;AAGD,0BAEC;AAGD,wBAEC;AAED,kBAEC;AAED,kBAEC;AAED,0BAEC;AAhCD,gFAAgF;AAChF,SAAgB,WAAW,CAAC,GAAW;IACnC,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,GAAG,CAAC,IAAI,EAAE,KAAK,MAAM;QAAE,OAAO,EAAE,CAAC;IAC5D,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,CAA4B,CAAC;AAC7D,CAAC;AAED,gFAAgF;AAChF,SAAgB,UAAU,CAAC,GAAW;IAClC,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,GAAG,CAAC,IAAI,EAAE,KAAK,MAAM;QAAE,OAAO,EAAE,CAAC;IAC5D,OAAO,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;AAC3C,CAAC;AAED,oFAAoF;AACpF,SAAgB,OAAO,CAAC,KAAc;IAClC,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;AACvE,CAAC;AAED,sEAAsE;AACtE,SAAgB,MAAM,CAAC,KAAc;IACjC,OAAO,CAAC,KAAK,IAAI,EAAE,CAA4B,CAAC;AACpD,CAAC;AAED,SAAgB,GAAG,CAAC,KAAc;IAC9B,OAAO,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC9C,CAAC;AAED,SAAgB,GAAG,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AACjD,CAAC;AAED,SAAgB,OAAO,CAAC,KAAc;IAClC,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;AACnD,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { ReplyEmailParams, TemplateFolderResult } from '../types';
|
|
2
|
+
/** The reads a platform must supply for a template- or signature-backed reply. */
|
|
3
|
+
export interface ReplyBodyDeps {
|
|
4
|
+
readTemplateEmails(emailAccount: string, folderName?: string, limit?: number, includeBody?: boolean, subject?: string): Promise<TemplateFolderResult>;
|
|
5
|
+
readOutlookSignatureHtml(name: string): Promise<string>;
|
|
6
|
+
listOutlookSignatures(): Promise<string[]>;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* The content of an HTML document's `<body>`, or the input when there is no
|
|
10
|
+
* document around it.
|
|
11
|
+
*
|
|
12
|
+
* Both things this is used on — a signature file and a saved template — are whole
|
|
13
|
+
* HTML documents, and neither may nest its `<html>`/`<body>` inside the reply's.
|
|
14
|
+
*/
|
|
15
|
+
export declare function innerBodyHtml(html: string): string;
|
|
16
|
+
/**
|
|
17
|
+
* Resolve a saved template's HTML by subject, so a reply can name a template
|
|
18
|
+
* instead of carrying its (often large, Word-generated) HTML.
|
|
19
|
+
*
|
|
20
|
+
* The read is filtered by subject in the platform layer rather than here:
|
|
21
|
+
* unfiltered, EVERY template's full body crosses the interpreter's stdout on
|
|
22
|
+
* every reply, and a folder of Word-sized templates overruns the buffer outright
|
|
23
|
+
* — turning a growing Templates folder into a failure on a call that never
|
|
24
|
+
* needed more than one body.
|
|
25
|
+
*/
|
|
26
|
+
export declare function resolveTemplateHtmlBySubject(deps: ReplyBodyDeps, emailAccount: string, folderName: string, subject: string): Promise<string>;
|
|
27
|
+
/**
|
|
28
|
+
* The HTML to insert above the quoted original: template resolved, section
|
|
29
|
+
* chosen, placeholders and signature filled, document wrapper removed.
|
|
30
|
+
*
|
|
31
|
+
* Composition also runs (with no options) on any body taken straight from a
|
|
32
|
+
* template, so a stray [[SECTION]] marker is caught here rather than mailed to a
|
|
33
|
+
* customer.
|
|
34
|
+
*/
|
|
35
|
+
export declare function composeReplyHtml(params: ReplyEmailParams, deps: ReplyBodyDeps): Promise<string>;
|
|
36
|
+
/**
|
|
37
|
+
* Where the new text goes in an Outlook-built reply.
|
|
38
|
+
*
|
|
39
|
+
* Outlook builds the reply body as a Word document whose own (empty) paragraph
|
|
40
|
+
* sits inside `WordSection1`; inserting straight after that div's opening tag is
|
|
41
|
+
* what puts the new text where the user's cursor would have been. A reply
|
|
42
|
+
* Outlook did not build that way falls back to just inside `<body>`.
|
|
43
|
+
*
|
|
44
|
+
* The insertion itself cannot live here — the reply HTML never leaves Outlook,
|
|
45
|
+
* so each platform splices it in its own language (`windows/send.ts`, and the
|
|
46
|
+
* `insertAboveQuoted` handler in `mac/run.ts`). The anchor both of them look for
|
|
47
|
+
* is the one part they must agree on, so it is stated once, here.
|
|
48
|
+
*/
|
|
49
|
+
export declare const WORD_SECTION_ANCHOR = "WordSection1>";
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WORD_SECTION_ANCHOR = void 0;
|
|
4
|
+
exports.innerBodyHtml = innerBodyHtml;
|
|
5
|
+
exports.resolveTemplateHtmlBySubject = resolveTemplateHtmlBySubject;
|
|
6
|
+
exports.composeReplyHtml = composeReplyHtml;
|
|
7
|
+
// Everything replyOutlookEmail does BEFORE it touches Outlook.
|
|
8
|
+
//
|
|
9
|
+
// Resolving a named template, filling {{PLACEHOLDER}}s, substituting a named
|
|
10
|
+
// signature and reducing the result to insertable HTML is identical work on both
|
|
11
|
+
// platforms — it is string handling plus two reads that each platform already
|
|
12
|
+
// implements. Keeping it here is what lets macOS answer the same
|
|
13
|
+
// ReplyEmailParams contract Windows does instead of a subset of it.
|
|
14
|
+
const outlookTemplateSections_1 = require("../outlookTemplateSections");
|
|
15
|
+
const errors_1 = require("../errors");
|
|
16
|
+
/**
|
|
17
|
+
* The content of an HTML document's `<body>`, or the input when there is no
|
|
18
|
+
* document around it.
|
|
19
|
+
*
|
|
20
|
+
* Both things this is used on — a signature file and a saved template — are whole
|
|
21
|
+
* HTML documents, and neither may nest its `<html>`/`<body>` inside the reply's.
|
|
22
|
+
*/
|
|
23
|
+
function innerBodyHtml(html) {
|
|
24
|
+
const match = /<body[^>]*>([\s\S]*)<\/body>/i.exec(html);
|
|
25
|
+
return (match ? match[1] : html).trim();
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Resolve a saved template's HTML by subject, so a reply can name a template
|
|
29
|
+
* instead of carrying its (often large, Word-generated) HTML.
|
|
30
|
+
*
|
|
31
|
+
* The read is filtered by subject in the platform layer rather than here:
|
|
32
|
+
* unfiltered, EVERY template's full body crosses the interpreter's stdout on
|
|
33
|
+
* every reply, and a folder of Word-sized templates overruns the buffer outright
|
|
34
|
+
* — turning a growing Templates folder into a failure on a call that never
|
|
35
|
+
* needed more than one body.
|
|
36
|
+
*/
|
|
37
|
+
async function resolveTemplateHtmlBySubject(deps, emailAccount, folderName, subject) {
|
|
38
|
+
const result = await deps.readTemplateEmails(emailAccount, folderName, 50, true, subject);
|
|
39
|
+
if (!result.folderFound) {
|
|
40
|
+
const folders = result.availableFolders.join(', ') || '(none)';
|
|
41
|
+
throw new errors_1.NotFoundError('folder', `Template folder '${folderName}' not found in ${emailAccount}. Available folders: ${folders}.`);
|
|
42
|
+
}
|
|
43
|
+
const want = subject.trim().toLowerCase();
|
|
44
|
+
const match = result.templates.find(t => t.subject.trim().toLowerCase() === want);
|
|
45
|
+
if (!match) {
|
|
46
|
+
// The read above was filtered, so it can't name the alternatives. List them
|
|
47
|
+
// in a second pass with bodies omitted — which is what makes reading the
|
|
48
|
+
// whole folder safe here, and keeps the error as useful as it was before
|
|
49
|
+
// the filter.
|
|
50
|
+
const all = await deps.readTemplateEmails(emailAccount, folderName, 50, false);
|
|
51
|
+
const names = all.templates.map(t => t.subject).filter(Boolean).join(', ') || '(none)';
|
|
52
|
+
throw new errors_1.NotFoundError('template', `Template '${subject}' not found in '${folderName}'. Available templates: ${names}.`);
|
|
53
|
+
}
|
|
54
|
+
if (!match.htmlBody || match.htmlBody.trim() === '') {
|
|
55
|
+
throw new errors_1.NotFoundError('template', `Template '${subject}' has an empty HTML body.`);
|
|
56
|
+
}
|
|
57
|
+
return match.htmlBody;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* The HTML to insert above the quoted original: template resolved, section
|
|
61
|
+
* chosen, placeholders and signature filled, document wrapper removed.
|
|
62
|
+
*
|
|
63
|
+
* Composition also runs (with no options) on any body taken straight from a
|
|
64
|
+
* template, so a stray [[SECTION]] marker is caught here rather than mailed to a
|
|
65
|
+
* customer.
|
|
66
|
+
*/
|
|
67
|
+
async function composeReplyHtml(params, deps) {
|
|
68
|
+
let htmlBody = params.htmlBody;
|
|
69
|
+
let fromTemplate = false;
|
|
70
|
+
if ((!htmlBody || htmlBody.trim() === '') && params.templateSubject) {
|
|
71
|
+
htmlBody = await resolveTemplateHtmlBySubject(deps, params.emailAccount, params.templateFolder || 'Templates', params.templateSubject);
|
|
72
|
+
fromTemplate = true;
|
|
73
|
+
}
|
|
74
|
+
if (!htmlBody || htmlBody.trim() === '') {
|
|
75
|
+
throw new errors_1.InvalidRequestError('replyOutlookEmail needs either htmlBody or a resolvable templateSubject.');
|
|
76
|
+
}
|
|
77
|
+
// A named signature fills {{SIGNATURE}} like any other placeholder, but is
|
|
78
|
+
// read here so the caller never carries the signature HTML — images and all —
|
|
79
|
+
// across the wire.
|
|
80
|
+
let placeholders = params.templatePlaceholders;
|
|
81
|
+
if (params.signatureName) {
|
|
82
|
+
const signatureHtml = await deps.readOutlookSignatureHtml(params.signatureName);
|
|
83
|
+
if (signatureHtml.trim() === '') {
|
|
84
|
+
const available = (await deps.listOutlookSignatures()).join(', ') || '(none)';
|
|
85
|
+
throw new errors_1.NotFoundError('signature', `Outlook signature '${params.signatureName}' not found. Available signatures: ${available}.`);
|
|
86
|
+
}
|
|
87
|
+
placeholders = { ...placeholders, SIGNATURE: innerBodyHtml(signatureHtml) };
|
|
88
|
+
}
|
|
89
|
+
const hasPlaceholders = !!placeholders && Object.keys(placeholders).length > 0;
|
|
90
|
+
if (fromTemplate || params.templateSection || hasPlaceholders) {
|
|
91
|
+
htmlBody = (0, outlookTemplateSections_1.composeTemplateBody)(htmlBody, {
|
|
92
|
+
section: params.templateSection,
|
|
93
|
+
placeholders,
|
|
94
|
+
label: params.templateSubject,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
return innerBodyHtml(htmlBody);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Where the new text goes in an Outlook-built reply.
|
|
101
|
+
*
|
|
102
|
+
* Outlook builds the reply body as a Word document whose own (empty) paragraph
|
|
103
|
+
* sits inside `WordSection1`; inserting straight after that div's opening tag is
|
|
104
|
+
* what puts the new text where the user's cursor would have been. A reply
|
|
105
|
+
* Outlook did not build that way falls back to just inside `<body>`.
|
|
106
|
+
*
|
|
107
|
+
* The insertion itself cannot live here — the reply HTML never leaves Outlook,
|
|
108
|
+
* so each platform splices it in its own language (`windows/send.ts`, and the
|
|
109
|
+
* `insertAboveQuoted` handler in `mac/run.ts`). The anchor both of them look for
|
|
110
|
+
* is the one part they must agree on, so it is stated once, here.
|
|
111
|
+
*/
|
|
112
|
+
exports.WORD_SECTION_ANCHOR = 'WordSection1>';
|
|
113
|
+
//# sourceMappingURL=replyBody.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"replyBody.js","sourceRoot":"","sources":["../../src/shared/replyBody.ts"],"names":[],"mappings":"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"}
|