@voltro/plugin-mail 0.33.0 → 0.35.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/CHANGELOG.md +1968 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +174 -168
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
import { Config as e, Context as t, Duration as n, Effect as r, Fiber as i, Layer as a, ManagedRuntime as o, ParseResult as s, Redacted as c, Schedule as l, Schema as u } from "effect";
|
|
2
|
-
import { definePlugin as d } from "@voltro/protocol";
|
|
3
|
-
import { pluginEnv as
|
|
4
|
-
import { createLogger as
|
|
5
|
-
import { SqlClient as
|
|
6
|
-
import { PgClient as
|
|
7
|
-
import { FetchHttpClient as
|
|
2
|
+
import { definePlugin as d, pluginInstanceName as f } from "@voltro/protocol";
|
|
3
|
+
import { pluginEnv as p } from "@voltro/env";
|
|
4
|
+
import { createLogger as m } from "@voltro/logger";
|
|
5
|
+
import { SqlClient as h } from "@effect/sql";
|
|
6
|
+
import { PgClient as g } from "@effect/sql-pg";
|
|
7
|
+
import { FetchHttpClient as _, HttpClient as v, HttpClientRequest as y } from "@effect/platform";
|
|
8
8
|
//#region src/types.ts
|
|
9
|
-
var
|
|
9
|
+
var b = class extends u.TaggedError()("MailError", {
|
|
10
10
|
provider: u.String,
|
|
11
11
|
message: u.String,
|
|
12
12
|
transient: u.Boolean,
|
|
13
13
|
status: u.optional(u.Number)
|
|
14
|
-
}) {},
|
|
14
|
+
}) {}, x = (e) => ({
|
|
15
15
|
name: e.name,
|
|
16
16
|
props: e.props,
|
|
17
17
|
subject: e.subject,
|
|
18
18
|
render: e.render,
|
|
19
19
|
...e.locale === void 0 ? {} : { locale: e.locale },
|
|
20
20
|
...e.preview === void 0 ? {} : { preview: e.preview }
|
|
21
|
-
}),
|
|
21
|
+
}), S = class extends t.Tag("@voltro/plugin-mail/MailService")() {}, C = (e) => e === void 0 ? [] : typeof e == "string" ? [e] : e, ee = (e) => {
|
|
22
22
|
try {
|
|
23
23
|
let t = s.ArrayFormatter.formatErrorSync(e);
|
|
24
24
|
return t.length === 0 ? String(e) : t.map((e) => `${e.path.length > 0 ? e.path.join(".") : "(root)"}: ${e.message}`).join("; ");
|
|
@@ -32,16 +32,16 @@ var y = class extends u.TaggedError()("MailError", {
|
|
|
32
32
|
}
|
|
33
33
|
return w;
|
|
34
34
|
}, E = (e, t) => r.gen(function* () {
|
|
35
|
-
let n = e, i = yield* u.decodeUnknown(n.props)(t).pipe(r.mapError((t) => new
|
|
35
|
+
let n = e, i = yield* u.decodeUnknown(n.props)(t).pipe(r.mapError((t) => new b({
|
|
36
36
|
provider: "template",
|
|
37
|
-
message: `invalid props for '${e.name}': ${
|
|
37
|
+
message: `invalid props for '${e.name}': ${ee(t)}`.slice(0, 500),
|
|
38
38
|
transient: !1
|
|
39
39
|
}))), a = n.subject(i), o = n.render(i);
|
|
40
40
|
return {
|
|
41
41
|
subject: a,
|
|
42
42
|
html: yield* r.tryPromise({
|
|
43
43
|
try: async () => (await T())(o, { plainText: !1 }),
|
|
44
|
-
catch: (t) => new
|
|
44
|
+
catch: (t) => new b({
|
|
45
45
|
provider: "template",
|
|
46
46
|
message: `render failed for '${e.name}': ${String(t)}`.slice(0, 500),
|
|
47
47
|
transient: !1
|
|
@@ -49,30 +49,30 @@ var y = class extends u.TaggedError()("MailError", {
|
|
|
49
49
|
}),
|
|
50
50
|
text: yield* r.tryPromise({
|
|
51
51
|
try: async () => (await T())(o, { plainText: !0 }),
|
|
52
|
-
catch: (t) => new
|
|
52
|
+
catch: (t) => new b({
|
|
53
53
|
provider: "template",
|
|
54
54
|
message: `render(text) failed for '${e.name}': ${String(t)}`.slice(0, 500),
|
|
55
55
|
transient: !1
|
|
56
56
|
})
|
|
57
57
|
})
|
|
58
58
|
};
|
|
59
|
-
}), D = /* @__PURE__ */ new Map(),
|
|
60
|
-
for (let t of e) D.set(
|
|
61
|
-
}, O = (e, t) => (t ? D.get(`${e}:${t}`) : void 0) ?? D.get(e),
|
|
59
|
+
}), D = /* @__PURE__ */ new Map(), te = (e) => e.locale ? `${e.name}:${e.locale}` : e.name, ne = (e) => {
|
|
60
|
+
for (let t of e) D.set(te(t), t);
|
|
61
|
+
}, O = (e, t) => (t ? D.get(`${e}:${t}`) : void 0) ?? D.get(e), re = () => D.size, k = () => [...D.values()].map((e) => e.locale ? {
|
|
62
62
|
name: e.name,
|
|
63
63
|
locale: e.locale
|
|
64
64
|
} : { name: e.name }), ie = () => D.clear(), ae = (e) => {
|
|
65
65
|
if (typeof e != "object" || !e) return !1;
|
|
66
66
|
let t = e;
|
|
67
67
|
return typeof t.name == "string" && typeof t.subject == "function" && typeof t.render == "function" && t.props !== void 0;
|
|
68
|
-
}, oe =
|
|
69
|
-
let e = /* @__PURE__ */ new Set(), t = (e, t) => `${
|
|
68
|
+
}, oe = m({ scope: "@voltro/plugin-mail" }), A = (e) => e.trim().toLowerCase(), se = "*", j = (e) => e ?? se, M = () => {
|
|
69
|
+
let e = /* @__PURE__ */ new Set(), t = (e, t) => `${j(e)}\u0000${A(t)}`;
|
|
70
70
|
return {
|
|
71
|
-
isSuppressed: (n, i) => r.sync(() => e.has(t(n, i))),
|
|
71
|
+
isSuppressed: (n, i) => r.sync(() => e.has(t(n, i)) || e.has(t(null, i))),
|
|
72
72
|
suppress: (n, i) => r.sync(() => void e.add(t(n, i))),
|
|
73
73
|
unsuppress: (n, i) => r.sync(() => void e.delete(t(n, i)))
|
|
74
74
|
};
|
|
75
|
-
},
|
|
75
|
+
}, ce = (e) => {
|
|
76
76
|
let t = e.DB_URL ?? e.DB_PRIMARY_URL;
|
|
77
77
|
if (t) {
|
|
78
78
|
let e = new URL(t);
|
|
@@ -91,8 +91,8 @@ var y = class extends u.TaggedError()("MailError", {
|
|
|
91
91
|
password: e.DB_PASSWORD ?? e.PG_PASSWORD ?? "app",
|
|
92
92
|
database: e.DB_DATABASE ?? e.PG_DATABASE ?? "app"
|
|
93
93
|
};
|
|
94
|
-
},
|
|
95
|
-
let n = t.table ?? "_voltro_mail_suppression", i = null, a = (n) =>
|
|
94
|
+
}, le = (t = {}) => {
|
|
95
|
+
let n = t.table ?? "_voltro_mail_suppression", i = null, a = (n) => g.layerConfig({
|
|
96
96
|
host: e.succeed(n.host),
|
|
97
97
|
port: e.succeed(n.port),
|
|
98
98
|
username: e.succeed(n.username),
|
|
@@ -105,9 +105,10 @@ var y = class extends u.TaggedError()("MailError", {
|
|
|
105
105
|
let a = i;
|
|
106
106
|
if (!a) return r.succeed(!1);
|
|
107
107
|
let o = r.gen(function* () {
|
|
108
|
-
let r = yield*
|
|
108
|
+
let r = yield* h.SqlClient;
|
|
109
109
|
return (yield* r`
|
|
110
|
-
SELECT 1 AS one FROM ${r(n)}
|
|
110
|
+
SELECT 1 AS one FROM ${r(n)}
|
|
111
|
+
WHERE email = ${A(t)} AND tenant IN (${j(e)}, ${se}) LIMIT 1`).length > 0;
|
|
111
112
|
});
|
|
112
113
|
return r.tryPromise(() => a.runPromise(o)).pipe(r.catchAll(() => r.succeed(!1)));
|
|
113
114
|
},
|
|
@@ -115,14 +116,14 @@ var y = class extends u.TaggedError()("MailError", {
|
|
|
115
116
|
let o = i;
|
|
116
117
|
if (!o) return r.void;
|
|
117
118
|
let s = r.gen(function* () {
|
|
118
|
-
let r = yield*
|
|
119
|
+
let r = yield* h.SqlClient;
|
|
119
120
|
yield* r`
|
|
120
121
|
INSERT INTO ${r(n)} (tenant, email, reason, created_at)
|
|
121
|
-
VALUES (${
|
|
122
|
+
VALUES (${j(e)}, ${A(t)}, ${a}, ${Date.now()})
|
|
122
123
|
ON CONFLICT (tenant, email) DO UPDATE SET reason = ${a}, created_at = ${Date.now()}`;
|
|
123
124
|
});
|
|
124
125
|
return r.tryPromise(() => o.runPromise(s)).pipe(r.catchAll((e) => r.sync(() => oe.warn("suppress write failed", {
|
|
125
|
-
email:
|
|
126
|
+
email: A(t),
|
|
126
127
|
message: String(e)
|
|
127
128
|
}))));
|
|
128
129
|
},
|
|
@@ -130,15 +131,15 @@ var y = class extends u.TaggedError()("MailError", {
|
|
|
130
131
|
let a = i;
|
|
131
132
|
if (!a) return r.void;
|
|
132
133
|
let o = r.gen(function* () {
|
|
133
|
-
let r = yield*
|
|
134
|
-
yield* r`DELETE FROM ${r(n)} WHERE tenant = ${
|
|
134
|
+
let r = yield* h.SqlClient;
|
|
135
|
+
yield* r`DELETE FROM ${r(n)} WHERE tenant = ${j(e)} AND email = ${A(t)}`;
|
|
135
136
|
});
|
|
136
137
|
return r.tryPromise(() => a.runPromise(o)).pipe(r.catchAll(() => r.void));
|
|
137
138
|
},
|
|
138
139
|
activate: async (e) => {
|
|
139
|
-
let t = o.make(a(
|
|
140
|
+
let t = o.make(a(ce(e)));
|
|
140
141
|
await t.runPromise(r.gen(function* () {
|
|
141
|
-
let e = yield*
|
|
142
|
+
let e = yield* h.SqlClient;
|
|
142
143
|
yield* e`
|
|
143
144
|
CREATE TABLE IF NOT EXISTS ${e(n)} (
|
|
144
145
|
tenant TEXT NOT NULL,
|
|
@@ -154,8 +155,8 @@ var y = class extends u.TaggedError()("MailError", {
|
|
|
154
155
|
i = null, e && await e.dispose();
|
|
155
156
|
}
|
|
156
157
|
};
|
|
157
|
-
},
|
|
158
|
-
let e = /* @__PURE__ */ new Map(), t = (e, t) => `${
|
|
158
|
+
}, ue = m({ scope: "@voltro/plugin-mail" }), N = (e) => e ?? "*", P = () => {
|
|
159
|
+
let e = /* @__PURE__ */ new Map(), t = (e, t) => `${N(e)} ${t}`;
|
|
159
160
|
return {
|
|
160
161
|
reserve: (n, i) => r.sync(() => {
|
|
161
162
|
let r = t(n, i);
|
|
@@ -170,7 +171,7 @@ var y = class extends u.TaggedError()("MailError", {
|
|
|
170
171
|
}),
|
|
171
172
|
record: (n, i, a) => r.sync(() => void e.set(t(n, i), a))
|
|
172
173
|
};
|
|
173
|
-
},
|
|
174
|
+
}, de = (e) => {
|
|
174
175
|
let t = e.DB_URL ?? e.DB_PRIMARY_URL;
|
|
175
176
|
if (t) {
|
|
176
177
|
let e = new URL(t);
|
|
@@ -189,8 +190,8 @@ var y = class extends u.TaggedError()("MailError", {
|
|
|
189
190
|
password: e.DB_PASSWORD ?? e.PG_PASSWORD ?? "app",
|
|
190
191
|
database: e.DB_DATABASE ?? e.PG_DATABASE ?? "app"
|
|
191
192
|
};
|
|
192
|
-
},
|
|
193
|
-
let n = t.table ?? "_voltro_mail_idempotency", i = null, a = (n) =>
|
|
193
|
+
}, F = (t = {}) => {
|
|
194
|
+
let n = t.table ?? "_voltro_mail_idempotency", i = null, a = (n) => g.layerConfig({
|
|
194
195
|
host: e.succeed(n.host),
|
|
195
196
|
port: e.succeed(n.port),
|
|
196
197
|
username: e.succeed(n.username),
|
|
@@ -203,15 +204,15 @@ var y = class extends u.TaggedError()("MailError", {
|
|
|
203
204
|
let a = i;
|
|
204
205
|
if (!a) return r.succeed({ won: !0 });
|
|
205
206
|
let o = r.gen(function* () {
|
|
206
|
-
let r = yield*
|
|
207
|
+
let r = yield* h.SqlClient;
|
|
207
208
|
if ((yield* r`
|
|
208
209
|
INSERT INTO ${r(n)} (tenant, key, created_at)
|
|
209
|
-
VALUES (${
|
|
210
|
+
VALUES (${N(e)}, ${t}, ${Date.now()})
|
|
210
211
|
ON CONFLICT (tenant, key) DO NOTHING
|
|
211
212
|
RETURNING key`).length > 0) return { won: !0 };
|
|
212
213
|
let i = (yield* r`
|
|
213
214
|
SELECT result_id, result_provider FROM ${r(n)}
|
|
214
|
-
WHERE tenant = ${
|
|
215
|
+
WHERE tenant = ${N(e)} AND key = ${t} LIMIT 1`)[0];
|
|
215
216
|
return i && i.result_id && i.result_provider ? {
|
|
216
217
|
won: !1,
|
|
217
218
|
prior: {
|
|
@@ -220,7 +221,7 @@ var y = class extends u.TaggedError()("MailError", {
|
|
|
220
221
|
}
|
|
221
222
|
} : { won: !1 };
|
|
222
223
|
});
|
|
223
|
-
return r.tryPromise(() => a.runPromise(o)).pipe(r.catchAll((e) => r.sync(() => (
|
|
224
|
+
return r.tryPromise(() => a.runPromise(o)).pipe(r.catchAll((e) => r.sync(() => (ue.warn("idempotency reserve failed — skipping send to avoid a double", {
|
|
224
225
|
key: t,
|
|
225
226
|
message: String(e)
|
|
226
227
|
}), { won: !1 }))));
|
|
@@ -229,20 +230,20 @@ var y = class extends u.TaggedError()("MailError", {
|
|
|
229
230
|
let o = i;
|
|
230
231
|
if (!o) return r.void;
|
|
231
232
|
let s = r.gen(function* () {
|
|
232
|
-
let r = yield*
|
|
233
|
+
let r = yield* h.SqlClient;
|
|
233
234
|
yield* r`
|
|
234
235
|
UPDATE ${r(n)} SET result_id = ${a.id}, result_provider = ${a.provider}
|
|
235
|
-
WHERE tenant = ${
|
|
236
|
+
WHERE tenant = ${N(e)} AND key = ${t}`;
|
|
236
237
|
});
|
|
237
|
-
return r.tryPromise(() => o.runPromise(s)).pipe(r.catchAll((e) => r.sync(() =>
|
|
238
|
+
return r.tryPromise(() => o.runPromise(s)).pipe(r.catchAll((e) => r.sync(() => ue.warn("idempotency record failed", {
|
|
238
239
|
key: t,
|
|
239
240
|
message: String(e)
|
|
240
241
|
}))));
|
|
241
242
|
},
|
|
242
243
|
activate: async (e) => {
|
|
243
|
-
let t = o.make(a(
|
|
244
|
+
let t = o.make(a(de(e)));
|
|
244
245
|
await t.runPromise(r.gen(function* () {
|
|
245
|
-
let e = yield*
|
|
246
|
+
let e = yield* h.SqlClient;
|
|
246
247
|
yield* e`
|
|
247
248
|
CREATE TABLE IF NOT EXISTS ${e(n)} (
|
|
248
249
|
tenant TEXT NOT NULL,
|
|
@@ -259,7 +260,7 @@ var y = class extends u.TaggedError()("MailError", {
|
|
|
259
260
|
i = null, e && await e.dispose();
|
|
260
261
|
}
|
|
261
262
|
};
|
|
262
|
-
},
|
|
263
|
+
}, fe = m({ scope: "@voltro/plugin-mail" }), I = () => {
|
|
263
264
|
let e = /* @__PURE__ */ new Map();
|
|
264
265
|
return {
|
|
265
266
|
hold: (t) => r.sync(() => void e.set(t.id, t)),
|
|
@@ -270,34 +271,34 @@ var y = class extends u.TaggedError()("MailError", {
|
|
|
270
271
|
}),
|
|
271
272
|
size: () => r.sync(() => e.size)
|
|
272
273
|
};
|
|
273
|
-
},
|
|
274
|
+
}, pe = 0, L = (e) => e.idempotencyKey ?? `held-${pe += 1}`, R = (e) => ({
|
|
274
275
|
shouldHold: (t) => !e.providerSchedules && t !== void 0 && t.getTime() > Date.now(),
|
|
275
276
|
hold: (t) => {
|
|
276
277
|
let { scheduledAt: n, ...r } = t;
|
|
277
278
|
return e.store.hold({
|
|
278
|
-
id:
|
|
279
|
+
id: L(t),
|
|
279
280
|
dueAt: t.scheduledAt?.getTime() ?? Date.now(),
|
|
280
281
|
message: r
|
|
281
282
|
});
|
|
282
283
|
},
|
|
283
284
|
tick: (t = Date.now()) => r.gen(function* () {
|
|
284
285
|
let n = yield* e.store.claimDue(t);
|
|
285
|
-
for (let t of n) yield* e.flush(t.message).pipe(r.catchAll((e) => r.sync(() =>
|
|
286
|
+
for (let t of n) yield* e.flush(t.message).pipe(r.catchAll((e) => r.sync(() => fe.warn("scheduled flush failed", {
|
|
286
287
|
id: t.id,
|
|
287
288
|
message: String(e)
|
|
288
289
|
}))));
|
|
289
290
|
return n.length;
|
|
290
291
|
}),
|
|
291
292
|
pending: () => e.store.size()
|
|
292
|
-
}),
|
|
293
|
+
}), me = 0, z = (e) => `${e}-${me += 1}`, he = (e) => e === void 0 || e === 408 || e === 429 || e >= 500, B = (e, t) => {
|
|
293
294
|
let n = t.status;
|
|
294
|
-
return new
|
|
295
|
+
return new b({
|
|
295
296
|
provider: e,
|
|
296
297
|
message: (t.message ?? "send failed").slice(0, 500),
|
|
297
|
-
transient:
|
|
298
|
+
transient: he(n),
|
|
298
299
|
...n === void 0 ? {} : { status: n }
|
|
299
300
|
});
|
|
300
|
-
},
|
|
301
|
+
}, V = (e, t, n, i, a) => r.tryPromise({
|
|
301
302
|
try: async () => {
|
|
302
303
|
let e = await fetch(t, {
|
|
303
304
|
method: "POST",
|
|
@@ -318,20 +319,20 @@ var y = class extends u.TaggedError()("MailError", {
|
|
|
318
319
|
},
|
|
319
320
|
catch: (t) => {
|
|
320
321
|
let n = t;
|
|
321
|
-
return
|
|
322
|
+
return B(e, {
|
|
322
323
|
...typeof n.status == "number" ? { status: n.status } : {},
|
|
323
324
|
message: n.message ?? t?.message ?? String(t)
|
|
324
325
|
});
|
|
325
326
|
}
|
|
326
|
-
}),
|
|
327
|
+
}), H = (e) => ({
|
|
327
328
|
from: e.from,
|
|
328
|
-
to:
|
|
329
|
+
to: C(e.to),
|
|
329
330
|
subject: e.subject,
|
|
330
331
|
html: e.html,
|
|
331
332
|
text: e.text,
|
|
332
333
|
reply_to: e.replyTo,
|
|
333
|
-
cc: e.cc ?
|
|
334
|
-
bcc: e.bcc ?
|
|
334
|
+
cc: e.cc ? C(e.cc) : void 0,
|
|
335
|
+
bcc: e.bcc ? C(e.bcc) : void 0,
|
|
335
336
|
headers: e.headers,
|
|
336
337
|
tags: e.tags?.map((e) => ({
|
|
337
338
|
name: e,
|
|
@@ -343,34 +344,34 @@ var y = class extends u.TaggedError()("MailError", {
|
|
|
343
344
|
content: e.content,
|
|
344
345
|
...e.contentType ? { content_type: e.contentType } : {}
|
|
345
346
|
}))
|
|
346
|
-
}),
|
|
347
|
+
}), U = (e) => ({
|
|
347
348
|
name: "resend",
|
|
348
349
|
supportsScheduling: !0,
|
|
349
|
-
send: (t) =>
|
|
350
|
+
send: (t) => V("resend", "https://api.resend.com/emails", { authorization: `Bearer ${e.apiKey}` }, H(t), async (e) => ({
|
|
350
351
|
id: (await e.json()).id ?? "resend",
|
|
351
352
|
provider: "resend"
|
|
352
353
|
})),
|
|
353
|
-
sendBatch: (t) =>
|
|
354
|
+
sendBatch: (t) => V("resend", "https://api.resend.com/emails/batch", { authorization: `Bearer ${e.apiKey}` }, t.map(H), async (e) => {
|
|
354
355
|
let n = (await e.json()).data ?? [];
|
|
355
356
|
return t.map((e, t) => ({
|
|
356
357
|
id: n[t]?.id ?? "resend",
|
|
357
358
|
provider: "resend"
|
|
358
359
|
}));
|
|
359
360
|
})
|
|
360
|
-
}),
|
|
361
|
+
}), W = (e) => ({
|
|
361
362
|
name: "postmark",
|
|
362
|
-
send: (t) =>
|
|
363
|
+
send: (t) => V("postmark", "https://api.postmarkapp.com/email", {
|
|
363
364
|
"x-postmark-server-token": e.serverToken,
|
|
364
365
|
accept: "application/json"
|
|
365
366
|
}, {
|
|
366
367
|
From: t.from,
|
|
367
|
-
To:
|
|
368
|
+
To: C(t.to).join(","),
|
|
368
369
|
Subject: t.subject,
|
|
369
370
|
HtmlBody: t.html,
|
|
370
371
|
TextBody: t.text,
|
|
371
372
|
ReplyTo: t.replyTo,
|
|
372
|
-
Cc: t.cc ?
|
|
373
|
-
Bcc: t.bcc ?
|
|
373
|
+
Cc: t.cc ? C(t.cc).join(",") : void 0,
|
|
374
|
+
Bcc: t.bcc ? C(t.bcc).join(",") : void 0,
|
|
374
375
|
Attachments: t.attachments?.map((e) => ({
|
|
375
376
|
Name: e.filename,
|
|
376
377
|
Content: e.content,
|
|
@@ -380,44 +381,44 @@ var y = class extends u.TaggedError()("MailError", {
|
|
|
380
381
|
id: (await e.json()).MessageID ?? "postmark",
|
|
381
382
|
provider: "postmark"
|
|
382
383
|
}))
|
|
383
|
-
}),
|
|
384
|
+
}), G = (e) => [...e.text ? [{
|
|
384
385
|
type: "text/plain",
|
|
385
386
|
value: e.text
|
|
386
387
|
}] : [], ...e.html ? [{
|
|
387
388
|
type: "text/html",
|
|
388
389
|
value: e.html
|
|
389
|
-
}] : []],
|
|
390
|
-
to:
|
|
391
|
-
cc: e.cc ?
|
|
392
|
-
bcc: e.bcc ?
|
|
390
|
+
}] : []], K = (e) => ({
|
|
391
|
+
to: C(e.to).map((e) => ({ email: e })),
|
|
392
|
+
cc: e.cc ? C(e.cc).map((e) => ({ email: e })) : void 0,
|
|
393
|
+
bcc: e.bcc ? C(e.bcc).map((e) => ({ email: e })) : void 0,
|
|
393
394
|
subject: e.subject,
|
|
394
395
|
...e.scheduledAt ? { send_at: Math.floor(e.scheduledAt.getTime() / 1e3) } : {}
|
|
395
|
-
}),
|
|
396
|
+
}), ge = (e) => e.attachments?.map((e) => ({
|
|
396
397
|
filename: e.filename,
|
|
397
398
|
content: e.content,
|
|
398
399
|
type: e.contentType ?? "application/octet-stream",
|
|
399
400
|
disposition: "attachment"
|
|
400
|
-
})),
|
|
401
|
+
})), _e = (e) => {
|
|
401
402
|
let t = (e) => ({
|
|
402
|
-
personalizations: [
|
|
403
|
+
personalizations: [K(e)],
|
|
403
404
|
from: { email: e.from },
|
|
404
405
|
reply_to: e.replyTo ? { email: e.replyTo } : void 0,
|
|
405
406
|
subject: e.subject,
|
|
406
|
-
content:
|
|
407
|
-
attachments:
|
|
407
|
+
content: G(e),
|
|
408
|
+
attachments: ge(e)
|
|
408
409
|
});
|
|
409
410
|
return {
|
|
410
411
|
name: "sendgrid",
|
|
411
412
|
supportsScheduling: !0,
|
|
412
|
-
send: (n) =>
|
|
413
|
+
send: (n) => V("sendgrid", "https://api.sendgrid.com/v3/mail/send", { authorization: `Bearer ${e.apiKey}` }, t(n), async (e) => ({
|
|
413
414
|
id: e.headers.get("x-message-id") ?? "sendgrid",
|
|
414
415
|
provider: "sendgrid"
|
|
415
416
|
})),
|
|
416
|
-
sendBatch: (t) =>
|
|
417
|
-
personalizations: t.map(
|
|
417
|
+
sendBatch: (t) => V("sendgrid", "https://api.sendgrid.com/v3/mail/send", { authorization: `Bearer ${e.apiKey}` }, {
|
|
418
|
+
personalizations: t.map(K),
|
|
418
419
|
from: { email: t[0]?.from },
|
|
419
420
|
subject: t[0]?.subject,
|
|
420
|
-
content:
|
|
421
|
+
content: G(t[0] ?? {})
|
|
421
422
|
}, async (e) => {
|
|
422
423
|
let n = e.headers.get("x-message-id") ?? "sendgrid";
|
|
423
424
|
return t.map((e, t) => ({
|
|
@@ -426,35 +427,35 @@ var y = class extends u.TaggedError()("MailError", {
|
|
|
426
427
|
}));
|
|
427
428
|
})
|
|
428
429
|
};
|
|
429
|
-
},
|
|
430
|
+
}, ve = (e, t) => {
|
|
430
431
|
let n = t, r = n.response?.status;
|
|
431
|
-
return
|
|
432
|
+
return B(e, {
|
|
432
433
|
...typeof r == "number" ? { status: r } : {},
|
|
433
434
|
message: n.message ?? String(t)
|
|
434
435
|
});
|
|
435
|
-
},
|
|
436
|
-
let i = yield* (yield*
|
|
436
|
+
}, ye = (e, t, n) => r.gen(function* () {
|
|
437
|
+
let i = yield* (yield* v.HttpClient).execute(t);
|
|
437
438
|
if (i.status < 200 || i.status >= 300) {
|
|
438
439
|
let t = yield* i.text.pipe(r.catchAll(() => r.succeed("")));
|
|
439
|
-
return yield* r.fail(
|
|
440
|
+
return yield* r.fail(B(e, {
|
|
440
441
|
status: i.status,
|
|
441
442
|
message: t || `HTTP ${i.status}`
|
|
442
443
|
}));
|
|
443
444
|
}
|
|
444
445
|
return yield* n(i);
|
|
445
|
-
}).pipe(r.catchAll((t) => t instanceof
|
|
446
|
+
}).pipe(r.catchAll((t) => t instanceof b ? r.fail(t) : r.fail(ve(e, t))), r.provide(_.layer)), be = (e) => ({ sign: async (t, n, r) => {
|
|
446
447
|
let { createHash: i, createHmac: a } = await import("node:crypto"), o = (e) => i("sha256").update(e).digest("hex"), s = (e, t) => a("sha256", e).update(t).digest(), c = (/* @__PURE__ */ new Date()).toISOString().replace(/[:-]|\.\d{3}/g, ""), l = c.slice(0, 8), u = `host:${new URL(t).host}\nx-amz-date:${c}\n` + (e.sessionToken ? `x-amz-security-token:${e.sessionToken}\n` : ""), d = e.sessionToken ? "host;x-amz-date;x-amz-security-token" : "host;x-amz-date", f = `POST\n${n}\n\n${u}\n${d}\n${o(r)}`, p = `${l}/${e.region}/ses/aws4_request`, m = `AWS4-HMAC-SHA256\n${c}\n${p}\n${o(f)}`, h = a("sha256", s(s(s(s(`AWS4${e.secretAccessKey}`, l), e.region), "ses"), "aws4_request")).update(m).digest("hex");
|
|
447
448
|
return {
|
|
448
449
|
authorization: `AWS4-HMAC-SHA256 Credential=${e.accessKeyId}/${p}, SignedHeaders=${d}, Signature=${h}`,
|
|
449
450
|
"x-amz-date": c,
|
|
450
451
|
...e.sessionToken ? { "x-amz-security-token": e.sessionToken } : {}
|
|
451
452
|
};
|
|
452
|
-
} }),
|
|
453
|
+
} }), xe = (e) => JSON.stringify({
|
|
453
454
|
FromEmailAddress: e.from,
|
|
454
455
|
Destination: {
|
|
455
|
-
ToAddresses:
|
|
456
|
-
...e.cc ? { CcAddresses:
|
|
457
|
-
...e.bcc ? { BccAddresses:
|
|
456
|
+
ToAddresses: C(e.to),
|
|
457
|
+
...e.cc ? { CcAddresses: C(e.cc) } : {},
|
|
458
|
+
...e.bcc ? { BccAddresses: C(e.bcc) } : {}
|
|
458
459
|
},
|
|
459
460
|
...e.replyTo ? { ReplyToAddresses: [e.replyTo] } : {},
|
|
460
461
|
Content: { Simple: {
|
|
@@ -473,41 +474,41 @@ var y = class extends u.TaggedError()("MailError", {
|
|
|
473
474
|
} } : {}
|
|
474
475
|
}
|
|
475
476
|
} }
|
|
476
|
-
}),
|
|
477
|
-
let t =
|
|
477
|
+
}), Se = (e) => {
|
|
478
|
+
let t = be(e), n = `https://email.${e.region}.amazonaws.com`, i = "/v2/email/outbound-emails";
|
|
478
479
|
return {
|
|
479
480
|
name: "ses",
|
|
480
481
|
send: (e) => r.gen(function* () {
|
|
481
|
-
let a =
|
|
482
|
+
let a = xe(e), o = yield* r.tryPromise({
|
|
482
483
|
try: () => t.sign(n, i, a),
|
|
483
|
-
catch: (e) =>
|
|
484
|
+
catch: (e) => B("ses", { message: e?.message ?? String(e) })
|
|
484
485
|
});
|
|
485
|
-
return yield*
|
|
486
|
+
return yield* ye("ses", y.post(`${n}${i}`).pipe(y.setHeaders({
|
|
486
487
|
"content-type": "application/json",
|
|
487
488
|
...o
|
|
488
|
-
}),
|
|
489
|
+
}), y.bodyUnsafeJson(JSON.parse(a))), (e) => e.json.pipe(r.map((e) => ({
|
|
489
490
|
id: e.MessageId ?? "ses",
|
|
490
491
|
provider: "ses"
|
|
491
492
|
}))));
|
|
492
493
|
})
|
|
493
494
|
};
|
|
494
|
-
},
|
|
495
|
+
}, Ce = (e) => {
|
|
495
496
|
let t = [["from", e.from], ["subject", e.subject]];
|
|
496
|
-
for (let n of
|
|
497
|
-
if (e.cc) for (let n of
|
|
498
|
-
if (e.bcc) for (let n of
|
|
497
|
+
for (let n of C(e.to)) t.push(["to", n]);
|
|
498
|
+
if (e.cc) for (let n of C(e.cc)) t.push(["cc", n]);
|
|
499
|
+
if (e.bcc) for (let n of C(e.bcc)) t.push(["bcc", n]);
|
|
499
500
|
if (e.replyTo && t.push(["h:Reply-To", e.replyTo]), e.html && t.push(["html", e.html]), e.text && t.push(["text", e.text]), e.headers) for (let [n, r] of Object.entries(e.headers)) t.push([`h:${n}`, r]);
|
|
500
501
|
if (e.tags) for (let n of e.tags) t.push(["o:tag", n]);
|
|
501
502
|
return e.scheduledAt && t.push(["o:deliverytime", e.scheduledAt.toUTCString()]), t;
|
|
502
|
-
},
|
|
503
|
+
}, we = (e) => {
|
|
503
504
|
let t = `${e.baseUrl ?? "https://api.mailgun.net"}/v3/${e.domain}/messages`;
|
|
504
505
|
return {
|
|
505
506
|
name: "mailgun",
|
|
506
507
|
supportsScheduling: !0,
|
|
507
508
|
send: (n) => {
|
|
508
509
|
let i = new URLSearchParams();
|
|
509
|
-
for (let [e, t] of
|
|
510
|
-
return
|
|
510
|
+
for (let [e, t] of Ce(n)) i.append(e, t);
|
|
511
|
+
return ye("mailgun", y.post(t).pipe(y.setHeader("authorization", `Basic ${Buffer.from(`api:${e.apiKey}`).toString("base64")}`), y.bodyText(i.toString(), "application/x-www-form-urlencoded")), (e) => e.json.pipe(r.map((e) => ({
|
|
511
512
|
id: e.id ?? "mailgun",
|
|
512
513
|
provider: "mailgun"
|
|
513
514
|
}))));
|
|
@@ -532,9 +533,9 @@ var y = class extends u.TaggedError()("MailError", {
|
|
|
532
533
|
return {
|
|
533
534
|
id: (await t.sendMail({
|
|
534
535
|
from: n.from,
|
|
535
|
-
to:
|
|
536
|
-
cc: n.cc ?
|
|
537
|
-
bcc: n.bcc ?
|
|
536
|
+
to: C(n.to),
|
|
537
|
+
cc: n.cc ? C(n.cc) : void 0,
|
|
538
|
+
bcc: n.bcc ? C(n.bcc) : void 0,
|
|
538
539
|
replyTo: n.replyTo,
|
|
539
540
|
subject: n.subject,
|
|
540
541
|
html: n.html,
|
|
@@ -552,47 +553,47 @@ var y = class extends u.TaggedError()("MailError", {
|
|
|
552
553
|
},
|
|
553
554
|
catch: (e) => {
|
|
554
555
|
let t = e;
|
|
555
|
-
return
|
|
556
|
+
return B("smtp", {
|
|
556
557
|
...typeof t.responseCode == "number" ? { status: t.responseCode } : {},
|
|
557
558
|
message: t.message ?? String(e)
|
|
558
559
|
});
|
|
559
560
|
}
|
|
560
561
|
})
|
|
561
562
|
};
|
|
562
|
-
},
|
|
563
|
+
}, Te = (e) => ({
|
|
563
564
|
name: "console",
|
|
564
565
|
send: (t) => r.sync(() => {
|
|
565
|
-
let n = `✉ to=${
|
|
566
|
+
let n = `✉ to=${C(t.to).join(",")} subject=${JSON.stringify(t.subject)}`;
|
|
566
567
|
return e ? e(n, { from: t.from }) : process.stdout.write(`[mail:console] ${n}\n`), {
|
|
567
|
-
id:
|
|
568
|
+
id: z("console"),
|
|
568
569
|
provider: "console"
|
|
569
570
|
};
|
|
570
571
|
})
|
|
571
|
-
}), J = [],
|
|
572
|
+
}), J = [], Ee = () => [...J], De = () => {
|
|
572
573
|
J.length = 0;
|
|
573
|
-
},
|
|
574
|
+
}, Oe = () => ({
|
|
574
575
|
name: "memory",
|
|
575
576
|
send: (e) => r.sync(() => (J.push(e), {
|
|
576
|
-
id:
|
|
577
|
+
id: z("mem"),
|
|
577
578
|
provider: "memory"
|
|
578
579
|
}))
|
|
579
|
-
}), Y =
|
|
580
|
+
}), Y = m({ scope: "@voltro/plugin-mail" }), ke = (e) => {
|
|
580
581
|
if (e.provider !== void 0 && typeof e.provider != "string") return e.provider;
|
|
581
582
|
let t = e.env ?? {}, n = e.provider ?? t.MAIL_PROVIDER ?? "console", r = (e, t) => {
|
|
582
583
|
if (!t) throw Error(`@voltro/plugin-mail: provider '${n}' needs apiKey or ${e}`);
|
|
583
584
|
return t;
|
|
584
585
|
};
|
|
585
586
|
switch (n) {
|
|
586
|
-
case "resend": return
|
|
587
|
-
case "postmark": return
|
|
588
|
-
case "sendgrid": return
|
|
589
|
-
case "ses": return
|
|
587
|
+
case "resend": return U({ apiKey: r("RESEND_API_KEY", e.apiKey ?? t.RESEND_API_KEY) });
|
|
588
|
+
case "postmark": return W({ serverToken: r("POSTMARK_SERVER_TOKEN", e.apiKey ?? t.POSTMARK_SERVER_TOKEN) });
|
|
589
|
+
case "sendgrid": return _e({ apiKey: r("SENDGRID_API_KEY", e.apiKey ?? t.SENDGRID_API_KEY) });
|
|
590
|
+
case "ses": return Se({
|
|
590
591
|
region: r("AWS_REGION", t.AWS_REGION),
|
|
591
592
|
accessKeyId: r("AWS_ACCESS_KEY_ID", t.AWS_ACCESS_KEY_ID),
|
|
592
593
|
secretAccessKey: r("AWS_SECRET_ACCESS_KEY", t.AWS_SECRET_ACCESS_KEY),
|
|
593
594
|
...t.AWS_SESSION_TOKEN ? { sessionToken: t.AWS_SESSION_TOKEN } : {}
|
|
594
595
|
});
|
|
595
|
-
case "mailgun": return
|
|
596
|
+
case "mailgun": return we({
|
|
596
597
|
apiKey: r("MAILGUN_API_KEY", e.apiKey ?? t.MAILGUN_API_KEY),
|
|
597
598
|
domain: r("MAILGUN_DOMAIN", t.MAILGUN_DOMAIN),
|
|
598
599
|
...t.MAILGUN_BASE_URL ? { baseUrl: t.MAILGUN_BASE_URL } : {}
|
|
@@ -606,29 +607,29 @@ var y = class extends u.TaggedError()("MailError", {
|
|
|
606
607
|
pass: t.SMTP_PASS
|
|
607
608
|
} } : {}
|
|
608
609
|
});
|
|
609
|
-
case "memory": return
|
|
610
|
-
default: return
|
|
610
|
+
case "memory": return Oe();
|
|
611
|
+
default: return Te((e, t) => Y.info(e, t));
|
|
611
612
|
}
|
|
612
613
|
}, X = (e) => {
|
|
613
|
-
let t = e.attempts ?? 3, n = e.suppression ??
|
|
614
|
+
let t = e.attempts ?? 3, n = e.suppression ?? M(), i = e.allowlist, a = e.production !== !0 && i !== void 0 && i.length > 0, o = (e) => i.some((t) => t.toLowerCase() === e.toLowerCase()), s = l.recurs(t).pipe(l.whileInput((e) => e.transient)), c = /* @__PURE__ */ new Map();
|
|
614
615
|
for (let t of e.templates ?? []) c.set(t.locale ? `${t.name}:${t.locale}` : t.name, t);
|
|
615
616
|
let u = (e, t) => (t ? c.get(`${e}:${t}`) : void 0) ?? c.get(e) ?? O(e, t), d = /* @__PURE__ */ new Map(), f = (e, t) => `${e.name}|${e.locale ?? ""}|${JSON.stringify(t ?? null)}`, p = (e, t) => {
|
|
616
617
|
if (d.set(e, t), d.size > 500) {
|
|
617
618
|
let e = d.keys().next().value;
|
|
618
619
|
e !== void 0 && d.delete(e);
|
|
619
620
|
}
|
|
620
|
-
}, m = e.idempotency ??
|
|
621
|
-
store: e.schedule ??
|
|
621
|
+
}, m = e.idempotency ?? P(), h = R({
|
|
622
|
+
store: e.schedule ?? I(),
|
|
622
623
|
providerSchedules: e.provider.supportsScheduling === !0,
|
|
623
624
|
flush: (e) => v(e)
|
|
624
625
|
}), g = (t) => r.gen(function* () {
|
|
625
626
|
let i = t.from ?? e.from;
|
|
626
|
-
if (!i) return yield* r.fail(new
|
|
627
|
+
if (!i) return yield* r.fail(new b({
|
|
627
628
|
provider: e.provider.name,
|
|
628
629
|
message: "no `from` — set mailPlugin({ from }) or pass message.from",
|
|
629
630
|
transient: !1
|
|
630
631
|
}));
|
|
631
|
-
let s =
|
|
632
|
+
let s = C(t.to);
|
|
632
633
|
if (a) {
|
|
633
634
|
let n = s.filter(o);
|
|
634
635
|
if (n.length === 0) return Y.warn("mail skipped — no recipient in allowlist (non-production)", {
|
|
@@ -683,7 +684,7 @@ var y = class extends u.TaggedError()("MailError", {
|
|
|
683
684
|
}
|
|
684
685
|
};
|
|
685
686
|
}), _ = (t) => {
|
|
686
|
-
let n =
|
|
687
|
+
let n = C(t.to);
|
|
687
688
|
return e.provider.send(t).pipe(r.retry(s), r.tap((i) => r.sync(() => {
|
|
688
689
|
Y.info("mail sent", {
|
|
689
690
|
provider: i.provider,
|
|
@@ -721,7 +722,7 @@ var y = class extends u.TaggedError()("MailError", {
|
|
|
721
722
|
dueAt: t.scheduledAt?.toISOString()
|
|
722
723
|
}), e.onSent?.({
|
|
723
724
|
id: "scheduled",
|
|
724
|
-
to:
|
|
725
|
+
to: C(n.message.to),
|
|
725
726
|
from: n.message.from,
|
|
726
727
|
subject: n.message.subject,
|
|
727
728
|
provider: "scheduled",
|
|
@@ -731,7 +732,7 @@ var y = class extends u.TaggedError()("MailError", {
|
|
|
731
732
|
id: "scheduled",
|
|
732
733
|
provider: "scheduled"
|
|
733
734
|
}) : yield* _(n.message);
|
|
734
|
-
}),
|
|
735
|
+
}), y = (e, t, n) => t === void 0 ? n : r.gen(function* () {
|
|
735
736
|
let r = yield* m.reserve(e, t);
|
|
736
737
|
if (!r.won) return Y.info("mail idempotent replay — skipped", { key: t }), r.prior ?? {
|
|
737
738
|
id: "idempotent-replay",
|
|
@@ -741,7 +742,7 @@ var y = class extends u.TaggedError()("MailError", {
|
|
|
741
742
|
return yield* m.record(e, t, i), i;
|
|
742
743
|
}), x = (e) => r.suspend(() => {
|
|
743
744
|
let t = u(e.template, e.locale);
|
|
744
|
-
if (!t) return r.fail(new
|
|
745
|
+
if (!t) return r.fail(new b({
|
|
745
746
|
provider: "template",
|
|
746
747
|
message: `unknown template '${e.template}'${e.locale ? ` (locale '${e.locale}')` : ""}`,
|
|
747
748
|
transient: !1
|
|
@@ -763,15 +764,15 @@ var y = class extends u.TaggedError()("MailError", {
|
|
|
763
764
|
...e.scheduledAt === void 0 ? {} : { scheduledAt: e.scheduledAt },
|
|
764
765
|
...e.idempotencyKey === void 0 ? {} : { idempotencyKey: e.idempotencyKey }
|
|
765
766
|
})));
|
|
766
|
-
}),
|
|
767
|
+
}), S = (e) => "template" in e ? x(e) : r.succeed(e);
|
|
767
768
|
return {
|
|
768
769
|
service: {
|
|
769
770
|
send: (e) => r.gen(function* () {
|
|
770
|
-
let t = yield*
|
|
771
|
-
return yield*
|
|
771
|
+
let t = yield* S(e);
|
|
772
|
+
return yield* y(t.tenantId ?? null, t.idempotencyKey, v(t));
|
|
772
773
|
}),
|
|
773
774
|
sendBatch: (t) => r.gen(function* () {
|
|
774
|
-
let n = yield* r.forEach(t,
|
|
775
|
+
let n = yield* r.forEach(t, S), i = n.some((e) => e.idempotencyKey !== void 0 || h.shouldHold(e.scheduledAt));
|
|
775
776
|
if (e.provider.sendBatch && !i) {
|
|
776
777
|
let t = [], i = [];
|
|
777
778
|
for (let e of n) {
|
|
@@ -784,10 +785,10 @@ var y = class extends u.TaggedError()("MailError", {
|
|
|
784
785
|
i && (Y.info("mail sent (batch)", {
|
|
785
786
|
provider: i.provider,
|
|
786
787
|
id: i.id,
|
|
787
|
-
to:
|
|
788
|
+
to: C(t.to).join(",")
|
|
788
789
|
}), e.onSent?.({
|
|
789
790
|
id: i.id,
|
|
790
|
-
to:
|
|
791
|
+
to: C(t.to),
|
|
791
792
|
from: t.from,
|
|
792
793
|
subject: t.subject,
|
|
793
794
|
provider: i.provider,
|
|
@@ -805,7 +806,7 @@ var y = class extends u.TaggedError()("MailError", {
|
|
|
805
806
|
provider: e.provider.name
|
|
806
807
|
} : t);
|
|
807
808
|
}
|
|
808
|
-
return yield* r.forEach(n, (e) =>
|
|
809
|
+
return yield* r.forEach(n, (e) => y(e.tenantId ?? null, e.idempotencyKey, v(e)));
|
|
809
810
|
}),
|
|
810
811
|
suppress: n.suppress,
|
|
811
812
|
unsuppress: n.unsuppress,
|
|
@@ -813,7 +814,7 @@ var y = class extends u.TaggedError()("MailError", {
|
|
|
813
814
|
},
|
|
814
815
|
scheduler: h
|
|
815
816
|
};
|
|
816
|
-
},
|
|
817
|
+
}, Z = (e) => X(e).service, Ae = (e) => a.succeed(S, Z(e)), je = (e = 200) => {
|
|
817
818
|
let t = [];
|
|
818
819
|
return {
|
|
819
820
|
record: (n) => {
|
|
@@ -844,35 +845,35 @@ var y = class extends u.TaggedError()("MailError", {
|
|
|
844
845
|
case "Suspend": return Q(e.f(), t + 1);
|
|
845
846
|
default: return null;
|
|
846
847
|
}
|
|
847
|
-
},
|
|
848
|
+
}, Me = (e) => Q(e.ast, 0), $ = (e, t, n, r, i) => t ? {
|
|
848
849
|
type: e,
|
|
849
850
|
email: t,
|
|
850
851
|
provider: n,
|
|
851
852
|
raw: i,
|
|
852
853
|
...r === void 0 ? {} : { messageId: r }
|
|
853
|
-
} : null,
|
|
854
|
+
} : null, Ne = (e) => e === "email.bounced" ? "bounced" : e === "email.complained" ? "complained" : e === "email.delivered" ? "delivered" : e === "email.opened" ? "opened" : e === "email.clicked" ? "clicked" : "unknown", Pe = (e) => e === "Bounce" ? "bounced" : e === "SpamComplaint" ? "complained" : e === "Delivery" ? "delivered" : e === "Open" ? "opened" : e === "Click" ? "clicked" : "unknown", Fe = (e) => e === "bounce" || e === "dropped" ? "bounced" : e === "spamreport" ? "complained" : e === "delivered" ? "delivered" : e === "open" ? "opened" : e === "click" ? "clicked" : "unknown", Ie = (e, t) => {
|
|
854
855
|
let n = [], r = (e) => {
|
|
855
856
|
e && n.push(e);
|
|
856
857
|
};
|
|
857
858
|
if (e === "sendgrid" && Array.isArray(t)) {
|
|
858
|
-
for (let e of t) r($(
|
|
859
|
+
for (let e of t) r($(Fe(String(e.event)), e.email, "sendgrid", e.sg_message_id, e));
|
|
859
860
|
return n;
|
|
860
861
|
}
|
|
861
862
|
let i = t ?? {};
|
|
862
863
|
if (e === "resend") {
|
|
863
864
|
let e = i.data ?? {}, a = Array.isArray(e.to) ? e.to[0] : e.to ?? e.email;
|
|
864
|
-
return r($(
|
|
865
|
+
return r($(Ne(String(i.type)), a, "resend", e.email_id, t)), n;
|
|
865
866
|
}
|
|
866
867
|
if (e === "postmark") {
|
|
867
868
|
let e = i.Email ?? i.Recipient;
|
|
868
|
-
return r($(
|
|
869
|
+
return r($(Pe(String(i.RecordType)), e, "postmark", i.MessageID, t)), n;
|
|
869
870
|
}
|
|
870
871
|
return n;
|
|
871
|
-
},
|
|
872
|
-
let r =
|
|
872
|
+
}, Le = (e, t, n, i = null) => r.gen(function* () {
|
|
873
|
+
let r = Ie(e, t);
|
|
873
874
|
for (let e of r) (e.type === "bounced" || e.type === "complained") && (yield* n.suppress(i, e.email, e.type));
|
|
874
875
|
return r;
|
|
875
|
-
}),
|
|
876
|
+
}), Re = p([
|
|
876
877
|
{
|
|
877
878
|
name: "MAIL_PROVIDER",
|
|
878
879
|
required: !1,
|
|
@@ -1053,48 +1054,53 @@ var y = class extends u.TaggedError()("MailError", {
|
|
|
1053
1054
|
secret: !1,
|
|
1054
1055
|
description: "Fallback Postgres database name for the postgres suppression store."
|
|
1055
1056
|
}
|
|
1056
|
-
]),
|
|
1057
|
-
let t = process.env, o =
|
|
1057
|
+
]), ze = "@voltro/plugin-mail", Be = (e = {}) => {
|
|
1058
|
+
let t = process.env, o = ke({
|
|
1058
1059
|
...e.provider === void 0 ? {} : { provider: e.provider },
|
|
1059
1060
|
...e.apiKey === void 0 ? {} : { apiKey: e.apiKey },
|
|
1060
1061
|
env: t
|
|
1061
|
-
}), s =
|
|
1062
|
+
}), s = Re.read("MAIL_ALLOWLIST"), c = e.allowlist ?? (s ? s.split(",").map((e) => e.trim()).filter(Boolean) : void 0), u = t.NODE_ENV === "production", p = e.suppression === void 0 || e.suppression === "memory" ? M() : e.suppression === "postgres" ? le() : e.suppression, m = e.idempotency === void 0 || e.idempotency === "memory" ? P() : e.idempotency === "postgres" ? F() : e.idempotency, h = e.schedule ?? I(), g = je(), _ = X({
|
|
1062
1063
|
provider: o,
|
|
1063
|
-
suppression:
|
|
1064
|
-
idempotency:
|
|
1065
|
-
schedule:
|
|
1066
|
-
onSent:
|
|
1064
|
+
suppression: p,
|
|
1065
|
+
idempotency: m,
|
|
1066
|
+
schedule: h,
|
|
1067
|
+
onSent: g.record,
|
|
1067
1068
|
...e.from === void 0 ? {} : { from: e.from },
|
|
1068
1069
|
...e.replyTo === void 0 ? {} : { replyTo: e.replyTo },
|
|
1069
1070
|
...c === void 0 ? {} : { allowlist: c },
|
|
1070
1071
|
...e.attempts === void 0 ? {} : { attempts: e.attempts },
|
|
1071
1072
|
...e.templates === void 0 ? {} : { templates: e.templates },
|
|
1072
1073
|
production: u
|
|
1073
|
-
}),
|
|
1074
|
-
for (let t of e.templates ?? [])
|
|
1075
|
-
let
|
|
1074
|
+
}), v = a.succeed(S, _.service), y = o.supportsScheduling !== !0, b = e.scheduleTickMs ?? 1e3, x, C = /* @__PURE__ */ new Map();
|
|
1075
|
+
for (let t of e.templates ?? []) C.set(t.locale ? `${t.name}:${t.locale}` : t.name, t);
|
|
1076
|
+
let ee = (e, t) => (t ? C.get(`${e}:${t}`) : void 0) ?? C.get(e) ?? O(e, t), w = (e) => ({
|
|
1076
1077
|
name: e.name,
|
|
1077
1078
|
...e.locale ? { locale: e.locale } : {},
|
|
1078
|
-
props: e.preview ??
|
|
1079
|
+
props: e.preview ?? Me(e.props)
|
|
1079
1080
|
}), T = () => {
|
|
1080
1081
|
let t = /* @__PURE__ */ new Map();
|
|
1081
1082
|
for (let n of e.templates ?? []) t.set(n.locale ? `${n.name}:${n.locale}` : n.name, w(n));
|
|
1082
|
-
for (let e of
|
|
1083
|
+
for (let e of k()) {
|
|
1083
1084
|
let n = O(e.name, e.locale);
|
|
1084
1085
|
n && t.set(e.locale ? `${e.name}:${e.locale}` : e.name, w(n));
|
|
1085
1086
|
}
|
|
1086
1087
|
return [...t.values()];
|
|
1087
1088
|
};
|
|
1088
1089
|
return d({
|
|
1089
|
-
name:
|
|
1090
|
+
name: f({
|
|
1091
|
+
base: ze,
|
|
1092
|
+
alias: e.alias,
|
|
1093
|
+
instance: e.name
|
|
1094
|
+
}),
|
|
1095
|
+
baseName: ze,
|
|
1090
1096
|
description: "Transactional email — MailService over Resend / Postmark / SendGrid / SMTP (+ console/memory), with default-from, transient retry and a dev allowlist.",
|
|
1091
1097
|
permissions: [
|
|
1092
1098
|
"network:outbound:*",
|
|
1093
1099
|
"inspect:read",
|
|
1094
1100
|
"inspect:write"
|
|
1095
1101
|
],
|
|
1096
|
-
declaredEnv:
|
|
1097
|
-
services:
|
|
1102
|
+
declaredEnv: Re.declared,
|
|
1103
|
+
services: v,
|
|
1098
1104
|
inspectEndpoints: [
|
|
1099
1105
|
{
|
|
1100
1106
|
method: "GET",
|
|
@@ -1102,7 +1108,7 @@ var y = class extends u.TaggedError()("MailError", {
|
|
|
1102
1108
|
description: "Recent sent mail (dev capture buffer), newest first",
|
|
1103
1109
|
handler: () => r.succeed({
|
|
1104
1110
|
kind: "json",
|
|
1105
|
-
data: { sends:
|
|
1111
|
+
data: { sends: g.list() }
|
|
1106
1112
|
})
|
|
1107
1113
|
},
|
|
1108
1114
|
{
|
|
@@ -1134,7 +1140,7 @@ var y = class extends u.TaggedError()("MailError", {
|
|
|
1134
1140
|
status: 400,
|
|
1135
1141
|
data: { error: "missing \"template\"" }
|
|
1136
1142
|
};
|
|
1137
|
-
let n =
|
|
1143
|
+
let n = ee(t.template, t.locale);
|
|
1138
1144
|
return n ? yield* E(n, t.props).pipe(r.map((e) => ({
|
|
1139
1145
|
kind: "json",
|
|
1140
1146
|
data: e
|
|
@@ -1151,9 +1157,9 @@ var y = class extends u.TaggedError()("MailError", {
|
|
|
1151
1157
|
}
|
|
1152
1158
|
],
|
|
1153
1159
|
onActivate: (t) => r.gen(function* () {
|
|
1154
|
-
if (
|
|
1155
|
-
let e =
|
|
1156
|
-
|
|
1160
|
+
if (p.activate && (yield* r.promise(() => p.activate(t.env))), m.activate && (yield* r.promise(() => m.activate(t.env))), y) {
|
|
1161
|
+
let e = _.scheduler.tick().pipe(r.repeat(l.spaced(n.millis(Math.max(50, b)))));
|
|
1162
|
+
x = r.runFork(e);
|
|
1157
1163
|
}
|
|
1158
1164
|
t.logger.info("mail active", {
|
|
1159
1165
|
provider: o.name,
|
|
@@ -1166,9 +1172,9 @@ var y = class extends u.TaggedError()("MailError", {
|
|
|
1166
1172
|
});
|
|
1167
1173
|
}),
|
|
1168
1174
|
onDeactivate: () => r.gen(function* () {
|
|
1169
|
-
|
|
1175
|
+
x !== void 0 && (yield* i.interrupt(x), x = void 0), p.deactivate && (yield* r.promise(() => p.deactivate())), m.deactivate && (yield* r.promise(() => m.deactivate()));
|
|
1170
1176
|
})
|
|
1171
1177
|
});
|
|
1172
1178
|
};
|
|
1173
1179
|
//#endregion
|
|
1174
|
-
export {
|
|
1180
|
+
export { b as MailError, S as MailService, Z as buildMailService, X as buildMailServiceWithScheduler, ie as clearGlobalTemplates, De as clearMailBuffer, Te as consoleProvider, je as createOutbox, x as defineEmail, re as globalTemplateCount, Le as handleMailEvents, L as heldId, ae as isEmailTemplate, k as listGlobalTemplates, O as lookupGlobalTemplate, Be as mailPlugin, Ae as mailServiceLayer, we as mailgunProvider, R as makeScheduler, P as memoryIdempotencyStore, Oe as memoryProvider, I as memoryScheduleStore, M as memorySuppressionStore, Ie as parseMailEvent, F as postgresIdempotencyStore, le as postgresSuppressionStore, W as postmarkProvider, Ee as readMailBuffer, ne as registerEmailTemplates, E as renderTemplate, U as resendProvider, ke as resolveProvider, _e as sendgridProvider, Se as sesProvider, q as smtpProvider };
|