@lunora/mail 1.0.0-alpha.50 → 1.0.0-alpha.51

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.
@@ -1 +1 @@
1
- import{createInboundEmailHandler as r,dispatchToLunoraFunction as a}from"../packem_shared/createInboundEmailHandler-D2i0mEBB.mjs";import{parseInboundEmail as t}from"../packem_shared/parseInboundEmail-Cxe54g-h.mjs";export{r as createInboundEmailHandler,a as dispatchToLunoraFunction,t as parseInboundEmail};
1
+ import{createInboundEmailHandler as r,dispatchToLunoraFunction as a}from"../packem_shared/createInboundEmailHandler-D2i0mEBB.mjs";import{parseInboundEmail as t}from"../packem_shared/parseInboundEmail-CqU52y3O.mjs";export{r as createInboundEmailHandler,a as dispatchToLunoraFunction,t as parseInboundEmail};
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { M as MailTransport, L as LunoraMailOptions, a as Mailer, b as MailboxSink, S as SendOptions } from "./packem_shared/capture-transport.d-_rIl9W6N.mjs";
2
- export { type C as CapturedMail, type Q as QueueLike, type c as SendPayload, d as createCaptureTransport } from "./packem_shared/capture-transport.d-_rIl9W6N.mjs";
1
+ import { M as MailTransport, L as LunoraMailOptions, a as Mailer, b as MailboxSink, S as SendOptions } from "./packem_shared/capture-transport.d-8CDAv51Z.mjs";
2
+ export { type C as CapturedMail, type Q as QueueLike, type c as SendPayload, d as createCaptureTransport } from "./packem_shared/capture-transport.d-8CDAv51Z.mjs";
3
3
  import { D as DurableObjectJurisdiction } from "./packem_shared/shard.d-DVADjmEJ.mjs";
4
4
  import { ReactElement } from 'react';
5
5
  /**
@@ -100,6 +100,12 @@ interface QueuedSend {
100
100
  from?: string;
101
101
  headers?: Record<string, string>;
102
102
  html?: string;
103
+ /**
104
+ * Stable dedup key, minted at enqueue time by `createMailer(...).queue()` — see
105
+ * `SendOptions.idempotencyKey`. Carried through untouched by `consumeQueuedSend`;
106
+ * a consumer wanting exactly-once delivery dedupes against its own store using it.
107
+ */
108
+ idempotencyKey?: string;
103
109
  replyTo?: string;
104
110
  subject: string;
105
111
  text?: string;
@@ -122,6 +128,7 @@ declare const toQueuedPayload: (options: SendOptions) => QueuedSend;
122
128
  * const mailer = createMailer({ apiKey: env.RESEND_API_KEY, from: "..." });
123
129
  * for (const message of batch.messages) {
124
130
  * await consumeQueuedSend(mailer, message.body);
131
+ * message.ack();
125
132
  * }
126
133
  * },
127
134
  * };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { M as MailTransport, L as LunoraMailOptions, a as Mailer, b as MailboxSink, S as SendOptions } from "./packem_shared/capture-transport.d-_rIl9W6N.js";
2
- export { type C as CapturedMail, type Q as QueueLike, type c as SendPayload, d as createCaptureTransport } from "./packem_shared/capture-transport.d-_rIl9W6N.js";
1
+ import { M as MailTransport, L as LunoraMailOptions, a as Mailer, b as MailboxSink, S as SendOptions } from "./packem_shared/capture-transport.d-8CDAv51Z.js";
2
+ export { type C as CapturedMail, type Q as QueueLike, type c as SendPayload, d as createCaptureTransport } from "./packem_shared/capture-transport.d-8CDAv51Z.js";
3
3
  import { D as DurableObjectJurisdiction } from "./packem_shared/shard.d-DVADjmEJ.js";
4
4
  import { ReactElement } from 'react';
5
5
  /**
@@ -100,6 +100,12 @@ interface QueuedSend {
100
100
  from?: string;
101
101
  headers?: Record<string, string>;
102
102
  html?: string;
103
+ /**
104
+ * Stable dedup key, minted at enqueue time by `createMailer(...).queue()` — see
105
+ * `SendOptions.idempotencyKey`. Carried through untouched by `consumeQueuedSend`;
106
+ * a consumer wanting exactly-once delivery dedupes against its own store using it.
107
+ */
108
+ idempotencyKey?: string;
103
109
  replyTo?: string;
