@voltro/plugin-mail 0.83.0 → 0.84.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 (3) hide show
  1. package/CHANGELOG.md +717 -0
  2. package/dist/index.js +171 -168
  3. package/package.json +6 -6
package/dist/index.js CHANGED
@@ -2,84 +2,86 @@ import { Context as e, Duration as t, Effect as n, Fiber as r, Layer as i, Parse
2
2
  import { definePlugin as c, pluginInstanceName as l } from "@voltro/protocol";
3
3
  import { pluginEnv as u } from "@voltro/env";
4
4
  import { createLogger as d } from "@voltro/logger";
5
- import { and as f, eq as p, id as m, inSet as h, queryFor as g, registerRetention as _, retentionTtlMsFromEnv as ee, table as v, text as y, timestamp as b } from "@voltro/database";
6
- import { FetchHttpClient as x, HttpClient as te, HttpClientRequest as S } from "@effect/platform";
5
+ import { and as f, dropped as p, eq as m, id as h, inSet as g, queryFor as _, registerRetention as ee, retentionTtlMsFromEnv as v, table as y, text as b, timestamp as x } from "@voltro/database";
6
+ import { FetchHttpClient as te, HttpClient as S, HttpClientRequest as C } from "@effect/platform";
7
7
  //#region src/types.ts
8
- var C = class extends s.TaggedError()("MailError", {
8
+ var w = class extends s.TaggedError()("MailError", {
9
9
  provider: s.String,
10
10
  message: s.String,
11
11
  transient: s.Boolean,
12
12
  status: s.optional(s.Number)
13
- }) {}, w = class extends s.TaggedError()("MailWebhookError", {
13
+ }) {}, T = class extends s.TaggedError()("MailWebhookError", {
14
14
  provider: s.String,
15
15
  message: s.String
16
- }) {}, T = (e) => ({
16
+ }) {}, ne = (e) => ({
17
17
  name: e.name,
18
18
  props: e.props,
19
19
  subject: e.subject,
20
20
  render: e.render,
21
21
  ...e.locale === void 0 ? {} : { locale: e.locale },
22
22
  ...e.preview === void 0 ? {} : { preview: e.preview }
23
- }), ne = class extends e.Tag("@voltro/plugin-mail/MailService")() {}, E = (e) => e === void 0 ? [] : typeof e == "string" ? [e] : e, D = (e) => {
23
+ }), E = class extends e.Tag("@voltro/plugin-mail/MailService")() {}, D = (e) => e === void 0 ? [] : typeof e == "string" ? [e] : e, re = (e) => {
24
24
  try {
25
25
  let t = a.ArrayFormatter.formatErrorSync(e);
26
26
  return t.length === 0 ? String(e) : t.map((e) => `${e.path.length > 0 ? e.path.join(".") : "(root)"}: ${e.message}`).join("; ");
27
27
  } catch {
28
28
  return String(e);
29
29
  }
30
- }, O = null, re = async () => {
30
+ }, O = null, ie = async () => {
31
31
  if (!O) {
32
32
  let e = await import("@react-email/render");
33
33
  if (O = e.render ?? e.default?.render ?? null, !O) throw Error("@react-email/render: `render` export not found (install @react-email/render + react + react-dom)");
34
34
  }
35
35
  return O;
36
36
  }, k = (e, t) => n.gen(function* () {
37
- let r = e, i = yield* s.decodeUnknown(r.props)(t).pipe(n.mapError((t) => new C({
37
+ let r = e, i = yield* s.decodeUnknown(r.props)(t).pipe(n.mapError((t) => new w({
38
38
  provider: "template",
39
- message: `invalid props for '${e.name}': ${D(t)}`.slice(0, 500),
39
+ message: `invalid props for '${e.name}': ${re(t)}`.slice(0, 500),
40
40
  transient: !1
41
41
  }))), a = r.subject(i), o = r.render(i);
42
42
  return {
43
43
  subject: a,
44
44
  html: yield* n.tryPromise({
45
- try: async () => (await re())(o, { plainText: !1 }),
46
- catch: (t) => new C({
45
+ try: async () => (await ie())(o, { plainText: !1 }),
46
+ catch: (t) => new w({
47
47
  provider: "template",
48
48
  message: `render failed for '${e.name}': ${String(t)}`.slice(0, 500),
49
49
  transient: !1
50
50
  })
51
51
  }),
52
52
  text: yield* n.tryPromise({
53
- try: async () => (await re())(o, { plainText: !0 }),
54
- catch: (t) => new C({
53
+ try: async () => (await ie())(o, { plainText: !0 }),
54
+ catch: (t) => new w({
55
55
  provider: "template",
56
56
  message: `render(text) failed for '${e.name}': ${String(t)}`.slice(0, 500),
57
57
  transient: !1
58
58
  })
59
59
  })
60
60
  };
61
- }), A = /* @__PURE__ */ new Map(), ie = (e) => e.locale ? `${e.name}:${e.locale}` : e.name, ae = (e) => {
62
- for (let t of e) A.set(ie(t), t);
63
- }, j = (e, t) => (t ? A.get(`${e}:${t}`) : void 0) ?? A.get(e), oe = () => A.size, se = () => [...A.values()].map((e) => e.locale ? {
61
+ }), A = /* @__PURE__ */ new Map(), ae = (e) => e.locale ? `${e.name}:${e.locale}` : e.name, oe = (e) => {
62
+ for (let t of e) A.set(ae(t), t);
63
+ }, j = (e, t) => (t ? A.get(`${e}:${t}`) : void 0) ?? A.get(e), se = () => A.size, ce = () => [...A.values()].map((e) => e.locale ? {
64
64
  name: e.name,
65
65
  locale: e.locale
66
- } : { name: e.name }), ce = () => A.clear(), le = (e) => {
66
+ } : { name: e.name }), le = () => A.clear(), ue = (e) => {
67
67
  if (typeof e != "object" || !e) return !1;
68
68
  let t = e;
69
69
  return typeof t.name == "string" && typeof t.subject == "function" && typeof t.render == "function" && t.props !== void 0;
70
- }, M = "_voltro_mail_suppression", N = "_voltro_mail_idempotency", ue = v(M, {
71
- id: m({ scheme: "numeric" }),
72
- tenant: y().maxLength(191),
73
- email: y().maxLength(320),
74
- reason: y().nullable(),
75
- createdAt: b().default("now")
76
- }).unique("mailSuppressionAddress", ["tenant", "email"]).nonReactive(), de = v(N, {
77
- id: m({ scheme: "numeric" }),
78
- tenant: y().maxLength(191),
79
- key: y().maxLength(255),
80
- resultId: y().nullable(),
81
- resultProvider: y().nullable(),
82
- createdAt: b().default("now")
70
+ }, M = "_voltro_mail_suppression", N = "_voltro_mail_idempotency", de = y(M, {
71
+ id: h({ scheme: "numeric" }),
72
+ tenant: b().maxLength(191),
73
+ email: b().maxLength(320),
74
+ reason: b().nullable(),
75
+ createdAt: x().default("now"),
76
+ created_at: p()
77
+ }).unique("mailSuppressionAddress", ["tenant", "email"]).nonReactive(), fe = y(N, {
78
+ id: h({ scheme: "numeric" }),
79
+ tenant: b().maxLength(191),
80
+ key: b().maxLength(255),
81
+ resultId: b().nullable().renamedFrom("result_id"),
82
+ resultProvider: b().nullable().renamedFrom("result_provider"),
83
+ createdAt: x().default("now"),
84
+ created_at: p()
83
85
  }).unique("mailIdempotencyKey", ["tenant", "key"]).nonReactive(), P = (e) => n.tryPromise({
84
86
  try: e,
85
87
  catch: (e) => e
@@ -87,14 +89,14 @@ var C = class extends s.TaggedError()("MailError", {
87
89
  let t = [];
88
90
  for (let n = e, r = 0; n != null && r < 4; n = n.cause, r++) t.push(n instanceof Error ? n.message : String(n));
89
91
  return t.join(" ← ");
90
- }, fe = d({ scope: "@voltro/plugin-mail" }), I = (e) => e.trim().toLowerCase(), pe = "*", L = (e) => e ?? pe, R = () => {
92
+ }, pe = d({ scope: "@voltro/plugin-mail" }), I = (e) => e.trim().toLowerCase(), me = "*", L = (e) => e ?? me, R = () => {
91
93
  let e = /* @__PURE__ */ new Set(), t = (e, t) => `${L(e)}\u0000${I(t)}`;
92
94
  return {
93
95
  isSuppressed: (r, i) => n.sync(() => e.has(t(r, i)) || e.has(t(null, i))),
94
96
  suppress: (r, i) => n.sync(() => void e.add(t(r, i))),
95
97
  unsuppress: (r, i) => n.sync(() => void e.delete(t(r, i)))
96
98
  };
97
- }, me = () => {
99
+ }, he = () => {
98
100
  let e = null, t = (e, t) => ({
99
101
  tenant: L(e),
100
102
  email: I(t)
@@ -102,7 +104,7 @@ var C = class extends s.TaggedError()("MailError", {
102
104
  return {
103
105
  isSuppressed: (t, r) => {
104
106
  let i = e;
105
- return i ? P(() => i.query(g(ue).where(f(p("email", I(r)), h("tenant", [L(t), pe]))).limit(1).descriptor)).pipe(n.map((e) => e.length > 0), n.catchAll(() => n.succeed(!1))) : n.succeed(!1);
107
+ return i ? P(() => i.query(_(de).where(f(m("email", I(r)), g("tenant", [L(t), me]))).limit(1).descriptor)).pipe(n.map((e) => e.length > 0), n.catchAll(() => n.succeed(!1))) : n.succeed(!1);
106
108
  },
107
109
  suppress: (r, i, a) => {
108
110
  let o = e;
@@ -110,7 +112,7 @@ var C = class extends s.TaggedError()("MailError", {
110
112
  ...t(r, i),
111
113
  reason: a,
112
114
  createdAt: /* @__PURE__ */ new Date()
113
- }, { conflictColumns: ["tenant", "email"] })).pipe(n.asVoid, n.catchAll((e) => n.sync(() => fe.warn("suppress write failed", {
115
+ }, { conflictColumns: ["tenant", "email"] })).pipe(n.asVoid, n.catchAll((e) => n.sync(() => pe.warn("suppress write failed", {
114
116
  email: I(i),
115
117
  message: F(e)
116
118
  })))) : n.void;
@@ -119,13 +121,13 @@ var C = class extends s.TaggedError()("MailError", {
119
121
  let a = e;
120
122
  if (!a) return n.void;
121
123
  let { tenant: o, email: s } = t(r, i);
122
- return P(() => a.deleteMany(M, { where: f(p("tenant", o), p("email", s)) })).pipe(n.asVoid, n.catchAll(() => n.void));
124
+ return P(() => a.deleteMany(M, { where: f(m("tenant", o), m("email", s)) })).pipe(n.asVoid, n.catchAll(() => n.void));
123
125
  },
124
126
  bind: async (t) => {
125
127
  e = t;
126
128
  }
127
129
  };
128
- }, he = d({ scope: "@voltro/plugin-mail" }), z = (e) => e ?? "*", B = () => {
130
+ }, ge = d({ scope: "@voltro/plugin-mail" }), z = (e) => e ?? "*", B = () => {
129
131
  let e = /* @__PURE__ */ new Map(), t = (e, t) => `${z(e)} ${t}`;
130
132
  return {
131
133
  reserve: (r, i) => n.sync(() => {
@@ -141,7 +143,7 @@ var C = class extends s.TaggedError()("MailError", {
141
143
  }),
142
144
  record: (r, i, a) => n.sync(() => void e.set(t(r, i), a))
143
145
  };
144
- }, ge = () => {
146
+ }, _e = () => {
145
147
  let e = null;
146
148
  return {
147
149
  reserve: (t, r) => {
@@ -160,7 +162,7 @@ var C = class extends s.TaggedError()("MailError", {
160
162
  provider: r
161
163
  }
162
164
  } : { won: !1 };
163
- }), n.catchAll((e) => n.sync(() => (he.warn("idempotency reserve failed — skipping send to avoid a double", {
165
+ }), n.catchAll((e) => n.sync(() => (ge.warn("idempotency reserve failed — skipping send to avoid a double", {
164
166
  key: r,
165
167
  message: F(e)
166
168
  }), { won: !1 })))) : n.succeed({ won: !0 });
@@ -170,7 +172,7 @@ var C = class extends s.TaggedError()("MailError", {
170
172
  return a ? P(() => a.updateMany(N, {
171
173
  resultId: i.id,
172
174
  resultProvider: i.provider
173
- }, { where: f(p("tenant", z(t)), p("key", r)) })).pipe(n.asVoid, n.catchAll((e) => n.sync(() => he.warn("idempotency record failed", {
175
+ }, { where: f(m("tenant", z(t)), m("key", r)) })).pipe(n.asVoid, n.catchAll((e) => n.sync(() => ge.warn("idempotency record failed", {
174
176
  key: r,
175
177
  message: F(e)
176
178
  })))) : n.void;
@@ -179,7 +181,7 @@ var C = class extends s.TaggedError()("MailError", {
179
181
  e = t;
180
182
  }
181
183
  };
182
- }, _e = d({ scope: "@voltro/plugin-mail" }), V = () => {
184
+ }, ve = d({ scope: "@voltro/plugin-mail" }), V = () => {
183
185
  let e = /* @__PURE__ */ new Map();
184
186
  return {
185
187
  hold: (t) => n.sync(() => void e.set(t.id, t)),
@@ -190,31 +192,31 @@ var C = class extends s.TaggedError()("MailError", {
190
192
  }),
191
193
  size: () => n.sync(() => e.size)
192
194
  };
193
- }, ve = 0, ye = (e) => e.idempotencyKey ?? `held-${ve += 1}`, be = (e) => ({
195
+ }, ye = 0, be = (e) => e.idempotencyKey ?? `held-${ye += 1}`, xe = (e) => ({
194
196
  shouldHold: (t) => !e.providerSchedules && t !== void 0 && t.getTime() > Date.now(),
195
197
  hold: (t) => {
196
198
  let { scheduledAt: n, ...r } = t;
197
199
  return e.store.hold({
198
- id: ye(t),
200
+ id: be(t),
199
201
  dueAt: t.scheduledAt?.getTime() ?? Date.now(),
200
202
  message: r
201
203
  });
202
204
  },
203
205
  tick: (t = Date.now()) => n.gen(function* () {
204
206
  let r = yield* e.store.claimDue(t);
205
- for (let t of r) yield* e.flush(t.message).pipe(n.catchAll((e) => n.sync(() => _e.warn("scheduled flush failed", {
207
+ for (let t of r) yield* e.flush(t.message).pipe(n.catchAll((e) => n.sync(() => ve.warn("scheduled flush failed", {
206
208
  id: t.id,
207
209
  message: String(e)
208
210
  }))));
209
211
  return r.length;
210
212
  }),
211
213
  pending: () => e.store.size()
212
- }), xe = 0, Se = (e) => `${e}-${xe += 1}`, Ce = (e) => e === void 0 || e === 408 || e === 429 || e >= 500, H = (e, t) => {
214
+ }), Se = 0, Ce = (e) => `${e}-${Se += 1}`, we = (e) => e === void 0 || e === 408 || e === 429 || e >= 500, H = (e, t) => {
213
215
  let n = t.status;
214
- return new C({
216
+ return new w({
215
217
  provider: e,
216
218
  message: (t.message ?? "send failed").slice(0, 500),
217
- transient: e === "smtp" ? n === void 0 || n >= 400 && n < 500 : Ce(n),
219
+ transient: e === "smtp" ? n === void 0 || n >= 400 && n < 500 : we(n),
218
220
  ...n === void 0 ? {} : { status: n }
219
221
  });
220
222
  }, U = (e, t, r, i, a) => n.tryPromise({
@@ -243,14 +245,14 @@ var C = class extends s.TaggedError()("MailError", {
243
245
  message: n.message ?? t?.message ?? String(t)
244
246
  });
245
247
  }
246
- }), W = 500, we = (e, t) => {
248
+ }), W = 500, Te = (e, t) => {
247
249
  let n = e.stream === "broadcast" ? t?.broadcast ?? "broadcast" : t?.transactional;
248
250
  return {
249
251
  ...n === void 0 ? {} : { route: n },
250
252
  from: e.from,
251
- to: E(e.to),
252
- ...e.cc ? { cc: E(e.cc) } : {},
253
- ...e.bcc ? { bcc: E(e.bcc) } : {},
253
+ to: D(e.to),
254
+ ...e.cc ? { cc: D(e.cc) } : {},
255
+ ...e.bcc ? { bcc: D(e.bcc) } : {},
254
256
  ...e.replyTo ? { reply_to: [e.replyTo] } : {},
255
257
  subject: e.subject,
256
258
  ...e.html === void 0 ? {} : { html: e.html },
@@ -268,10 +270,10 @@ var C = class extends s.TaggedError()("MailError", {
268
270
  ...e.contentType ? { content_type: e.contentType } : {}
269
271
  })) } : {}
270
272
  };
271
- }, Te = (e, t, r, i = Math.floor(Date.now() / 1e3), a = 300) => n.tryPromise({
273
+ }, Ee = (e, t, r, i = Math.floor(Date.now() / 1e3), a = 300) => n.tryPromise({
272
274
  try: async () => {
273
275
  let n = (e) => {
274
- throw new w({
276
+ throw new T({
275
277
  provider: "lettermint",
276
278
  message: e
277
279
  });
@@ -291,11 +293,11 @@ var C = class extends s.TaggedError()("MailError", {
291
293
  return n("body is not JSON");
292
294
  }
293
295
  },
294
- catch: (e) => e instanceof w ? e : new w({
296
+ catch: (e) => e instanceof T ? e : new T({
295
297
  provider: "lettermint",
296
298
  message: e?.message ?? String(e)
297
299
  })
298
- }), Ee = (e) => {
300
+ }), De = (e) => {
299
301
  let t = (e.baseUrl ?? "https://api.lettermint.co/v1").replace(/\/+$/, ""), r = {
300
302
  "x-lettermint-token": e.projectToken,
301
303
  accept: "application/json"
@@ -307,28 +309,28 @@ var C = class extends s.TaggedError()("MailError", {
307
309
  send: (n) => U("lettermint", `${t}/send`, {
308
310
  ...r,
309
311
  ...n.idempotencyKey === void 0 ? {} : { "idempotency-key": n.idempotencyKey }
310
- }, we(n, e.routes), async (e) => ({
312
+ }, Te(n, e.routes), async (e) => ({
311
313
  id: (await e.json()).message_id ?? "lettermint",
312
314
  provider: "lettermint"
313
315
  })),
314
- sendBatch: (i) => n.forEach(Array.from({ length: Math.ceil(i.length / W) }, (e, t) => i.slice(t * W, (t + 1) * W)), (n) => U("lettermint", `${t}/send/batch`, r, n.map((t) => we(t, e.routes)), async (e) => {
316
+ sendBatch: (i) => n.forEach(Array.from({ length: Math.ceil(i.length / W) }, (e, t) => i.slice(t * W, (t + 1) * W)), (n) => U("lettermint", `${t}/send/batch`, r, n.map((t) => Te(t, e.routes)), async (e) => {
315
317
  let t = await e.json();
316
318
  return n.map((e, n) => ({
317
319
  id: t[n]?.message_id ?? "lettermint",
318
320
  provider: "lettermint"
319
321
  }));
320
322
  })).pipe(n.map((e) => e.flat())),
321
- webhook: { verify: Te }
323
+ webhook: { verify: Ee }
322
324
  };
323
- }, De = (e) => ({
325
+ }, Oe = (e) => ({
324
326
  from: e.from,
325
- to: E(e.to),
327
+ to: D(e.to),
326
328
  subject: e.subject,
327
329
  html: e.html,
328
330
  text: e.text,
329
331
  reply_to: e.replyTo,
330
- cc: e.cc ? E(e.cc) : void 0,
331
- bcc: e.bcc ? E(e.bcc) : void 0,
332
+ cc: e.cc ? D(e.cc) : void 0,
333
+ bcc: e.bcc ? D(e.bcc) : void 0,
332
334
  headers: e.headers,
333
335
  tags: e.tags?.map((e) => ({
334
336
  name: e,
@@ -340,34 +342,34 @@ var C = class extends s.TaggedError()("MailError", {
340
342
  content: e.content,
341
343
  ...e.contentType ? { content_type: e.contentType } : {}
342
344
  }))
343
- }), Oe = (e) => ({
345
+ }), ke = (e) => ({
344
346
  name: "resend",
345
347
  supportsScheduling: !0,
346
- send: (t) => U("resend", "https://api.resend.com/emails", { authorization: `Bearer ${e.apiKey}` }, De(t), async (e) => ({
348
+ send: (t) => U("resend", "https://api.resend.com/emails", { authorization: `Bearer ${e.apiKey}` }, Oe(t), async (e) => ({
347
349
  id: (await e.json()).id ?? "resend",
348
350
  provider: "resend"
349
351
  })),
350
- sendBatch: (t) => U("resend", "https://api.resend.com/emails/batch", { authorization: `Bearer ${e.apiKey}` }, t.map(De), async (e) => {
352
+ sendBatch: (t) => U("resend", "https://api.resend.com/emails/batch", { authorization: `Bearer ${e.apiKey}` }, t.map(Oe), async (e) => {
351
353
  let n = (await e.json()).data ?? [];
352
354
  return t.map((e, t) => ({
353
355
  id: n[t]?.id ?? "resend",
354
356
  provider: "resend"
355
357
  }));
356
358
  })
357
- }), ke = (e) => ({
359
+ }), Ae = (e) => ({
358
360
  name: "postmark",
359
361
  send: (t) => U("postmark", "https://api.postmarkapp.com/email", {
360
362
  "x-postmark-server-token": e.serverToken,
361
363
  accept: "application/json"
362
364
  }, {
363
365
  From: t.from,
364
- To: E(t.to).join(","),
366
+ To: D(t.to).join(","),
365
367
  Subject: t.subject,
366
368
  HtmlBody: t.html,
367
369
  TextBody: t.text,
368
370
  ReplyTo: t.replyTo,
369
- Cc: t.cc ? E(t.cc).join(",") : void 0,
370
- Bcc: t.bcc ? E(t.bcc).join(",") : void 0,
371
+ Cc: t.cc ? D(t.cc).join(",") : void 0,
372
+ Bcc: t.bcc ? D(t.bcc).join(",") : void 0,
371
373
  MessageStream: t.stream === "broadcast" ? e.streams?.broadcast ?? "broadcast" : e.streams?.transactional ?? "outbound",
372
374
  Headers: t.headers ? Object.entries(t.headers).map(([e, t]) => ({
373
375
  Name: e,
@@ -383,31 +385,31 @@ var C = class extends s.TaggedError()("MailError", {
383
385
  id: (await e.json()).MessageID ?? "postmark",
384
386
  provider: "postmark"
385
387
  }))
386
- }), Ae = (e) => [...e.text ? [{
388
+ }), je = (e) => [...e.text ? [{
387
389
  type: "text/plain",
388
390
  value: e.text
389
391
  }] : [], ...e.html ? [{
390
392
  type: "text/html",
391
393
  value: e.html
392
- }] : []], je = (e) => ({
393
- to: E(e.to).map((e) => ({ email: e })),
394
- cc: e.cc ? E(e.cc).map((e) => ({ email: e })) : void 0,
395
- bcc: e.bcc ? E(e.bcc).map((e) => ({ email: e })) : void 0,
394
+ }] : []], Me = (e) => ({
395
+ to: D(e.to).map((e) => ({ email: e })),
396
+ cc: e.cc ? D(e.cc).map((e) => ({ email: e })) : void 0,
397
+ bcc: e.bcc ? D(e.bcc).map((e) => ({ email: e })) : void 0,
396
398
  subject: e.subject,
397
399
  ...e.scheduledAt ? { send_at: Math.floor(e.scheduledAt.getTime() / 1e3) } : {}
398
- }), Me = (e) => e.attachments?.map((e) => ({
400
+ }), Ne = (e) => e.attachments?.map((e) => ({
399
401
  filename: e.filename,
400
402
  content: e.content,
401
403
  type: e.contentType ?? "application/octet-stream",
402
404
  disposition: "attachment"
403
- })), Ne = (e) => {
405
+ })), Pe = (e) => {
404
406
  let t = (e) => ({
405
- personalizations: [je(e)],
407
+ personalizations: [Me(e)],
406
408
  from: { email: e.from },
407
409
  reply_to: e.replyTo ? { email: e.replyTo } : void 0,
408
410
  subject: e.subject,
409
- content: Ae(e),
410
- attachments: Me(e)
411
+ content: je(e),
412
+ attachments: Ne(e)
411
413
  });
412
414
  return {
413
415
  name: "sendgrid",
@@ -417,10 +419,10 @@ var C = class extends s.TaggedError()("MailError", {
417
419
  provider: "sendgrid"
418
420
  })),
419
421
  sendBatch: (t) => U("sendgrid", "https://api.sendgrid.com/v3/mail/send", { authorization: `Bearer ${e.apiKey}` }, {
420
- personalizations: t.map(je),
422
+ personalizations: t.map(Me),
421
423
  from: { email: t[0]?.from },
422
424
  subject: t[0]?.subject,
423
- content: Ae(t[0] ?? {})
425
+ content: je(t[0] ?? {})
424
426
  }, async (e) => {
425
427
  let n = e.headers.get("x-message-id") ?? "sendgrid";
426
428
  return t.map((e, t) => ({
@@ -429,14 +431,14 @@ var C = class extends s.TaggedError()("MailError", {
429
431
  }));
430
432
  })
431
433
  };
432
- }, Pe = (e, t) => {
434
+ }, Fe = (e, t) => {
433
435
  let n = t, r = n.response?.status;
434
436
  return H(e, {
435
437
  ...typeof r == "number" ? { status: r } : {},
436
438
  message: n.message ?? String(t)
437
439
  });
438
- }, Fe = (e, t, r) => n.gen(function* () {
439
- let i = yield* (yield* te.HttpClient).execute(t);
440
+ }, Ie = (e, t, r) => n.gen(function* () {
441
+ let i = yield* (yield* S.HttpClient).execute(t);
440
442
  if (i.status < 200 || i.status >= 300) {
441
443
  let t = yield* i.text.pipe(n.catchAll(() => n.succeed("")));
442
444
  return yield* n.fail(H(e, {
@@ -445,19 +447,19 @@ var C = class extends s.TaggedError()("MailError", {
445
447
  }));
446
448
  }
447
449
  return yield* r(i);
448
- }).pipe(n.catchAll((t) => t instanceof C ? n.fail(t) : n.fail(Pe(e, t))), n.provide(x.layer)), Ie = (e) => ({ sign: async (t, n, r) => {
450
+ }).pipe(n.catchAll((t) => t instanceof w ? n.fail(t) : n.fail(Fe(e, t))), n.provide(te.layer)), Le = (e) => ({ sign: async (t, n, r) => {
449
451
  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");
450
452
  return {
451
453
  authorization: `AWS4-HMAC-SHA256 Credential=${e.accessKeyId}/${p}, SignedHeaders=${d}, Signature=${h}`,
452
454
  "x-amz-date": c,
453
455
  ...e.sessionToken ? { "x-amz-security-token": e.sessionToken } : {}
454
456
  };
455
- } }), Le = (e) => JSON.stringify({
457
+ } }), Re = (e) => JSON.stringify({
456
458
  FromEmailAddress: e.from,
457
459
  Destination: {
458
- ToAddresses: E(e.to),
459
- ...e.cc ? { CcAddresses: E(e.cc) } : {},
460
- ...e.bcc ? { BccAddresses: E(e.bcc) } : {}
460
+ ToAddresses: D(e.to),
461
+ ...e.cc ? { CcAddresses: D(e.cc) } : {},
462
+ ...e.bcc ? { BccAddresses: D(e.bcc) } : {}
461
463
  },
462
464
  ...e.replyTo ? { ReplyToAddresses: [e.replyTo] } : {},
463
465
  Content: { Simple: {
@@ -476,41 +478,41 @@ var C = class extends s.TaggedError()("MailError", {
476
478
  } } : {}
477
479
  }
478
480
  } }
479
- }), Re = (e) => {
480
- let t = Ie(e), r = `https://email.${e.region}.amazonaws.com`, i = "/v2/email/outbound-emails";
481
+ }), ze = (e) => {
482
+ let t = Le(e), r = `https://email.${e.region}.amazonaws.com`, i = "/v2/email/outbound-emails";
481
483
  return {
482
484
  name: "ses",
483
485
  send: (e) => n.gen(function* () {
484
- let a = Le(e), o = yield* n.tryPromise({
486
+ let a = Re(e), o = yield* n.tryPromise({
485
487
  try: () => t.sign(r, i, a),
486
488
  catch: (e) => H("ses", { message: e?.message ?? String(e) })
487
489
  });
488
- return yield* Fe("ses", S.post(`${r}${i}`).pipe(S.setHeaders({
490
+ return yield* Ie("ses", C.post(`${r}${i}`).pipe(C.setHeaders({
489
491
  "content-type": "application/json",
490
492
  ...o
491
- }), S.bodyUnsafeJson(JSON.parse(a))), (e) => e.json.pipe(n.map((e) => ({
493
+ }), C.bodyUnsafeJson(JSON.parse(a))), (e) => e.json.pipe(n.map((e) => ({
492
494
  id: e.MessageId ?? "ses",
493
495
  provider: "ses"
494
496
  }))));
495
497
  })
496
498
  };
497
- }, ze = (e) => {
499
+ }, Be = (e) => {
498
500
  let t = [["from", e.from], ["subject", e.subject]];
499
- for (let n of E(e.to)) t.push(["to", n]);
500
- if (e.cc) for (let n of E(e.cc)) t.push(["cc", n]);
501
- if (e.bcc) for (let n of E(e.bcc)) t.push(["bcc", n]);
501
+ for (let n of D(e.to)) t.push(["to", n]);
502
+ if (e.cc) for (let n of D(e.cc)) t.push(["cc", n]);
503
+ if (e.bcc) for (let n of D(e.bcc)) t.push(["bcc", n]);
502
504
  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]);
503
505
  if (e.tags) for (let n of e.tags) t.push(["o:tag", n]);
504
506
  return e.scheduledAt && t.push(["o:deliverytime", e.scheduledAt.toUTCString()]), t;
505
- }, Be = (e) => {
507
+ }, Ve = (e) => {
506
508
  let t = `${e.baseUrl ?? "https://api.mailgun.net"}/v3/${e.domain}/messages`;
507
509
  return {
508
510
  name: "mailgun",
509
511
  supportsScheduling: !0,
510
512
  send: (r) => {
511
513
  let i = new URLSearchParams();
512
- for (let [e, t] of ze(r)) i.append(e, t);
513
- return Fe("mailgun", S.post(t).pipe(S.setHeader("authorization", `Basic ${Buffer.from(`api:${e.apiKey}`).toString("base64")}`), S.bodyText(i.toString(), "application/x-www-form-urlencoded")), (e) => e.json.pipe(n.map((e) => ({
514
+ for (let [e, t] of Be(r)) i.append(e, t);
515
+ return Ie("mailgun", C.post(t).pipe(C.setHeader("authorization", `Basic ${Buffer.from(`api:${e.apiKey}`).toString("base64")}`), C.bodyText(i.toString(), "application/x-www-form-urlencoded")), (e) => e.json.pipe(n.map((e) => ({
514
516
  id: e.id ?? "mailgun",
515
517
  provider: "mailgun"
516
518
  }))));
@@ -535,9 +537,9 @@ var C = class extends s.TaggedError()("MailError", {
535
537
  return {
536
538
  id: (await t.sendMail({
537
539
  from: r.from,
538
- to: E(r.to),
539
- cc: r.cc ? E(r.cc) : void 0,
540
- bcc: r.bcc ? E(r.bcc) : void 0,
540
+ to: D(r.to),
541
+ cc: r.cc ? D(r.cc) : void 0,
542
+ bcc: r.bcc ? D(r.bcc) : void 0,
541
543
  replyTo: r.replyTo,
542
544
  subject: r.subject,
543
545
  html: r.html,
@@ -562,41 +564,41 @@ var C = class extends s.TaggedError()("MailError", {
562
564
  }
563
565
  })
564
566
  };
565
- }, Ve = (e) => ({
567
+ }, He = (e) => ({
566
568
  name: "console",
567
569
  send: (t) => n.sync(() => {
568
- let n = `✉ to=${E(t.to).join(",")} subject=${JSON.stringify(t.subject)}`;
570
+ let n = `✉ to=${D(t.to).join(",")} subject=${JSON.stringify(t.subject)}`;
569
571
  return e ? e(n, { from: t.from }) : process.stdout.write(`[mail:console] ${n}\n`), {
570
- id: Se("console"),
572
+ id: Ce("console"),
571
573
  provider: "console"
572
574
  };
573
575
  })
574
- }), K = [], He = () => [...K], Ue = () => {
576
+ }), K = [], Ue = () => [...K], We = () => {
575
577
  K.length = 0;
576
- }, We = () => ({
578
+ }, Ge = () => ({
577
579
  name: "memory",
578
580
  send: (e) => n.sync(() => (K.push(e), {
579
- id: Se("mem"),
581
+ id: Ce("mem"),
580
582
  provider: "memory"
581
583
  }))
582
- }), q = d({ scope: "@voltro/plugin-mail" }), Ge = (e) => {
584
+ }), q = d({ scope: "@voltro/plugin-mail" }), Ke = (e) => {
583
585
  if (e.provider !== void 0 && typeof e.provider != "string") return e.provider;
584
586
  let t = e.env ?? {}, n = e.provider ?? t.MAIL_PROVIDER ?? "console", r = (e, t) => {
585
587
  if (!t) throw Error(`@voltro/plugin-mail: provider '${n}' needs apiKey or ${e}`);
586
588
  return t;
587
589
  };
588
590
  switch (n) {
589
- case "lettermint": return Ee({ projectToken: r("LETTERMINT_PROJECT_TOKEN", e.apiKey ?? t.LETTERMINT_PROJECT_TOKEN) });
590
- case "resend": return Oe({ apiKey: r("RESEND_API_KEY", e.apiKey ?? t.RESEND_API_KEY) });
591
- case "postmark": return ke({ serverToken: r("POSTMARK_SERVER_TOKEN", e.apiKey ?? t.POSTMARK_SERVER_TOKEN) });
592
- case "sendgrid": return Ne({ apiKey: r("SENDGRID_API_KEY", e.apiKey ?? t.SENDGRID_API_KEY) });
593
- case "ses": return Re({
591
+ case "lettermint": return De({ projectToken: r("LETTERMINT_PROJECT_TOKEN", e.apiKey ?? t.LETTERMINT_PROJECT_TOKEN) });
592
+ case "resend": return ke({ apiKey: r("RESEND_API_KEY", e.apiKey ?? t.RESEND_API_KEY) });
593
+ case "postmark": return Ae({ serverToken: r("POSTMARK_SERVER_TOKEN", e.apiKey ?? t.POSTMARK_SERVER_TOKEN) });
594
+ case "sendgrid": return Pe({ apiKey: r("SENDGRID_API_KEY", e.apiKey ?? t.SENDGRID_API_KEY) });
595
+ case "ses": return ze({
594
596
  region: r("AWS_REGION", t.AWS_REGION),
595
597
  accessKeyId: r("AWS_ACCESS_KEY_ID", t.AWS_ACCESS_KEY_ID),
596
598
  secretAccessKey: r("AWS_SECRET_ACCESS_KEY", t.AWS_SECRET_ACCESS_KEY),
597
599
  ...t.AWS_SESSION_TOKEN ? { sessionToken: t.AWS_SESSION_TOKEN } : {}
598
600
  });
599
- case "mailgun": return Be({
601
+ case "mailgun": return Ve({
600
602
  apiKey: r("MAILGUN_API_KEY", e.apiKey ?? t.MAILGUN_API_KEY),
601
603
  domain: r("MAILGUN_DOMAIN", t.MAILGUN_DOMAIN),
602
604
  ...t.MAILGUN_BASE_URL ? { baseUrl: t.MAILGUN_BASE_URL } : {}
@@ -610,8 +612,8 @@ var C = class extends s.TaggedError()("MailError", {
610
612
  pass: t.SMTP_PASS
611
613
  } } : {}
612
614
  });
613
- case "memory": return We();
614
- default: return Ve((e, t) => q.info(e, t));
615
+ case "memory": return Ge();
616
+ default: return He((e, t) => q.info(e, t));
615
617
  }
616
618
  }, J = (e) => {
617
619
  let t = e.attempts ?? 3, r = e.suppression ?? R(), i = e.allowlist, a = e.production !== !0 && i !== void 0 && i.length > 0, s = (e) => i.some((t) => t.toLowerCase() === e.toLowerCase()), c = o.recurs(t).pipe(o.whileInput((e) => e.transient)), l = /* @__PURE__ */ new Map();
@@ -621,14 +623,14 @@ var C = class extends s.TaggedError()("MailError", {
621
623
  let e = d.keys().next().value;
622
624
  e !== void 0 && d.delete(e);
623
625
  }
624
- }, m = e.idempotency ?? B(), h = be({
626
+ }, m = e.idempotency ?? B(), h = xe({
625
627
  store: e.schedule ?? V(),
626
628
  providerSchedules: e.provider.supportsScheduling === !0,
627
629
  flush: (e) => v(e)
628
630
  }), g = (t) => {
629
631
  if (t.stream !== "broadcast" || e.provider.managesUnsubscribe === !0) return n.succeed(void 0);
630
632
  let r = t.unsubscribe;
631
- if (r === void 0 || !r.oneClickUrl.startsWith("https://")) return n.fail(new C({
633
+ if (r === void 0 || !r.oneClickUrl.startsWith("https://")) return n.fail(new w({
632
634
  provider: e.provider.name,
633
635
  message: `a broadcast needs \`unsubscribe: { oneClickUrl }\` (an https URL) — '${e.provider.name}' does not unsubscribe recipients itself`,
634
636
  transient: !1
@@ -640,12 +642,12 @@ var C = class extends s.TaggedError()("MailError", {
640
642
  });
641
643
  }, _ = (t) => n.gen(function* () {
642
644
  let i = t.from ?? e.from;
643
- if (!i) return yield* n.fail(new C({
645
+ if (!i) return yield* n.fail(new w({
644
646
  provider: e.provider.name,
645
647
  message: "no `from` — set mailPlugin({ from }) or pass message.from",
646
648
  transient: !1
647
649
  }));
648
- let o = E(t.to);
650
+ let o = D(t.to);
649
651
  if (a) {
650
652
  let n = o.filter(s);
651
653
  if (n.length === 0) return q.warn("mail skipped — no recipient in allowlist (non-production)", {
@@ -704,7 +706,7 @@ var C = class extends s.TaggedError()("MailError", {
704
706
  }
705
707
  };
706
708
  }), ee = (t) => {
707
- let r = E(t.to);
709
+ let r = D(t.to);
708
710
  return e.provider.send(t).pipe(n.retry(c), n.tap((i) => n.sync(() => {
709
711
  q.info("mail sent", {
710
712
  provider: i.provider,
@@ -742,7 +744,7 @@ var C = class extends s.TaggedError()("MailError", {
742
744
  dueAt: t.scheduledAt?.toISOString()
743
745
  }), e.onSent?.({
744
746
  id: "scheduled",
745
- to: E(n.message.to),
747
+ to: D(n.message.to),
746
748
  from: n.message.from,
747
749
  subject: n.message.subject,
748
750
  provider: "scheduled",
@@ -762,7 +764,7 @@ var C = class extends s.TaggedError()("MailError", {
762
764
  return yield* m.record(e, t, i), i;
763
765
  }), b = (e) => n.suspend(() => {
764
766
  let t = u(e.template, e.locale);
765
- if (!t) return n.fail(new C({
767
+ if (!t) return n.fail(new w({
766
768
  provider: "template",
767
769
  message: `unknown template '${e.template}'${e.locale ? ` (locale '${e.locale}')` : ""}`,
768
770
  transient: !1
@@ -808,10 +810,10 @@ var C = class extends s.TaggedError()("MailError", {
808
810
  i && (q.info("mail sent (batch)", {
809
811
  provider: i.provider,
810
812
  id: i.id,
811
- to: E(t.to).join(",")
813
+ to: D(t.to).join(",")
812
814
  }), e.onSent?.({
813
815
  id: i.id,
814
- to: E(t.to),
816
+ to: D(t.to),
815
817
  from: t.from,
816
818
  subject: t.subject,
817
819
  provider: i.provider,
@@ -841,7 +843,7 @@ var C = class extends s.TaggedError()("MailError", {
841
843
  },
842
844
  scheduler: h
843
845
  };
844
- }, Ke = (e) => J(e).service, qe = (e) => i.succeed(ne, Ke(e)), Y = (e, t, n, r, i, a = {}) => {
846
+ }, qe = (e) => J(e).service, Je = (e) => i.succeed(E, qe(e)), Y = (e, t, n, r, i, a = {}) => {
845
847
  if (!t) return null;
846
848
  let o = a.metadata !== null && typeof a.metadata == "object" ? Object.fromEntries(Object.entries(a.metadata).filter(([, e]) => typeof e == "string")) : void 0;
847
849
  return {
@@ -853,36 +855,36 @@ var C = class extends s.TaggedError()("MailError", {
853
855
  ...a.eventId === void 0 ? {} : { eventId: a.eventId },
854
856
  ...o === void 0 ? {} : { metadata: o }
855
857
  };
856
- }, Je = (e) => e === "message.hard_bounced" ? "bounced" : e === "message.spam_complaint" ? "complained" : e === "message.unsubscribed" ? "unsubscribed" : e === "message.delivered" ? "delivered" : e === "message.opened" ? "opened" : e === "message.clicked" ? "clicked" : "unknown", Ye = (e) => e === "hard_bounce" ? "bounced" : e === "spam_complaint" ? "complained" : e === "unsubscribe" ? "unsubscribed" : "unknown", Xe = (e) => e === "email.bounced" ? "bounced" : e === "email.complained" ? "complained" : e === "email.delivered" ? "delivered" : e === "email.opened" ? "opened" : e === "email.clicked" ? "clicked" : "unknown", Ze = (e) => e === "Bounce" ? "bounced" : e === "SpamComplaint" ? "complained" : e === "Delivery" ? "delivered" : e === "Open" ? "opened" : e === "Click" ? "clicked" : "unknown", Qe = (e) => e === "bounce" || e === "dropped" ? "bounced" : e === "spamreport" ? "complained" : e === "delivered" ? "delivered" : e === "open" ? "opened" : e === "click" ? "clicked" : "unknown", X = (e, t) => {
858
+ }, Ye = (e) => e === "message.hard_bounced" ? "bounced" : e === "message.spam_complaint" ? "complained" : e === "message.unsubscribed" ? "unsubscribed" : e === "message.delivered" ? "delivered" : e === "message.opened" ? "opened" : e === "message.clicked" ? "clicked" : "unknown", Xe = (e) => e === "hard_bounce" ? "bounced" : e === "spam_complaint" ? "complained" : e === "unsubscribe" ? "unsubscribed" : "unknown", Ze = (e) => e === "email.bounced" ? "bounced" : e === "email.complained" ? "complained" : e === "email.delivered" ? "delivered" : e === "email.opened" ? "opened" : e === "email.clicked" ? "clicked" : "unknown", Qe = (e) => e === "Bounce" ? "bounced" : e === "SpamComplaint" ? "complained" : e === "Delivery" ? "delivered" : e === "Open" ? "opened" : e === "Click" ? "clicked" : "unknown", $e = (e) => e === "bounce" || e === "dropped" ? "bounced" : e === "spamreport" ? "complained" : e === "delivered" ? "delivered" : e === "open" ? "opened" : e === "click" ? "clicked" : "unknown", X = (e, t) => {
857
859
  let n = [], r = (e) => {
858
860
  e && n.push(e);
859
861
  };
860
862
  if (e === "sendgrid" && Array.isArray(t)) {
861
- for (let e of t) r(Y(Qe(String(e.event)), e.email, "sendgrid", e.sg_message_id, e));
863
+ for (let e of t) r(Y($e(String(e.event)), e.email, "sendgrid", e.sg_message_id, e));
862
864
  return n;
863
865
  }
864
866
  let i = t ?? {};
865
867
  if (e === "lettermint") {
866
868
  let e = String(i.event), a = i.data ?? {}, o = typeof i.id == "string" ? i.id : void 0;
867
- return e === "suppression.added" ? (a.type === "email" && r(Y(Ye(String(a.reason)), a.value, "lettermint", void 0, t, { eventId: o })), n) : e === "suppression.removed" ? (a.type === "email" && r(Y("unsuppressed", a.value, "lettermint", void 0, t, { eventId: o })), n) : (e.startsWith("message.") && r(Y(Je(e), a.recipient, "lettermint", a.message_id, t, {
869
+ return e === "suppression.added" ? (a.type === "email" && r(Y(Xe(String(a.reason)), a.value, "lettermint", void 0, t, { eventId: o })), n) : e === "suppression.removed" ? (a.type === "email" && r(Y("unsuppressed", a.value, "lettermint", void 0, t, { eventId: o })), n) : (e.startsWith("message.") && r(Y(Ye(e), a.recipient, "lettermint", a.message_id, t, {
868
870
  eventId: o,
869
871
  metadata: a.metadata
870
872
  })), n);
871
873
  }
872
874
  if (e === "resend") {
873
875
  let e = i.data ?? {}, a = Array.isArray(e.to) ? e.to[0] : e.to ?? e.email;
874
- return r(Y(Xe(String(i.type)), a, "resend", e.email_id, t)), n;
876
+ return r(Y(Ze(String(i.type)), a, "resend", e.email_id, t)), n;
875
877
  }
876
878
  if (e === "postmark") {
877
879
  let e = i.Email ?? i.Recipient;
878
- return r(Y(Ze(String(i.RecordType)), e, "postmark", i.MessageID, t, { metadata: i.Metadata })), n;
880
+ return r(Y(Qe(String(i.RecordType)), e, "postmark", i.MessageID, t, { metadata: i.Metadata })), n;
879
881
  }
880
882
  return n;
881
- }, $e = (e, t, r, i = null) => n.gen(function* () {
883
+ }, et = (e, t, r, i = null) => n.gen(function* () {
882
884
  let n = X(e, t);
883
885
  for (let e of n) e.type === "bounced" || e.type === "complained" ? yield* r.suppress(i, e.email, e.type) : e.type === "unsuppressed" && (yield* r.unsuppress(i, e.email));
884
886
  return n;
885
- }), et = (e = 200) => {
887
+ }), tt = (e = 200) => {
886
888
  let t = [];
887
889
  return {
888
890
  record: (n) => {
@@ -893,18 +895,18 @@ var C = class extends s.TaggedError()("MailError", {
893
895
  t.length = 0;
894
896
  }
895
897
  };
896
- }, tt = {
898
+ }, nt = {
897
899
  lettermint: "api.lettermint.co",
898
900
  resend: "api.resend.com",
899
901
  postmark: "api.postmarkapp.com",
900
902
  sendgrid: "api.sendgrid.com"
901
- }, nt = (e) => {
903
+ }, rt = (e) => {
902
904
  try {
903
905
  return new URL(e).host || void 0;
904
906
  } catch {
905
907
  return;
906
908
  }
907
- }, rt = (e) => {
909
+ }, it = (e) => {
908
910
  let t = e.env ?? {}, n = (e) => [{
909
911
  destination: e,
910
912
  purpose: "outgoing email: recipients, subject and body",
@@ -915,12 +917,12 @@ var C = class extends s.TaggedError()("MailError", {
915
917
  let t = e.provider.name;
916
918
  return t === "console" || t === "memory" ? [] : n(`runtime:the '${t}' mail provider`);
917
919
  }
918
- let r = e.provider ?? t.MAIL_PROVIDER ?? "console", i = tt[r];
920
+ let r = e.provider ?? t.MAIL_PROVIDER ?? "console", i = nt[r];
919
921
  if (i !== void 0) return n(i);
920
922
  switch (r) {
921
923
  case "ses": return n(t.AWS_REGION ? `email.${t.AWS_REGION}.amazonaws.com` : "runtime:email.<AWS_REGION>.amazonaws.com");
922
- case "mailgun": return n((t.MAILGUN_BASE_URL ? nt(t.MAILGUN_BASE_URL) : void 0) ?? "api.mailgun.net");
923
- case "smtp": return n((t.SMTP_URL ? nt(t.SMTP_URL) : void 0) ?? (t.SMTP_HOST ? `${t.SMTP_HOST}${t.SMTP_PORT ? `:${t.SMTP_PORT}` : ""}` : void 0) ?? "runtime:SMTP_URL or SMTP_HOST");
924
+ case "mailgun": return n((t.MAILGUN_BASE_URL ? rt(t.MAILGUN_BASE_URL) : void 0) ?? "api.mailgun.net");
925
+ case "smtp": return n((t.SMTP_URL ? rt(t.SMTP_URL) : void 0) ?? (t.SMTP_HOST ? `${t.SMTP_HOST}${t.SMTP_PORT ? `:${t.SMTP_PORT}` : ""}` : void 0) ?? "runtime:SMTP_URL or SMTP_HOST");
924
926
  default: return [];
925
927
  }
926
928
  }, Z = (e, t) => {
@@ -943,7 +945,7 @@ var C = class extends s.TaggedError()("MailError", {
943
945
  case "Suspend": return Z(e.f(), t + 1);
944
946
  default: return null;
945
947
  }
946
- }, it = (e) => Z(e.ast, 0), Q = u([
948
+ }, at = (e) => Z(e.ast, 0), Q = u([
947
949
  {
948
950
  name: "MAIL_PROVIDER",
949
951
  required: !1,
@@ -1064,11 +1066,11 @@ var C = class extends s.TaggedError()("MailError", {
1064
1066
  secret: !1,
1065
1067
  description: "Comma-separated recipient allowlist; in dev, mail to addresses outside it is skipped."
1066
1068
  }
1067
- ]), at = "@voltro/plugin-mail", $ = (e, t) => ({
1069
+ ]), ot = "@voltro/plugin-mail", $ = (e, t) => ({
1068
1070
  status: e,
1069
1071
  contentType: "application/json",
1070
1072
  body: JSON.stringify(t)
1071
- }), ot = (e, t, r, i) => {
1073
+ }), st = (e, t, r, i) => {
1072
1074
  let a = e.webhook;
1073
1075
  if (a === void 0) throw Error(`@voltro/plugin-mail: provider '${e.name}' has no webhook verifier — mailPlugin({ webhook }) needs one (lettermint)`);
1074
1076
  let o = r.secret ?? Q.read("MAIL_WEBHOOK_SECRET");
@@ -1096,46 +1098,46 @@ var C = class extends s.TaggedError()("MailError", {
1096
1098
  return $(200, { received: c.length });
1097
1099
  }
1098
1100
  };
1099
- }, st = (e = {}) => {
1100
- let a = process.env, s = Ge({
1101
+ }, ct = (e = {}) => {
1102
+ let a = process.env, s = Ke({
1101
1103
  ...e.provider === void 0 ? {} : { provider: e.provider },
1102
1104
  ...e.apiKey === void 0 ? {} : { apiKey: e.apiKey },
1103
1105
  env: a
1104
- }), u = Q.read("MAIL_ALLOWLIST"), d = e.allowlist ?? (u ? u.split(",").map((e) => e.trim()).filter(Boolean) : void 0), f = a.NODE_ENV === "production", p = e.suppression === void 0 || e.suppression === "memory" ? R() : e.suppression === "postgres" ? me() : e.suppression, m = e.idempotency === void 0 || e.idempotency === "memory" ? B() : e.idempotency === "postgres" ? ge() : e.idempotency, h = e.schedule ?? V(), g = [...e.suppression === "postgres" ? [ue] : [], ...e.idempotency === "postgres" ? [de] : []];
1105
- e.idempotency === "postgres" && _({
1106
+ }), u = Q.read("MAIL_ALLOWLIST"), d = e.allowlist ?? (u ? u.split(",").map((e) => e.trim()).filter(Boolean) : void 0), f = a.NODE_ENV === "production", p = e.suppression === void 0 || e.suppression === "memory" ? R() : e.suppression === "postgres" ? he() : e.suppression, m = e.idempotency === void 0 || e.idempotency === "memory" ? B() : e.idempotency === "postgres" ? _e() : e.idempotency, h = e.schedule ?? V(), g = [...e.suppression === "postgres" ? [de] : [], ...e.idempotency === "postgres" ? [fe] : []];
1107
+ e.idempotency === "postgres" && ee({
1106
1108
  source: "plugin",
1107
1109
  table: N,
1108
1110
  timeColumn: "createdAt",
1109
- ttlMs: ee(process.env.VOLTRO_MAIL_IDEMPOTENCY_TTL_HOURS, 720),
1111
+ ttlMs: v(process.env.VOLTRO_MAIL_IDEMPOTENCY_TTL_HOURS, 720),
1110
1112
  label: "mail idempotency keys"
1111
1113
  });
1112
- let v = et(), y = J({
1114
+ let _ = tt(), y = J({
1113
1115
  provider: s,
1114
1116
  suppression: p,
1115
1117
  idempotency: m,
1116
1118
  schedule: h,
1117
- onSent: v.record,
1119
+ onSent: _.record,
1118
1120
  ...e.from === void 0 ? {} : { from: e.from },
1119
1121
  ...e.replyTo === void 0 ? {} : { replyTo: e.replyTo },
1120
1122
  ...d === void 0 ? {} : { allowlist: d },
1121
1123
  ...e.attempts === void 0 ? {} : { attempts: e.attempts },
1122
1124
  ...e.templates === void 0 ? {} : { templates: e.templates },
1123
1125
  production: f
1124
- }), b = i.succeed(ne, y.service), x = s.supportsScheduling !== !0, te = e.scheduleTickMs ?? 1e3, S, C = /* @__PURE__ */ new Map();
1126
+ }), b = i.succeed(E, y.service), x = s.supportsScheduling !== !0, te = e.scheduleTickMs ?? 1e3, S, C = /* @__PURE__ */ new Map();
1125
1127
  for (let t of e.templates ?? []) C.set(t.locale ? `${t.name}:${t.locale}` : t.name, t);
1126
1128
  let w = (e, t) => (t ? C.get(`${e}:${t}`) : void 0) ?? C.get(e) ?? j(e, t), T = (e) => ({
1127
1129
  name: e.name,
1128
1130
  ...e.locale ? { locale: e.locale } : {},
1129
- props: e.preview ?? it(e.props)
1130
- }), E = () => {
1131
+ props: e.preview ?? at(e.props)
1132
+ }), ne = () => {
1131
1133
  let t = /* @__PURE__ */ new Map();
1132
1134
  for (let n of e.templates ?? []) t.set(n.locale ? `${n.name}:${n.locale}` : n.name, T(n));
1133
- for (let e of se()) {
1135
+ for (let e of ce()) {
1134
1136
  let n = j(e.name, e.locale);
1135
1137
  n && t.set(e.locale ? `${e.name}:${e.locale}` : e.name, T(n));
1136
1138
  }
1137
1139
  return [...t.values()];
1138
- }, D = e.webhook === void 0 ? [] : [ot(s, p, e.webhook, f)], O = [
1140
+ }, D = e.webhook === void 0 ? [] : [st(s, p, e.webhook, f)], re = [
1139
1141
  {
1140
1142
  method: "GET",
1141
1143
  path: "/outbox",
@@ -1143,7 +1145,7 @@ var C = class extends s.TaggedError()("MailError", {
1143
1145
  description: "Recent sent mail (dev capture buffer), newest first",
1144
1146
  handler: () => n.succeed({
1145
1147
  kind: "json",
1146
- data: { sends: v.list() }
1148
+ data: { sends: _.list() }
1147
1149
  })
1148
1150
  },
1149
1151
  {
@@ -1153,7 +1155,7 @@ var C = class extends s.TaggedError()("MailError", {
1153
1155
  description: "Discovered + registered email templates",
1154
1156
  handler: () => n.succeed({
1155
1157
  kind: "json",
1156
- data: { templates: E() }
1158
+ data: { templates: ne() }
1157
1159
  })
1158
1160
  },
1159
1161
  {
@@ -1191,28 +1193,29 @@ var C = class extends s.TaggedError()("MailError", {
1191
1193
  };
1192
1194
  })
1193
1195
  }
1196
+ ], O = [
1197
+ "network:outbound:*",
1198
+ "inspect:read",
1199
+ "inspect:write",
1200
+ ...g.length > 0 ? ["store:write"] : []
1194
1201
  ];
1195
1202
  return {
1196
1203
  ...c({
1197
1204
  name: l({
1198
- base: at,
1205
+ base: ot,
1199
1206
  alias: e.alias,
1200
1207
  instance: e.name
1201
1208
  }),
1202
- baseName: at,
1209
+ baseName: ot,
1203
1210
  description: "Transactional and broadcast email — MailService over Lettermint / Resend / Postmark / SendGrid / SES / Mailgun / SMTP (+ console/memory), with default-from, transient retry, suppression and a dev allowlist.",
1204
- permissions: [
1205
- "network:outbound:*",
1206
- "inspect:read",
1207
- "inspect:write"
1208
- ],
1211
+ permissions: O,
1209
1212
  declaredEnv: Q.declared,
1210
- egress: rt({
1213
+ egress: it({
1211
1214
  ...e.provider === void 0 ? {} : { provider: e.provider },
1212
1215
  env: a
1213
1216
  }),
1214
1217
  services: b,
1215
- inspectEndpoints: O,
1218
+ inspectEndpoints: re,
1216
1219
  ...D.length > 0 ? { httpRoutes: D } : {},
1217
1220
  ...g.length > 0 ? { extendSchema: { tables: g } } : {},
1218
1221
  bindDataStore: async (e) => {
@@ -1241,4 +1244,4 @@ var C = class extends s.TaggedError()("MailError", {
1241
1244
  };
1242
1245
  };
1243
1246
  //#endregion
1244
- export { C as MailError, ne as MailService, w as MailWebhookError, Ke as buildMailService, J as buildMailServiceWithScheduler, ce as clearGlobalTemplates, Ue as clearMailBuffer, Ve as consoleProvider, et as createOutbox, T as defineEmail, oe as globalTemplateCount, $e as handleMailEvents, ye as heldId, le as isEmailTemplate, Ee as lettermintProvider, se as listGlobalTemplates, j as lookupGlobalTemplate, rt as mailEgressOf, st as mailPlugin, qe as mailServiceLayer, Be as mailgunProvider, be as makeScheduler, B as memoryIdempotencyStore, We as memoryProvider, V as memoryScheduleStore, R as memorySuppressionStore, X as parseMailEvent, ge as postgresIdempotencyStore, me as postgresSuppressionStore, ke as postmarkProvider, He as readMailBuffer, ae as registerEmailTemplates, k as renderTemplate, Oe as resendProvider, Ge as resolveProvider, Ne as sendgridProvider, Re as sesProvider, G as smtpProvider, Te as verifyLettermintSignature };
1247
+ export { w as MailError, E as MailService, T as MailWebhookError, qe as buildMailService, J as buildMailServiceWithScheduler, le as clearGlobalTemplates, We as clearMailBuffer, He as consoleProvider, tt as createOutbox, ne as defineEmail, se as globalTemplateCount, et as handleMailEvents, be as heldId, ue as isEmailTemplate, De as lettermintProvider, ce as listGlobalTemplates, j as lookupGlobalTemplate, it as mailEgressOf, ct as mailPlugin, Je as mailServiceLayer, Ve as mailgunProvider, xe as makeScheduler, B as memoryIdempotencyStore, Ge as memoryProvider, V as memoryScheduleStore, R as memorySuppressionStore, X as parseMailEvent, _e as postgresIdempotencyStore, he as postgresSuppressionStore, Ae as postmarkProvider, Ue as readMailBuffer, oe as registerEmailTemplates, k as renderTemplate, ke as resendProvider, Ke as resolveProvider, Pe as sendgridProvider, ze as sesProvider, G as smtpProvider, Ee as verifyLettermintSignature };