@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.
Files changed (117) hide show
  1. package/LICENSE +190 -0
  2. package/README.md +253 -0
  3. package/dist/OutlookService.d.ts +43 -0
  4. package/dist/OutlookService.js +137 -0
  5. package/dist/OutlookService.js.map +1 -0
  6. package/dist/errors.d.ts +112 -0
  7. package/dist/errors.js +140 -0
  8. package/dist/errors.js.map +1 -0
  9. package/dist/index.d.ts +11 -0
  10. package/dist/index.js +71 -0
  11. package/dist/index.js.map +1 -0
  12. package/dist/mac/accounts.d.ts +5 -0
  13. package/dist/mac/accounts.js +17 -0
  14. package/dist/mac/accounts.js.map +1 -0
  15. package/dist/mac/attachments.d.ts +28 -0
  16. package/dist/mac/attachments.js +120 -0
  17. package/dist/mac/attachments.js.map +1 -0
  18. package/dist/mac/bounces.d.ts +32 -0
  19. package/dist/mac/bounces.js +285 -0
  20. package/dist/mac/bounces.js.map +1 -0
  21. package/dist/mac/cleanup.d.ts +29 -0
  22. package/dist/mac/cleanup.js +219 -0
  23. package/dist/mac/cleanup.js.map +1 -0
  24. package/dist/mac/drafts.d.ts +27 -0
  25. package/dist/mac/drafts.js +214 -0
  26. package/dist/mac/drafts.js.map +1 -0
  27. package/dist/mac/folders.d.ts +28 -0
  28. package/dist/mac/folders.js +127 -0
  29. package/dist/mac/folders.js.map +1 -0
  30. package/dist/mac/index.d.ts +22 -0
  31. package/dist/mac/index.js +119 -0
  32. package/dist/mac/index.js.map +1 -0
  33. package/dist/mac/read.d.ts +46 -0
  34. package/dist/mac/read.js +406 -0
  35. package/dist/mac/read.js.map +1 -0
  36. package/dist/mac/run.d.ts +64 -0
  37. package/dist/mac/run.js +250 -0
  38. package/dist/mac/run.js.map +1 -0
  39. package/dist/mac/scripts.d.ts +137 -0
  40. package/dist/mac/scripts.js +337 -0
  41. package/dist/mac/scripts.js.map +1 -0
  42. package/dist/mac/send.d.ts +23 -0
  43. package/dist/mac/send.js +135 -0
  44. package/dist/mac/send.js.map +1 -0
  45. package/dist/mac/signatures.d.ts +4 -0
  46. package/dist/mac/signatures.js +36 -0
  47. package/dist/mac/signatures.js.map +1 -0
  48. package/dist/mac/templates.d.ts +34 -0
  49. package/dist/mac/templates.js +266 -0
  50. package/dist/mac/templates.js.map +1 -0
  51. package/dist/mail.d.ts +72 -0
  52. package/dist/mail.js +131 -0
  53. package/dist/mail.js.map +1 -0
  54. package/dist/outlookTemplateSections.d.ts +62 -0
  55. package/dist/outlookTemplateSections.js +313 -0
  56. package/dist/outlookTemplateSections.js.map +1 -0
  57. package/dist/runtime.d.ts +76 -0
  58. package/dist/runtime.js +123 -0
  59. package/dist/runtime.js.map +1 -0
  60. package/dist/shared/attachmentMatch.d.ts +32 -0
  61. package/dist/shared/attachmentMatch.js +50 -0
  62. package/dist/shared/attachmentMatch.js.map +1 -0
  63. package/dist/shared/bounceRules.d.ts +33 -0
  64. package/dist/shared/bounceRules.js +104 -0
  65. package/dist/shared/bounceRules.js.map +1 -0
  66. package/dist/shared/capabilities.d.ts +3 -0
  67. package/dist/shared/capabilities.js +9 -0
  68. package/dist/shared/capabilities.js.map +1 -0
  69. package/dist/shared/json.d.ts +11 -0
  70. package/dist/shared/json.js +45 -0
  71. package/dist/shared/json.js.map +1 -0
  72. package/dist/shared/replyBody.d.ts +49 -0
  73. package/dist/shared/replyBody.js +113 -0
  74. package/dist/shared/replyBody.js.map +1 -0
  75. package/dist/types.d.ts +365 -0
  76. package/dist/types.js +13 -0
  77. package/dist/types.js.map +1 -0
  78. package/dist/windows/accounts.d.ts +2 -0
  79. package/dist/windows/accounts.js +22 -0
  80. package/dist/windows/accounts.js.map +1 -0
  81. package/dist/windows/attachments.d.ts +28 -0
  82. package/dist/windows/attachments.js +141 -0
  83. package/dist/windows/attachments.js.map +1 -0
  84. package/dist/windows/bounces.d.ts +34 -0
  85. package/dist/windows/bounces.js +267 -0
  86. package/dist/windows/bounces.js.map +1 -0
  87. package/dist/windows/cleanup.d.ts +29 -0
  88. package/dist/windows/cleanup.js +165 -0
  89. package/dist/windows/cleanup.js.map +1 -0
  90. package/dist/windows/drafts.d.ts +29 -0
  91. package/dist/windows/drafts.js +253 -0
  92. package/dist/windows/drafts.js.map +1 -0
  93. package/dist/windows/folders.d.ts +16 -0
  94. package/dist/windows/folders.js +88 -0
  95. package/dist/windows/folders.js.map +1 -0
  96. package/dist/windows/index.d.ts +27 -0
  97. package/dist/windows/index.js +100 -0
  98. package/dist/windows/index.js.map +1 -0
  99. package/dist/windows/read.d.ts +54 -0
  100. package/dist/windows/read.js +372 -0
  101. package/dist/windows/read.js.map +1 -0
  102. package/dist/windows/run.d.ts +54 -0
  103. package/dist/windows/run.js +161 -0
  104. package/dist/windows/run.js.map +1 -0
  105. package/dist/windows/scripts.d.ts +56 -0
  106. package/dist/windows/scripts.js +163 -0
  107. package/dist/windows/scripts.js.map +1 -0
  108. package/dist/windows/send.d.ts +11 -0
  109. package/dist/windows/send.js +114 -0
  110. package/dist/windows/send.js.map +1 -0
  111. package/dist/windows/signatures.d.ts +14 -0
  112. package/dist/windows/signatures.js +69 -0
  113. package/dist/windows/signatures.js.map +1 -0
  114. package/dist/windows/templates.d.ts +25 -0
  115. package/dist/windows/templates.js +246 -0
  116. package/dist/windows/templates.js.map +1 -0
  117. 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":"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"}
@@ -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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"}