104
110
  subject: string;
105
111
  text?: string;
@@ -122,6 +128,7 @@ declare const toQueuedPayload: (options: SendOptions) => QueuedSend;
122
128
  * const mailer = createMailer({ apiKey: env.RESEND_API_KEY, from: "..." });
123
129
  * for (const message of batch.messages) {
124
130
  * await consumeQueuedSend(mailer, message.body);
131
+ * message.ack();
125
132
  * }
126
133
  * },
127
134
  * };
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{createCaptureTransport as a}from"./packem_shared/createCaptureTransport-CKc6NpZR.mjs";import{createCloudflareTransport as t}from"./packem_shared/createCloudflareTransport-E-UdW8Dc.mjs";import{default as u}from"./packem_shared/createMailer-LHgKs5yh.mjs";import{createCaptureSink as f,createMailerFromEnv as l,shouldCaptureMail as m}from"./packem_shared/createCaptureSink-CE24od5h.mjs";import{consumeQueuedSend as s,toQueuedPayload as c}from"./packem_shared/consumeQueuedSend-8TXPj5o-.mjs";import{default as i}from"./packem_shared/renderEmail-BOUnr6i3.mjs";import{default as M}from"./packem_shared/createResendTransport-CG9s8iI9.mjs";export{s as consumeQueuedSend,f as createCaptureSink,a as createCaptureTransport,t as createCloudflareTransport,u as createMailer,l as createMailerFromEnv,M as createResendTransport,i as renderEmail,m as shouldCaptureMail,c as toQueuedPayload};
1
+ import{createCaptureTransport as a}from"./packem_shared/createCaptureTransport-CKc6NpZR.mjs";import{createCloudflareTransport as t}from"./packem_shared/createCloudflareTransport-DpfCxn16.mjs";import{default as u}from"./packem_shared/createMailer-BJs2hnV-.mjs";import{createCaptureSink as f,createMailerFromEnv as l,shouldCaptureMail as m}from"./packem_shared/createCaptureSink-4T2LJOYC.mjs";import{consumeQueuedSend as s,toQueuedPayload as c}from"./packem_shared/consumeQueuedSend-CRfALnCU.mjs";import{default as i}from"./packem_shared/renderEmail-BOUnr6i3.mjs";import{default as M}from"./packem_shared/createResendTransport-DDkOitck.mjs";export{s as consumeQueuedSend,f as createCaptureSink,a as createCaptureTransport,t as createCloudflareTransport,u as createMailer,l as createMailerFromEnv,M as createResendTransport,i as renderEmail,m as shouldCaptureMail,c as toQueuedPayload};
@@ -1,3 +1,3 @@
1
1
  import{LunoraError as t}from"@lunora/errors";const n=320,a=256,d=/^([^<]*)<([^>]*)>\s*$/,i=(r,s)=>{if(s.includes("\r")||s.includes(`
2
2
  `)||s.includes(","))throw new t("INTERNAL",`@lunora/mail: address ${r} must not contain CR, LF, or comma`)},f=(r,s)=>{if(s.includes("\r")||s.includes(`
3
- `))throw new t("INTERNAL",`@lunora/mail: ${r} must not contain CR or LF`)},m=(r,s)=>{if(r.length>a)throw new t("INTERNAL",`@lunora/mail: address name must be <= ${String(a)} characters`);if(s.length>n)throw new t("INTERNAL",`@lunora/mail: address email must be <= ${String(n)} characters`);return r&&i("name",r),i("email",s),r?{email:s,name:r}:{email:s}},A=r=>{const s=r.trim();if(s.length>n)throw new t("INTERNAL",`@lunora/mail: address email must be <= ${String(n)} characters`);return i("email",s),{email:s}},c=r=>{const s=d.exec(r),e=(s?.[2]??"").trim();return s&&e?m((s[1]??"").trim(),e):A(r)},o=r=>r===void 0?void 0:(Array.isArray(r)?r:[r]).map(e=>c(e)),u=r=>{o(r.to),o(r.cc),o(r.bcc),r.from!==void 0&&c(r.from),r.replyTo!==void 0&&c(r.replyTo)};export{f as a,u as b,c,o as t};
3
+ `))throw new t("INTERNAL",`@lunora/mail: ${r} must not contain CR or LF`)},m=(r,s)=>{if(r.length>a)throw new t("INTERNAL",`@lunora/mail: address name must be <= ${String(a)} characters`);if(s.length>n)throw new t("INTERNAL",`@lunora/mail: address email must be <= ${String(n)} characters`);return r&&i("name",r),i("email",s),r?{email:s,name:r}:{email:s}},A=r=>{const s=r.trim();if(s.length>n)throw new t("INTERNAL",`@lunora/mail: address email must be <= ${String(n)} characters`);return i("email",s),{email:s}},c=r=>{const s=d.exec(r),e=(s?.[2]??"").trim();return s&&e?m((s[1]??"").trim(),e):A(r)},o=r=>r===void 0?void 0:(Array.isArray(r)?r:[r]).map(e=>c(e)),u=r=>{o(r.to),o(r.cc),o(r.bcc),r.from!==void 0&&c(r.from),r.replyTo!==void 0&&c(r.replyTo)};export{f as a,c as b,u as c,o as t};
@@ -34,6 +34,15 @@ interface SendOptions {
34
34
  from?: string;
35
35
  headers?: Record<string, string>;
36
36
  html?: string;
37
+ /**
38
+ * Stable key for deduping a queued send across Cloudflare Queues' at-least-once
39
+ * redelivery. Only meaningful for `mailer.queue()` — `mailer.send()` ignores it.
40
+ * When omitted, `queue()` generates one at enqueue time so it survives redelivery
41
+ * (a key minted in the consumer would change on every retry, defeating the point).
42
+ * Not forwarded to the mail provider — a consumer wanting exactly-once delivery
43
+ * must dedupe against its own store using this key.
44
+ */
45
+ idempotencyKey?: string;
37
46
  react?: ReactElement;
38
47
  replyTo?: string;
39
48
  subject: string;
@@ -34,6 +34,15 @@ interface SendOptions {
34
34
  from?: string;
35
35
  headers?: Record<string, string>;
36
36
  html?: string;
37
+ /**
38
+ * Stable key for deduping a queued send across Cloudflare Queues' at-least-once
39
+ * redelivery. Only meaningful for `mailer.queue()` — `mailer.send()` ignores it.
40
+ * When omitted, `queue()` generates one at enqueue time so it survives redelivery
41
+ * (a key minted in the consumer would change on every retry, defeating the point).
42
+ * Not forwarded to the mail provider — a consumer wanting exactly-once delivery
43
+ * must dedupe against its own store using this key.
44
+ */
45
+ idempotencyKey?: string;
37
46
  react?: ReactElement;
38
47
  replyTo?: string;
39
48
  subject: string;
@@ -0,0 +1 @@
1
+ import{LunoraError as c}from"@lunora/errors";const d=n=>{const t={...n};return delete t.react,t},p=async(n,t)=>{if(!t||typeof t!="object"||Array.isArray(t))throw new c("INTERNAL","@lunora/mail: queue message body must be an object");const e=t;if(typeof e.subject!="string")throw new TypeError("@lunora/mail: queue message must have a string `subject`");const y=typeof e.to=="string",m=Array.isArray(e.to)&&e.to.every(o=>typeof o=="string");if(!y&&!m)throw new c("INTERNAL","@lunora/mail: queue message `to` must be a string or string[]");const s=(o,r)=>{if(r!==void 0){if(typeof r!="string")throw new TypeError(`@lunora/mail: queue message \`${o}\` must be a string`);return r}},a=(o,r)=>{if(r!==void 0){if(typeof r=="string")return[r];if(Array.isArray(r)&&r.every(i=>typeof i=="string"))return r;throw new TypeError(`@lunora/mail: queue message \`${o}\` must be a string or string[]`)}};let u;if(e.headers!==void 0){if(!e.headers||typeof e.headers!="object"||Array.isArray(e.headers))throw new TypeError("@lunora/mail: queue message `headers` must be an object of string values");const o=Object.entries(e.headers);for(const[r,i]of o)if(typeof i!="string")throw new TypeError(`@lunora/mail: queue message header "${r}" must be a string`);u=e.headers}const f={bcc:a("bcc",e.bcc),cc:a("cc",e.cc),from:s("from",e.from),headers:u,html:s("html",e.html),idempotencyKey:s("idempotencyKey",e.idempotencyKey),replyTo:s("replyTo",e.replyTo),subject:e.subject,text:s("text",e.text),to:e.to};return n.send(f)};export{p as consumeQueuedSend,d as toQueuedPayload};
@@ -1 +1 @@
1
- import{createCaptureTransport as d}from"./createCaptureTransport-CKc6NpZR.mjs";import"./createCloudflareTransport-E-UdW8Dc.mjs";import n from"./createMailer-LHgKs5yh.mjs";import{LunoraError as c}from"@lunora/errors";import{D as s,p as l}from"./shard-C0aRRoVy.mjs";import"./consumeQueuedSend-8TXPj5o-.mjs";import"./renderEmail-BOUnr6i3.mjs";import"./createResendTransport-CG9s8iI9.mjs";const E="__lunora_admin__:recordMail",p=/^(?:dev(?:elopment)?|local(?:host)?|test)$/iu,f=["CF_ENV","ENVIRONMENT","NODE_ENV","WORKER_ENV"],_=(t,e)=>{const r=t[e];if(typeof r!="string"||r==="")throw new c("INTERNAL",`@lunora/mail: missing env var \`${e}\` — set it in .dev.vars (and \`wrangler secret put ${e}\` for secrets).`);return r},N=t=>{const e=t.LUNORA_MAIL_CAPTURE;if(typeof e=="string"){const r=e.toLowerCase();if(r==="1"||r==="true")return!0;if(r==="0"||r==="false")return!1;console.warn(`@lunora/mail: unrecognized LUNORA_MAIL_CAPTURE value "${e}" — expected "1"/"true" or "0"/"false"; falling back to environment detection.`)}return f.some(r=>{const o=t[r];return typeof o=="string"&&p.test(o)})},m=(t,e=s,r)=>({record:async o=>{const i=t.SHARD,a=typeof t.LUNORA_ADMIN_TOKEN=="string"?t.LUNORA_ADMIN_TOKEN:void 0;if(i===void 0||a===void 0)return{id:"uncaptured"};try{return{id:(await l(i,{adminToken:a,envelope:{args:o,functionPath:E},jurisdiction:r,label:"@lunora/mail: recording captured mail",shardKey:e})).result?.id??"captured"}}catch(u){return console.error("@lunora/mail: failed to record captured mail into the studio inbox —",u),{id:"uncaptured"}}}}),L=(t,e={})=>{const r=_(t,"MAIL_FROM");if(N(t))return n({from:r,transport:d(m(t,e.rootShard,e.jurisdiction))});if(e.cloudflareSend)return n({cloudflareSend:e.cloudflareSend,from:r});const o=typeof t.RESEND_API_KEY=="string"?t.RESEND_API_KEY:void 0;if(o!==void 0&&o!=="")return n({apiKey:o,from:r});throw new c("INTERNAL","@lunora/mail: no transport configured — provide `cloudflareSend` (a SEND_EMAIL binding) or RESEND_API_KEY, or run in a dev environment to capture.")};export{m as createCaptureSink,L as createMailerFromEnv,N as shouldCaptureMail};
1
+ import{createCaptureTransport as d}from"./createCaptureTransport-CKc6NpZR.mjs";import"./createCloudflareTransport-DpfCxn16.mjs";import n from"./createMailer-BJs2hnV-.mjs";import{LunoraError as c}from"@lunora/errors";import{D as s,p as l}from"./shard-C0aRRoVy.mjs";import"./consumeQueuedSend-CRfALnCU.mjs";import"./renderEmail-BOUnr6i3.mjs";import"./createResendTransport-DDkOitck.mjs";const E="__lunora_admin__:recordMail",p=/^(?:dev(?:elopment)?|local(?:host)?|test)$/iu,f=["CF_ENV","ENVIRONMENT","NODE_ENV","WORKER_ENV"],_=(t,e)=>{const r=t[e];if(typeof r!="string"||r==="")throw new c("INTERNAL",`@lunora/mail: missing env var \`${e}\` — set it in .dev.vars (and \`wrangler secret put ${e}\` for secrets).`);return r},N=t=>{const e=t.LUNORA_MAIL_CAPTURE;if(typeof e=="string"){const r=e.toLowerCase();if(r==="1"||r==="true")return!0;if(r==="0"||r==="false")return!1;console.warn(`@lunora/mail: unrecognized LUNORA_MAIL_CAPTURE value "${e}" — expected "1"/"true" or "0"/"false"; falling back to environment detection.`)}return f.some(r=>{const o=t[r];return typeof o=="string"&&p.test(o)})},m=(t,e=s,r)=>({record:async o=>{const i=t.SHARD,a=typeof t.LUNORA_ADMIN_TOKEN=="string"?t.LUNORA_ADMIN_TOKEN:void 0;if(i===void 0||a===void 0)return{id:"uncaptured"};try{return{id:(await l(i,{adminToken:a,envelope:{args:o,functionPath:E},jurisdiction:r,label:"@lunora/mail: recording captured mail",shardKey:e})).result?.id??"captured"}}catch(u){return console.error("@lunora/mail: failed to record captured mail into the studio inbox —",u),{id:"uncaptured"}}}}),L=(t,e={})=>{const r=_(t,"MAIL_FROM");if(N(t))return n({from:r,transport:d(m(t,e.rootShard,e.jurisdiction))});if(e.cloudflareSend)return n({cloudflareSend:e.cloudflareSend,from:r});const o=typeof t.RESEND_API_KEY=="string"?t.RESEND_API_KEY:void 0;if(o!==void 0&&o!=="")return n({apiKey:o,from:r});throw new c("INTERNAL","@lunora/mail: no transport configured — provide `cloudflareSend` (a SEND_EMAIL binding) or RESEND_API_KEY, or run in a dev environment to capture.")};export{m as createCaptureSink,L as createMailerFromEnv,N as shouldCaptureMail};
@@ -1 +1 @@
1
- import{LunoraError as n}from"@lunora/errors";import{cloudflareEmailProvider as l}from"@visulima/email/providers/cloudflare-email";import{r as d,t as u,i as m}from"./provider-transport-DXmTG_xv.mjs";const E=r=>{const t=l({send:r.send});return{send:async e=>{await t.initialize();const o=e.cc!==void 0&&e.cc.length>0,s=e.bcc!==void 0&&e.bcc.length>0;if(o||s)throw new n("INTERNAL","@lunora/mail: Cloudflare Email Workers does not support cc/bcc — fan out one send per recipient instead");const{first:c,list:i}=d(e.to);if(i.length>1)throw new n("INTERNAL",`@lunora/mail: Cloudflare Email Workers is single-recipient but received ${String(i.length)} \`to\` addresses — fan out one send per recipient instead`);const a=await t.sendEmail(u(e,r.from,c));return m(a)}}};export{E as createCloudflareTransport};
1
+ import{LunoraError as n}from"@lunora/errors";import{cloudflareEmailProvider as l}from"@visulima/email/providers/cloudflare-email";import{r as d,t as u,i as m}from"./provider-transport-CR4w-R0A.mjs";const E=r=>{const t=l({send:r.send});return{send:async e=>{await t.initialize();const o=e.cc!==void 0&&e.cc.length>0,s=e.bcc!==void 0&&e.bcc.length>0;if(o||s)throw new n("INTERNAL","@lunora/mail: Cloudflare Email Workers does not support cc/bcc — fan out one send per recipient instead");const{first:c,list:i}=d(e.to);if(i.length>1)throw new n("INTERNAL",`@lunora/mail: Cloudflare Email Workers is single-recipient but received ${String(i.length)} \`to\` addresses — fan out one send per recipient instead`);const a=await t.sendEmail(u(e,r.from,c));return m(a)}}};export{E as createCloudflareTransport};
@@ -0,0 +1 @@
1
+ import{LunoraError as l}from"@lunora/errors";import{a as f,c as m}from"./address-soPj2Z0j.mjs";import{isCaptureTransport as s}from"./createCaptureTransport-CKc6NpZR.mjs";import{createCloudflareTransport as y}from"./createCloudflareTransport-DpfCxn16.mjs";import{toQueuedPayload as i}from"./consumeQueuedSend-CRfALnCU.mjs";import w from"./renderEmail-BOUnr6i3.mjs";import b from"./createResendTransport-DDkOitck.mjs";const h=()=>{if(typeof crypto<"u"){if(typeof crypto.randomUUID=="function")return crypto.randomUUID();if(typeof crypto.getRandomValues=="function"){const r=crypto.getRandomValues(new Uint8Array(16));return Array.from(r,u=>u.toString(16).padStart(2,"0")).join("")}}return Date.now().toString(36)},q=r=>{if(r.cloudflareSend)return y({from:r.from,send:r.cloudflareSend});if(r.apiKey)return b(r.apiKey,r.from);throw new l("INTERNAL","@lunora/mail: a transport is required — pass `transport`, `cloudflareSend` (Cloudflare Email Workers, the default), or `apiKey` (Resend)")},g=r=>{if(!r.from)throw new l("INTERNAL","@lunora/mail: `from` is required");const u=r.transport??q(r),n=async e=>{let{html:a}=e,{text:c}=e;if(e.react){const t=await w(e.react);a=a??t.html,c=c??t.text}if(f("subject",e.subject),e.headers)for(const[t,o]of Object.entries(e.headers))f(`header name "${t}"`,t),f(`header "${t}" value`,o);const d=e.from??r.from;return m({bcc:e.bcc,cc:e.cc,from:d,replyTo:e.replyTo,to:e.to}),{bcc:e.bcc,cc:e.cc,from:d,headers:e.headers,html:a,replyTo:e.replyTo,subject:e.subject,text:c,to:e.to}};return{queue:async e=>{if(!r.queue){if(s(u)){const d=await n(e);return await u.send(d),{queued:!0}}throw new l("INTERNAL","@lunora/mail: `queue` binding is required for mailer.queue()")}const a=await n(e),c=e.idempotencyKey??h();return await r.queue.send(i({...a,idempotencyKey:c})),{queued:!0}},send:async e=>{const a=await n(e);return u.send(a)}}};export{g as default};
@@ -1 +1 @@
1
- import{resendProvider as a}from"@visulima/email/providers/resend";import{r as d,t as c,i as l}from"./provider-transport-DXmTG_xv.mjs";const u=(i,s)=>{const e=a({apiKey:i});return{send:async r=>{await e.initialize();const{first:n,list:t}=d(r.to),o=await e.sendEmail(c(r,s,t.length===1?n:t));return l(o)}}};export{u as default};
1
+ import{resendProvider as a}from"@visulima/email/providers/resend";import{r as d,t as c,i as l}from"./provider-transport-CR4w-R0A.mjs";const u=(i,s)=>{const e=a({apiKey:i});return{send:async r=>{await e.initialize();const{first:n,list:t}=d(r.to),o=await e.sendEmail(c(r,s,t.length===1?n:t));return l(o)}}};export{u as default};
@@ -1 +1 @@
1
- import u from"postal-mime";import{a as r}from"./address-BQ5RUGdT.mjs";const s=(o,e)=>{if(e!==void 0)return r(`inbound ${o}`,e),e},m=o=>o.address!==void 0&&o.address!==""?o.name?`${o.name} <${o.address}>`:o.address:o.group?o.group.map(e=>e.address??"").filter(e=>e!=="").join(", "):o.name??"",t=(o,e)=>new RegExp(String.raw`\b${e}=([a-zA-Z]+)`,"i").exec(o)?.[1]?.toLowerCase()??null,p=o=>o===void 0||o===""?{dkim:null,dmarc:null,spf:null}:{dkim:t(o,"dkim"),dmarc:t(o,"dmarc"),spf:t(o,"spf")},b=async o=>{const e=await u.parse(o),i={};for(const n of e.headers)r(`inbound header \`${n.key}\``,n.value),i[n.key]=n.value;const c=e.headers.find(n=>n.key==="authentication-results")?.value,f=(e.to??[]).map(n=>{const a=m(n);return r("inbound to",a),a}),d=e.from?m(e.from):"";return r("inbound from",d),{attachments:e.attachments.map(n=>({content:n.content,disposition:n.disposition,...n.encoding===void 0?{}:{encoding:n.encoding},filename:n.filename,mimeType:n.mimeType})),authentication:p(c),from:d,headers:i,...e.html===void 0?{}:{html:e.html},...s("inReplyTo",e.inReplyTo)===void 0?{}:{inReplyTo:e.inReplyTo},...s("messageId",e.messageId)===void 0?{}:{messageId:e.messageId},...s("references",e.references)===void 0?{}:{references:e.references},...s("subject",e.subject)===void 0?{}:{subject:e.subject},...e.text===void 0?{}:{text:e.text},to:f}};export{b as parseInboundEmail};
1
+ import u from"postal-mime";import{a as r}from"./address-soPj2Z0j.mjs";const s=(o,e)=>{if(e!==void 0)return r(`inbound ${o}`,e),e},m=o=>o.address!==void 0&&o.address!==""?o.name?`${o.name} <${o.address}>`:o.address:o.group?o.group.map(e=>e.address??"").filter(e=>e!=="").join(", "):o.name??"",t=(o,e)=>new RegExp(String.raw`\b${e}=([a-zA-Z]+)`,"i").exec(o)?.[1]?.toLowerCase()??null,p=o=>o===void 0||o===""?{dkim:null,dmarc:null,spf:null}:{dkim:t(o,"dkim"),dmarc:t(o,"dmarc"),spf:t(o,"spf")},b=async o=>{const e=await u.parse(o),i={};for(const n of e.headers)r(`inbound header \`${n.key}\``,n.value),i[n.key]=n.value;const c=e.headers.find(n=>n.key==="authentication-results")?.value,f=(e.to??[]).map(n=>{const a=m(n);return r("inbound to",a),a}),d=e.from?m(e.from):"";return r("inbound from",d),{attachments:e.attachments.map(n=>({content:n.content,disposition:n.disposition,...n.encoding===void 0?{}:{encoding:n.encoding},filename:n.filename,mimeType:n.mimeType})),authentication:p(c),from:d,headers:i,...e.html===void 0?{}:{html:e.html},...s("inReplyTo",e.inReplyTo)===void 0?{}:{inReplyTo:e.inReplyTo},...s("messageId",e.messageId)===void 0?{}:{messageId:e.messageId},...s("references",e.references)===void 0?{}:{references:e.references},...s("subject",e.subject)===void 0?{}:{subject:e.subject},...e.text===void 0?{}:{text:e.text},to:f}};export{b as parseInboundEmail};
@@ -1 +1 @@
1
- import{LunoraError as o}from"@lunora/errors";import{t as n,c as s}from"./address-BQ5RUGdT.mjs";const c=e=>e instanceof Error?e.message:e==null?"send failed":typeof e=="string"?e:typeof e=="number"||typeof e=="boolean"||typeof e=="bigint"?e.toString():JSON.stringify(e)??"send failed",u=e=>{const t=n(e),[i]=t??[];if(!t||i===void 0)throw new o("INTERNAL","@lunora/mail: at least one recipient is required");return{first:i,list:t}},d=(e,t,i)=>({bcc:n(e.bcc),cc:n(e.cc),from:s(e.from??t),headers:e.headers,html:e.html,replyTo:e.replyTo?s(e.replyTo):void 0,subject:e.subject,text:e.text,to:i}),m=e=>{if(!e.success||!e.data)throw console.error(`@lunora/mail: send failed: ${c(e.error)}`),new o("INTERNAL","@lunora/mail: send failed");return{id:e.data.messageId}};export{m as i,u as r,d as t};
1
+ import{LunoraError as o}from"@lunora/errors";import{t as n,b as s}from"./address-soPj2Z0j.mjs";const c=e=>e instanceof Error?e.message:e==null?"send failed":typeof e=="string"?e:typeof e=="number"||typeof e=="boolean"||typeof e=="bigint"?e.toString():JSON.stringify(e)??"send failed",u=e=>{const t=n(e),[i]=t??[];if(!t||i===void 0)throw new o("INTERNAL","@lunora/mail: at least one recipient is required");return{first:i,list:t}},d=(e,t,i)=>({bcc:n(e.bcc),cc:n(e.cc),from:s(e.from??t),headers:e.headers,html:e.html,replyTo:e.replyTo?s(e.replyTo):void 0,subject:e.subject,text:e.text,to:i}),m=e=>{if(!e.success||!e.data)throw console.error(`@lunora/mail: send failed: ${c(e.error)}`),new o("INTERNAL","@lunora/mail: send failed");return{id:e.data.messageId}};export{m as i,u as r,d as t};
@@ -1,4 +1,4 @@
1
- import { C as CapturedMail } from "./packem_shared/capture-transport.d-_rIl9W6N.mjs";
1
+ import { C as CapturedMail } from "./packem_shared/capture-transport.d-8CDAv51Z.mjs";
2
2
  import 'react';
