@holo-js/mail 0.1.3
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/dist/chunk-UB6ANQ2F.mjs +552 -0
- package/dist/contracts.d.ts +320 -0
- package/dist/contracts.mjs +36 -0
- package/dist/index.d.ts +379 -0
- package/dist/index.mjs +1321 -0
- package/package.json +52 -0
|
@@ -0,0 +1,552 @@
|
|
|
1
|
+
// src/contracts.ts
|
|
2
|
+
import { defineMailConfig } from "@holo-js/config";
|
|
3
|
+
var HOLO_MAIL_DEFINITION_MARKER = /* @__PURE__ */ Symbol.for("holo-js.mail.definition");
|
|
4
|
+
var BUILT_IN_MAIL_DRIVERS = ["preview", "log", "fake", "smtp"];
|
|
5
|
+
var MAIL_PRIORITY_VALUES = ["high", "normal", "low"];
|
|
6
|
+
var MAIL_ATTACHMENT_DISPOSITIONS = ["attachment", "inline"];
|
|
7
|
+
function isObject(value) {
|
|
8
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
9
|
+
}
|
|
10
|
+
function normalizeOptionalString(value, label) {
|
|
11
|
+
if (typeof value === "undefined") {
|
|
12
|
+
return void 0;
|
|
13
|
+
}
|
|
14
|
+
const normalized = value.trim();
|
|
15
|
+
if (!normalized) {
|
|
16
|
+
throw new Error(`[@holo-js/mail] ${label} must be a non-empty string when provided.`);
|
|
17
|
+
}
|
|
18
|
+
return normalized;
|
|
19
|
+
}
|
|
20
|
+
function normalizeRequiredString(value, label) {
|
|
21
|
+
const normalized = value.trim();
|
|
22
|
+
if (!normalized) {
|
|
23
|
+
throw new Error(`[@holo-js/mail] ${label} must be a non-empty string.`);
|
|
24
|
+
}
|
|
25
|
+
return normalized;
|
|
26
|
+
}
|
|
27
|
+
function normalizeDelayValue(value, label) {
|
|
28
|
+
if (typeof value === "number") {
|
|
29
|
+
if (!Number.isFinite(value) || value < 0) {
|
|
30
|
+
throw new Error(`[@holo-js/mail] ${label} must be a finite number greater than or equal to 0.`);
|
|
31
|
+
}
|
|
32
|
+
return value;
|
|
33
|
+
}
|
|
34
|
+
if (!(value instanceof Date) || Number.isNaN(value.getTime())) {
|
|
35
|
+
throw new Error(`[@holo-js/mail] ${label} dates must be valid Date instances.`);
|
|
36
|
+
}
|
|
37
|
+
return value;
|
|
38
|
+
}
|
|
39
|
+
function normalizeJsonValue(value, label) {
|
|
40
|
+
if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
41
|
+
return value;
|
|
42
|
+
}
|
|
43
|
+
if (Array.isArray(value)) {
|
|
44
|
+
return Object.freeze(value.map((entry, index) => normalizeJsonValue(entry, `${label}[${index}]`)));
|
|
45
|
+
}
|
|
46
|
+
if (isObject(value)) {
|
|
47
|
+
return Object.freeze(Object.fromEntries(Object.entries(value).map(([key, entry]) => {
|
|
48
|
+
return [key, normalizeJsonValue(entry, `${label}.${key}`)];
|
|
49
|
+
})));
|
|
50
|
+
}
|
|
51
|
+
throw new Error(`[@holo-js/mail] ${label} must be JSON-serializable.`);
|
|
52
|
+
}
|
|
53
|
+
function normalizeHeaders(headers) {
|
|
54
|
+
if (!headers) {
|
|
55
|
+
return Object.freeze({});
|
|
56
|
+
}
|
|
57
|
+
if (!isObject(headers)) {
|
|
58
|
+
throw new Error("[@holo-js/mail] Mail headers must be a plain object when provided.");
|
|
59
|
+
}
|
|
60
|
+
return Object.freeze(Object.fromEntries(Object.entries(headers).map(([key, value]) => {
|
|
61
|
+
const normalizedKey = normalizeRequiredString(key, "Mail header name");
|
|
62
|
+
if (typeof value !== "string") {
|
|
63
|
+
throw new Error(`[@holo-js/mail] Mail header "${normalizedKey}" must be a string.`);
|
|
64
|
+
}
|
|
65
|
+
return [normalizedKey, value];
|
|
66
|
+
})));
|
|
67
|
+
}
|
|
68
|
+
function normalizeTags(tags) {
|
|
69
|
+
if (typeof tags === "undefined") {
|
|
70
|
+
return Object.freeze([]);
|
|
71
|
+
}
|
|
72
|
+
const seen = /* @__PURE__ */ new Set();
|
|
73
|
+
const normalized = [];
|
|
74
|
+
for (const tag of tags) {
|
|
75
|
+
const value = normalizeRequiredString(tag, "Mail tag");
|
|
76
|
+
if (!seen.has(value)) {
|
|
77
|
+
seen.add(value);
|
|
78
|
+
normalized.push(value);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return Object.freeze(normalized);
|
|
82
|
+
}
|
|
83
|
+
function normalizeViewIdentifier(value, label) {
|
|
84
|
+
const normalized = normalizeRequiredString(value, label);
|
|
85
|
+
if (normalized.startsWith("/") || normalized.includes("\\")) {
|
|
86
|
+
throw new Error(`[@holo-js/mail] ${label} must be a relative mail view identifier.`);
|
|
87
|
+
}
|
|
88
|
+
const segments = normalized.split("/");
|
|
89
|
+
if (segments.some((segment) => segment === "." || segment === ".." || !segment.trim())) {
|
|
90
|
+
throw new Error(`[@holo-js/mail] ${label} must not include empty, "." or ".." path segments.`);
|
|
91
|
+
}
|
|
92
|
+
return normalized;
|
|
93
|
+
}
|
|
94
|
+
function isValidEmail(value) {
|
|
95
|
+
if (value.includes(" ")) {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
const parts = value.split("@");
|
|
99
|
+
return parts.length === 2 && parts[0].length > 0 && parts[1].length > 0;
|
|
100
|
+
}
|
|
101
|
+
function normalizeAddress(input, label) {
|
|
102
|
+
const value = typeof input === "string" ? { email: input } : input;
|
|
103
|
+
if (!isObject(value) || typeof value.email !== "string") {
|
|
104
|
+
throw new Error(`[@holo-js/mail] ${label} must be an email string or an object with email.`);
|
|
105
|
+
}
|
|
106
|
+
const email = normalizeRequiredString(value.email, `${label} email`).toLowerCase();
|
|
107
|
+
if (!isValidEmail(email)) {
|
|
108
|
+
throw new Error(`[@holo-js/mail] ${label} email must be a valid email address.`);
|
|
109
|
+
}
|
|
110
|
+
const name = typeof value.name === "string" ? normalizeOptionalString(value.name, `${label} name`) : void 0;
|
|
111
|
+
return Object.freeze({
|
|
112
|
+
email,
|
|
113
|
+
...name ? { name } : {}
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
function normalizeRecipients(value, label, required) {
|
|
117
|
+
if (typeof value === "undefined") {
|
|
118
|
+
if (required) {
|
|
119
|
+
throw new Error(`[@holo-js/mail] ${label} must include at least one recipient.`);
|
|
120
|
+
}
|
|
121
|
+
return Object.freeze([]);
|
|
122
|
+
}
|
|
123
|
+
const inputs = Array.isArray(value) ? value : [value];
|
|
124
|
+
const recipients = [];
|
|
125
|
+
const seen = /* @__PURE__ */ new Set();
|
|
126
|
+
for (const entry of inputs) {
|
|
127
|
+
const normalized = normalizeAddress(entry, label);
|
|
128
|
+
if (!seen.has(normalized.email)) {
|
|
129
|
+
seen.add(normalized.email);
|
|
130
|
+
recipients.push(normalized);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if (required && recipients.length === 0) {
|
|
134
|
+
throw new Error(`[@holo-js/mail] ${label} must include at least one recipient.`);
|
|
135
|
+
}
|
|
136
|
+
return Object.freeze(recipients);
|
|
137
|
+
}
|
|
138
|
+
function normalizePriority(value) {
|
|
139
|
+
if (typeof value === "undefined") {
|
|
140
|
+
return void 0;
|
|
141
|
+
}
|
|
142
|
+
if (MAIL_PRIORITY_VALUES.includes(value)) {
|
|
143
|
+
return value;
|
|
144
|
+
}
|
|
145
|
+
throw new Error(`[@holo-js/mail] Mail priority must be one of: ${MAIL_PRIORITY_VALUES.join(", ")}.`);
|
|
146
|
+
}
|
|
147
|
+
function normalizeAttachmentDisposition(value) {
|
|
148
|
+
return value === "inline" ? "inline" : "attachment";
|
|
149
|
+
}
|
|
150
|
+
function normalizeAttachmentContentId(value, disposition) {
|
|
151
|
+
if (typeof value === "undefined") {
|
|
152
|
+
if (disposition === "inline") {
|
|
153
|
+
throw new Error("[@holo-js/mail] Inline attachments must define a contentId.");
|
|
154
|
+
}
|
|
155
|
+
return void 0;
|
|
156
|
+
}
|
|
157
|
+
const normalized = normalizeRequiredString(value.replace(/^<|>$/g, ""), "Mail attachment contentId");
|
|
158
|
+
if (disposition === "inline" && !normalized) {
|
|
159
|
+
throw new Error("[@holo-js/mail] Inline attachments must define a contentId.");
|
|
160
|
+
}
|
|
161
|
+
return normalized;
|
|
162
|
+
}
|
|
163
|
+
function inferAttachmentName(value) {
|
|
164
|
+
if (typeof value.name === "string" && value.name.trim()) {
|
|
165
|
+
return value.name.trim();
|
|
166
|
+
}
|
|
167
|
+
if ("path" in value) {
|
|
168
|
+
const parts = value.path.split("/");
|
|
169
|
+
return parts[parts.length - 1]?.trim() || void 0;
|
|
170
|
+
}
|
|
171
|
+
if ("storage" in value) {
|
|
172
|
+
const parts = value.storage.path.split("/");
|
|
173
|
+
return parts[parts.length - 1]?.trim() || void 0;
|
|
174
|
+
}
|
|
175
|
+
return void 0;
|
|
176
|
+
}
|
|
177
|
+
var ATTACHMENT_MIME_TYPES = Object.freeze({
|
|
178
|
+
csv: "text/csv",
|
|
179
|
+
gif: "image/gif",
|
|
180
|
+
htm: "text/html",
|
|
181
|
+
html: "text/html",
|
|
182
|
+
jpeg: "image/jpeg",
|
|
183
|
+
jpg: "image/jpeg",
|
|
184
|
+
json: "application/json",
|
|
185
|
+
md: "text/markdown",
|
|
186
|
+
pdf: "application/pdf",
|
|
187
|
+
png: "image/png",
|
|
188
|
+
svg: "image/svg+xml",
|
|
189
|
+
txt: "text/plain",
|
|
190
|
+
webp: "image/webp",
|
|
191
|
+
xml: "application/xml"
|
|
192
|
+
});
|
|
193
|
+
function inferMimeTypeFromName(name) {
|
|
194
|
+
if (!name) {
|
|
195
|
+
return void 0;
|
|
196
|
+
}
|
|
197
|
+
const extension = name.split(".").pop()?.trim().toLowerCase();
|
|
198
|
+
if (!extension) {
|
|
199
|
+
return void 0;
|
|
200
|
+
}
|
|
201
|
+
return ATTACHMENT_MIME_TYPES[extension];
|
|
202
|
+
}
|
|
203
|
+
function inferAttachmentSource(value) {
|
|
204
|
+
if ("path" in value) {
|
|
205
|
+
return "path";
|
|
206
|
+
}
|
|
207
|
+
if ("storage" in value) {
|
|
208
|
+
return "storage";
|
|
209
|
+
}
|
|
210
|
+
if ("content" in value) {
|
|
211
|
+
return "content";
|
|
212
|
+
}
|
|
213
|
+
return "resolve";
|
|
214
|
+
}
|
|
215
|
+
function createAttachmentMetadata(attachment) {
|
|
216
|
+
return Object.freeze({
|
|
217
|
+
source: inferAttachmentSource(attachment),
|
|
218
|
+
name: inferAttachmentName(attachment),
|
|
219
|
+
contentType: attachment.contentType ?? inferMimeTypeFromName(inferAttachmentName(attachment)),
|
|
220
|
+
disposition: attachment.disposition ?? "attachment",
|
|
221
|
+
contentId: attachment.contentId
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
function normalizeAttachment(input, index) {
|
|
225
|
+
if (!isObject(input)) {
|
|
226
|
+
throw new Error(`[@holo-js/mail] Mail attachment #${index + 1} must be a plain object.`);
|
|
227
|
+
}
|
|
228
|
+
const disposition = normalizeAttachmentDisposition(input.disposition);
|
|
229
|
+
const contentId = normalizeAttachmentContentId(input.contentId, disposition);
|
|
230
|
+
const name = inferAttachmentName(input);
|
|
231
|
+
const contentType = typeof input.contentType === "string" ? normalizeRequiredString(input.contentType, `Mail attachment #${index + 1} contentType`) : inferMimeTypeFromName(name);
|
|
232
|
+
const base = {
|
|
233
|
+
...name ? { name } : {},
|
|
234
|
+
...contentType ? { contentType } : {},
|
|
235
|
+
disposition,
|
|
236
|
+
...contentId ? { contentId } : {}
|
|
237
|
+
};
|
|
238
|
+
if ("path" in input) {
|
|
239
|
+
if (typeof input.path !== "string") {
|
|
240
|
+
throw new Error(`[@holo-js/mail] Mail attachment #${index + 1} path attachments must include a path.`);
|
|
241
|
+
}
|
|
242
|
+
return Object.freeze({
|
|
243
|
+
...base,
|
|
244
|
+
path: normalizeRequiredString(input.path, `Mail attachment #${index + 1} path`)
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
if ("storage" in input) {
|
|
248
|
+
if (!isObject(input.storage) || typeof input.storage.path !== "string") {
|
|
249
|
+
throw new Error(`[@holo-js/mail] Mail attachment #${index + 1} storage attachments must include a path.`);
|
|
250
|
+
}
|
|
251
|
+
return Object.freeze({
|
|
252
|
+
...base,
|
|
253
|
+
storage: Object.freeze({
|
|
254
|
+
path: normalizeRequiredString(input.storage.path, `Mail attachment #${index + 1} storage path`),
|
|
255
|
+
...typeof input.storage.disk === "string" ? { disk: normalizeRequiredString(input.storage.disk, `Mail attachment #${index + 1} storage disk`) } : {}
|
|
256
|
+
})
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
if ("content" in input) {
|
|
260
|
+
if (!(typeof input.content === "string" || input.content instanceof Uint8Array)) {
|
|
261
|
+
throw new Error(`[@holo-js/mail] Mail attachment #${index + 1} content attachments must use a string or Uint8Array.`);
|
|
262
|
+
}
|
|
263
|
+
const attachmentName = name ?? normalizeOptionalString(input.name, `Mail attachment #${index + 1} name`);
|
|
264
|
+
if (!attachmentName) {
|
|
265
|
+
throw new Error(`[@holo-js/mail] Mail attachment #${index + 1} content attachments must define a name.`);
|
|
266
|
+
}
|
|
267
|
+
return Object.freeze({
|
|
268
|
+
...base,
|
|
269
|
+
name: attachmentName,
|
|
270
|
+
content: input.content
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
if ("resolve" in input) {
|
|
274
|
+
if (typeof input.resolve !== "function") {
|
|
275
|
+
throw new Error(`[@holo-js/mail] Mail attachment #${index + 1} resolve attachments must define resolve().`);
|
|
276
|
+
}
|
|
277
|
+
return Object.freeze({
|
|
278
|
+
...base,
|
|
279
|
+
resolve: input.resolve
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
throw new Error(`[@holo-js/mail] Mail attachment #${index + 1} must define path, storage, content, or resolve.`);
|
|
283
|
+
}
|
|
284
|
+
function normalizeAttachments(attachments) {
|
|
285
|
+
if (typeof attachments === "undefined") {
|
|
286
|
+
return Object.freeze([]);
|
|
287
|
+
}
|
|
288
|
+
return Object.freeze(attachments.map((attachment, index) => normalizeAttachment(attachment, index)));
|
|
289
|
+
}
|
|
290
|
+
function resolveNormalizedAttachment(attachment) {
|
|
291
|
+
const metadata = createAttachmentMetadata(attachment);
|
|
292
|
+
const name = metadata.name;
|
|
293
|
+
if (!name) {
|
|
294
|
+
throw new Error("[@holo-js/mail] Attachments must resolve to a named attachment before sending.");
|
|
295
|
+
}
|
|
296
|
+
if ("path" in attachment) {
|
|
297
|
+
return Object.freeze({
|
|
298
|
+
...metadata,
|
|
299
|
+
name,
|
|
300
|
+
path: attachment.path
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
if ("storage" in attachment) {
|
|
304
|
+
return Object.freeze({
|
|
305
|
+
...metadata,
|
|
306
|
+
name,
|
|
307
|
+
storage: attachment.storage
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
if ("content" in attachment) {
|
|
311
|
+
return Object.freeze({
|
|
312
|
+
...metadata,
|
|
313
|
+
name,
|
|
314
|
+
content: attachment.content
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
throw new Error("[@holo-js/mail] Resolver attachments must be resolved before creating transport attachments.");
|
|
318
|
+
}
|
|
319
|
+
function isAttachmentQueueSafe(attachment) {
|
|
320
|
+
return !("resolve" in attachment);
|
|
321
|
+
}
|
|
322
|
+
async function resolveAttachmentDefinition(attachment) {
|
|
323
|
+
if (!("resolve" in attachment)) {
|
|
324
|
+
return attachment;
|
|
325
|
+
}
|
|
326
|
+
const resolvedPayload = await attachment.resolve();
|
|
327
|
+
if (!isObject(resolvedPayload)) {
|
|
328
|
+
throw new Error("[@holo-js/mail] Attachment resolvers must return a plain object payload.");
|
|
329
|
+
}
|
|
330
|
+
const merged = {
|
|
331
|
+
...resolvedPayload,
|
|
332
|
+
...attachment.name ? { name: attachment.name } : {},
|
|
333
|
+
...attachment.contentType ? { contentType: attachment.contentType } : {},
|
|
334
|
+
...attachment.disposition ? { disposition: attachment.disposition } : {},
|
|
335
|
+
...attachment.contentId ? { contentId: attachment.contentId } : {}
|
|
336
|
+
};
|
|
337
|
+
const normalized = normalizeAttachment(merged, 0);
|
|
338
|
+
if ("resolve" in normalized) {
|
|
339
|
+
throw new Error("[@holo-js/mail] Attachment resolvers must resolve to a path, storage, or content attachment.");
|
|
340
|
+
}
|
|
341
|
+
return normalized;
|
|
342
|
+
}
|
|
343
|
+
function createAttachmentResolutionPlan(attachment, context) {
|
|
344
|
+
const metadata = createAttachmentMetadata(attachment);
|
|
345
|
+
const queuedSafe = isAttachmentQueueSafe(attachment);
|
|
346
|
+
if (context.queued && !queuedSafe) {
|
|
347
|
+
throw new Error("[@holo-js/mail] Resolver attachments are not queue-safe and cannot be used when queueing is requested.");
|
|
348
|
+
}
|
|
349
|
+
return Object.freeze({
|
|
350
|
+
...metadata,
|
|
351
|
+
queuedSafe,
|
|
352
|
+
async resolve() {
|
|
353
|
+
const normalized = await resolveAttachmentDefinition(attachment);
|
|
354
|
+
return resolveNormalizedAttachment(normalized);
|
|
355
|
+
}
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
function createAttachmentResolutionPlans(attachments, context) {
|
|
359
|
+
return Object.freeze(attachments.map((attachment) => createAttachmentResolutionPlan(attachment, context)));
|
|
360
|
+
}
|
|
361
|
+
function normalizeRenderSource(render) {
|
|
362
|
+
if (typeof render === "undefined") {
|
|
363
|
+
return void 0;
|
|
364
|
+
}
|
|
365
|
+
if (!isObject(render)) {
|
|
366
|
+
throw new Error("[@holo-js/mail] Mail render sources must be plain objects when provided.");
|
|
367
|
+
}
|
|
368
|
+
return Object.freeze({
|
|
369
|
+
view: normalizeViewIdentifier(render.view, "Mail render view"),
|
|
370
|
+
...typeof render.props === "undefined" ? {} : { props: normalizeJsonValue(render.props, "Mail render props") }
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
function normalizeQueueOptions(value) {
|
|
374
|
+
if (typeof value === "undefined" || typeof value === "boolean") {
|
|
375
|
+
return value;
|
|
376
|
+
}
|
|
377
|
+
return Object.freeze({
|
|
378
|
+
...typeof value.queued === "boolean" ? { queued: value.queued } : {},
|
|
379
|
+
...typeof value.connection === "string" ? { connection: normalizeRequiredString(value.connection, "Mail queue connection") } : {},
|
|
380
|
+
...typeof value.queue === "string" ? { queue: normalizeRequiredString(value.queue, "Mail queue name") } : {},
|
|
381
|
+
...typeof value.afterCommit === "boolean" ? { afterCommit: value.afterCommit } : {}
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
function normalizeTextLikeContent(value, label) {
|
|
385
|
+
if (typeof value === "undefined") {
|
|
386
|
+
return void 0;
|
|
387
|
+
}
|
|
388
|
+
return normalizeRequiredString(value, label);
|
|
389
|
+
}
|
|
390
|
+
function normalizeContentSource(input) {
|
|
391
|
+
const text = normalizeTextLikeContent(input.text, "Mail text");
|
|
392
|
+
const html = normalizeTextLikeContent(input.html, "Mail html");
|
|
393
|
+
const markdown = normalizeTextLikeContent(input.markdown, "Mail markdown");
|
|
394
|
+
const render = normalizeRenderSource(input.render);
|
|
395
|
+
const markdownWrapper = typeof input.markdownWrapper === "string" ? normalizeViewIdentifier(input.markdownWrapper, "Mail markdown wrapper") : void 0;
|
|
396
|
+
const primaryKinds = [
|
|
397
|
+
typeof html === "string" ? "html" : void 0,
|
|
398
|
+
typeof markdown === "string" ? "markdown" : void 0,
|
|
399
|
+
render ? "render" : void 0,
|
|
400
|
+
typeof text === "string" && !html && !markdown && !render ? "text" : void 0
|
|
401
|
+
].filter(Boolean);
|
|
402
|
+
if (primaryKinds.length !== 1) {
|
|
403
|
+
throw new Error("[@holo-js/mail] Mail definitions must define exactly one primary content source.");
|
|
404
|
+
}
|
|
405
|
+
if (markdownWrapper && !markdown) {
|
|
406
|
+
throw new Error("[@holo-js/mail] Mail markdown wrappers are only valid for markdown mails.");
|
|
407
|
+
}
|
|
408
|
+
return {
|
|
409
|
+
...typeof text === "string" ? { text } : {},
|
|
410
|
+
...typeof html === "string" ? { html } : {},
|
|
411
|
+
...typeof markdown === "string" ? { markdown } : {},
|
|
412
|
+
...render ? { render } : {},
|
|
413
|
+
...markdownWrapper ? { markdownWrapper } : {}
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
function isMailDefinition(value) {
|
|
417
|
+
return !!value && typeof value === "object" && value[HOLO_MAIL_DEFINITION_MARKER] === true;
|
|
418
|
+
}
|
|
419
|
+
function mergeMailDefinitionInputs(base, overrides) {
|
|
420
|
+
if (!overrides || Object.keys(overrides).length === 0) {
|
|
421
|
+
return isMailDefinition(base) ? { ...base } : { ...base };
|
|
422
|
+
}
|
|
423
|
+
return {
|
|
424
|
+
...base,
|
|
425
|
+
...overrides,
|
|
426
|
+
headers: {
|
|
427
|
+
...base.headers ?? {},
|
|
428
|
+
...overrides.headers ?? {}
|
|
429
|
+
},
|
|
430
|
+
metadata: {
|
|
431
|
+
...base.metadata ?? {},
|
|
432
|
+
...overrides.metadata ?? {}
|
|
433
|
+
}
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
function normalizeMailDefinition(input) {
|
|
437
|
+
if (isMailDefinition(input)) {
|
|
438
|
+
return input;
|
|
439
|
+
}
|
|
440
|
+
if (!isObject(input)) {
|
|
441
|
+
throw new Error("[@holo-js/mail] Mail definitions must be plain objects.");
|
|
442
|
+
}
|
|
443
|
+
const subject = normalizeRequiredString(input.subject, "Mail subject");
|
|
444
|
+
const mailer = typeof input.mailer === "string" ? normalizeRequiredString(input.mailer, "Mail mailer") : void 0;
|
|
445
|
+
const from = typeof input.from !== "undefined" ? normalizeAddress(input.from, "Mail from") : void 0;
|
|
446
|
+
const replyTo = typeof input.replyTo !== "undefined" ? normalizeAddress(input.replyTo, "Mail replyTo") : void 0;
|
|
447
|
+
const metadata = typeof input.metadata === "undefined" ? void 0 : normalizeJsonValue(input.metadata, "Mail metadata");
|
|
448
|
+
const normalized = {
|
|
449
|
+
...mailer ? { mailer } : {},
|
|
450
|
+
...from ? { from } : {},
|
|
451
|
+
...replyTo ? { replyTo } : {},
|
|
452
|
+
to: normalizeRecipients(input.to, "Mail to", true),
|
|
453
|
+
cc: normalizeRecipients(input.cc, "Mail cc", false),
|
|
454
|
+
bcc: normalizeRecipients(input.bcc, "Mail bcc", false),
|
|
455
|
+
subject,
|
|
456
|
+
...normalizeContentSource(input),
|
|
457
|
+
attachments: normalizeAttachments(input.attachments),
|
|
458
|
+
headers: normalizeHeaders(input.headers),
|
|
459
|
+
tags: normalizeTags(input.tags),
|
|
460
|
+
...metadata ? { metadata } : {},
|
|
461
|
+
...normalizePriority(input.priority) ? { priority: normalizePriority(input.priority) } : {},
|
|
462
|
+
...typeof input.queue === "undefined" ? {} : { queue: normalizeQueueOptions(input.queue) },
|
|
463
|
+
...typeof input.delay === "undefined" ? {} : { delay: normalizeDelayValue(input.delay, "Mail delay") }
|
|
464
|
+
};
|
|
465
|
+
Object.defineProperty(normalized, HOLO_MAIL_DEFINITION_MARKER, {
|
|
466
|
+
value: true,
|
|
467
|
+
enumerable: false
|
|
468
|
+
});
|
|
469
|
+
return Object.freeze(normalized);
|
|
470
|
+
}
|
|
471
|
+
function defineMail(input) {
|
|
472
|
+
return normalizeMailDefinition(input);
|
|
473
|
+
}
|
|
474
|
+
function attachFromPath(path, options = {}) {
|
|
475
|
+
return Object.freeze({
|
|
476
|
+
path,
|
|
477
|
+
...options
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
function attachFromStorage(path, options = {}) {
|
|
481
|
+
return Object.freeze({
|
|
482
|
+
storage: Object.freeze({
|
|
483
|
+
path,
|
|
484
|
+
...typeof options.disk === "string" ? { disk: options.disk } : {}
|
|
485
|
+
}),
|
|
486
|
+
...typeof options.name === "string" ? { name: options.name } : {},
|
|
487
|
+
...typeof options.contentType === "string" ? { contentType: options.contentType } : {},
|
|
488
|
+
...typeof options.disposition === "string" ? { disposition: options.disposition } : {},
|
|
489
|
+
...typeof options.contentId === "string" ? { contentId: options.contentId } : {}
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
function attachContent(content, options) {
|
|
493
|
+
return Object.freeze({
|
|
494
|
+
content,
|
|
495
|
+
...options
|
|
496
|
+
});
|
|
497
|
+
}
|
|
498
|
+
var mailInternals = {
|
|
499
|
+
BUILT_IN_MAIL_DRIVERS,
|
|
500
|
+
HOLO_MAIL_DEFINITION_MARKER,
|
|
501
|
+
MAIL_ATTACHMENT_DISPOSITIONS,
|
|
502
|
+
MAIL_PRIORITY_VALUES,
|
|
503
|
+
attachContent,
|
|
504
|
+
attachFromPath,
|
|
505
|
+
attachFromStorage,
|
|
506
|
+
createAttachmentMetadata,
|
|
507
|
+
createAttachmentResolutionPlan,
|
|
508
|
+
createAttachmentResolutionPlans,
|
|
509
|
+
inferMimeTypeFromName,
|
|
510
|
+
inferAttachmentName,
|
|
511
|
+
inferAttachmentSource,
|
|
512
|
+
isObject,
|
|
513
|
+
isAttachmentQueueSafe,
|
|
514
|
+
isValidEmail,
|
|
515
|
+
mergeMailDefinitionInputs,
|
|
516
|
+
normalizeAddress,
|
|
517
|
+
normalizeAttachment,
|
|
518
|
+
normalizeAttachments,
|
|
519
|
+
normalizeDelayValue,
|
|
520
|
+
normalizeHeaders,
|
|
521
|
+
normalizeJsonValue,
|
|
522
|
+
normalizeMailDefinition,
|
|
523
|
+
normalizeOptionalString,
|
|
524
|
+
normalizePriority,
|
|
525
|
+
normalizeQueueOptions,
|
|
526
|
+
normalizeRecipients,
|
|
527
|
+
normalizeRenderSource,
|
|
528
|
+
normalizeRequiredString,
|
|
529
|
+
resolveAttachmentDefinition,
|
|
530
|
+
resolveNormalizedAttachment,
|
|
531
|
+
normalizeTags,
|
|
532
|
+
normalizeViewIdentifier
|
|
533
|
+
};
|
|
534
|
+
|
|
535
|
+
export {
|
|
536
|
+
defineMailConfig,
|
|
537
|
+
inferMimeTypeFromName,
|
|
538
|
+
createAttachmentMetadata,
|
|
539
|
+
resolveNormalizedAttachment,
|
|
540
|
+
isAttachmentQueueSafe,
|
|
541
|
+
resolveAttachmentDefinition,
|
|
542
|
+
createAttachmentResolutionPlan,
|
|
543
|
+
createAttachmentResolutionPlans,
|
|
544
|
+
isMailDefinition,
|
|
545
|
+
mergeMailDefinitionInputs,
|
|
546
|
+
normalizeMailDefinition,
|
|
547
|
+
defineMail,
|
|
548
|
+
attachFromPath,
|
|
549
|
+
attachFromStorage,
|
|
550
|
+
attachContent,
|
|
551
|
+
mailInternals
|
|
552
|
+
};
|