3
3
  /** Minimal `fetch` projection so a test can inject a stub. */
4
4
  type FetchLike = (input: string, init?: {
package/dist/testing.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { C as CapturedMail } from "./packem_shared/capture-transport.d-_rIl9W6N.js";
1
+ import { C as CapturedMail } from "./packem_shared/capture-transport.d-8CDAv51Z.js";
2
2
  import 'react';
3
3
  /** Minimal `fetch` projection so a test can inject a stub. */
4
4
  type FetchLike = (input: string, init?: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/mail",
3
- "version": "1.0.0-alpha.50",
3
+ "version": "1.0.0-alpha.51",
4
4
  "description": "Email for Lunora: Resend adapter, TSX templates, and queue-backed sends",
5
5
  "keywords": [
6
6
  "cloudflare",
@@ -1 +0,0 @@
1
- import{LunoraError as c}from"@lunora/errors";const d=n=>{const t={...n};return delete t.react,t},p=async(n,t)=>{if(!t||typeof t!="object"||Array.isArray(t))throw new c("INTERNAL","@lunora/mail: queue message body must be an object");const e=t;if(typeof e.subject!="string")throw new TypeError("@lunora/mail: queue message must have a string `subject`");const m=typeof e.to=="string",y=Array.isArray(e.to)&&e.to.every(s=>typeof s=="string");if(!m&&!y)throw new c("INTERNAL","@lunora/mail: queue message `to` must be a string or string[]");const o=(s,r)=>{if(r!==void 0){if(typeof r!="string")throw new TypeError(`@lunora/mail: queue message \`${s}\` must be a string`);return r}},a=(s,r)=>{if(r!==void 0){if(typeof r=="string")return[r];if(Array.isArray(r)&&r.every(i=>typeof i=="string"))return r;throw new TypeError(`@lunora/mail: queue message \`${s}\` must be a string or string[]`)}};let u;if(e.headers!==void 0){if(!e.headers||typeof e.headers!="object"||Array.isArray(e.headers))throw new TypeError("@lunora/mail: queue message `headers` must be an object of string values");const s=Object.entries(e.headers);for(const[r,i]of s)if(typeof i!="string")throw new TypeError(`@lunora/mail: queue message header "${r}" must be a string`);u=e.headers}const f={bcc:a("bcc",e.bcc),cc:a("cc",e.cc),from:o("from",e.from),headers:u,html:o("html",e.html),replyTo:o("replyTo",e.replyTo),subject:e.subject,text:o("text",e.text),to:e.to};return n.send(f)};export{p as consumeQueuedSend,d as toQueuedPayload};
@@ -1 +0,0 @@
1
- import{LunoraError as f}from"@lunora/errors";import{a as l,b as n}from"./address-BQ5RUGdT.mjs";import{isCaptureTransport as o}from"./createCaptureTransport-CKc6NpZR.mjs";import{createCloudflareTransport as i}from"./createCloudflareTransport-E-UdW8Dc.mjs";import{toQueuedPayload as y}from"./consumeQueuedSend-8TXPj5o-.mjs";import b from"./renderEmail-BOUnr6i3.mjs";import h from"./createResendTransport-CG9s8iI9.mjs";const w=r=>{if(r.cloudflareSend)return i({from:r.from,send:r.cloudflareSend});if(r.apiKey)return h(r.apiKey,r.from);throw new f("INTERNAL","@lunora/mail: a transport is required — pass `transport`, `cloudflareSend` (Cloudflare Email Workers, the default), or `apiKey` (Resend)")},x=r=>{if(!r.from)throw new f("INTERNAL","@lunora/mail: `from` is required");const c=r.transport??w(r),d=async e=>{let{html:a}=e,{text:u}=e;if(e.react){const t=await b(e.react);a=a??t.html,u=u??t.text}if(l("subject",e.subject),e.headers)for(const[t,s]of Object.entries(e.headers))l(`header name "${t}"`,t),l(`header "${t}" value`,s);const m=e.from??r.from;return n({bcc:e.bcc,cc:e.cc,from:m,replyTo:e.replyTo,to:e.to}),{bcc:e.bcc,cc:e.cc,from:m,headers:e.headers,html:a,replyTo:e.replyTo,subject:e.subject,text:u,to:e.to}};return{queue:async e=>{if(!r.queue){if(o(c)){const u=await d(e);return await c.send(u),{queued:!0}}throw new f("INTERNAL","@lunora/mail: `queue` binding is required for mailer.queue()")}const a=await d(e);return await r.queue.send(y(a)),{queued:!0}},send:async e=>{const a=await d(e);return c.send(a)}}};export{x as default};