@numoteq/emdash-plugin-jetemail 0.2.0 → 0.3.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/dist/client.d.mts CHANGED
@@ -4,6 +4,11 @@ interface JetEmailSender {
4
4
  fromName: string;
5
5
  fromEmail: string;
6
6
  }
7
+ interface JetEmailAttachment {
8
+ filename: string;
9
+ /** Raw bytes (Uint8Array or Node Buffer) or a base64 string. */
10
+ content: Uint8Array | string;
11
+ }
7
12
  interface JetEmailMessage {
8
13
  to: string | string[];
9
14
  cc?: string[];
@@ -11,6 +16,7 @@ interface JetEmailMessage {
11
16
  subject: string;
12
17
  text?: string;
13
18
  html?: string;
19
+ attachments?: JetEmailAttachment[];
14
20
  }
15
21
  type FetchFn = (url: string, init?: RequestInit) => Promise<Response>;
16
22
  declare function formatSender(name: string, email: string): string;
@@ -18,4 +24,4 @@ declare function deliverWithJetEmail(fetchFn: FetchFn, sender: JetEmailSender, m
18
24
  id?: string;
19
25
  }>;
20
26
  //#endregion
21
- export { FetchFn, JetEmailMessage, JetEmailSender, deliverWithJetEmail, formatSender };
27
+ export { FetchFn, JetEmailAttachment, JetEmailMessage, JetEmailSender, deliverWithJetEmail, formatSender };
package/dist/client.mjs CHANGED
@@ -3,6 +3,12 @@ const API_URL = "https://api.jetemail.com/email";
3
3
  function formatSender(name, email) {
4
4
  return `${name.replace(/[<>"\r\n]/g, "").trim()} <${email}>`;
5
5
  }
6
+ function toBase64(content) {
7
+ if (typeof content === "string") return content;
8
+ let binary = "";
9
+ for (let i = 0; i < content.length; i += 32768) binary += String.fromCharCode(...content.subarray(i, i + 32768));
10
+ return btoa(binary);
11
+ }
6
12
  async function deliverWithJetEmail(fetchFn, sender, message) {
7
13
  const body = {
8
14
  from: formatSender(sender.fromName, sender.fromEmail),
@@ -13,6 +19,10 @@ async function deliverWithJetEmail(fetchFn, sender, message) {
13
19
  if (message.html) body.html = message.html;
14
20
  if (message.cc?.length) body.cc = message.cc;
15
21
  if (message.replyTo) body.reply_to = message.replyTo;
22
+ if (message.attachments?.length) body.attachments = message.attachments.map((file) => ({
23
+ filename: file.filename,
24
+ data: toBase64(file.content)
25
+ }));
16
26
  const response = await fetchFn(API_URL, {
17
27
  method: "POST",
18
28
  headers: {
package/dist/index.mjs CHANGED
@@ -7,7 +7,7 @@
7
7
  /** @type {import("emdash").PluginDescriptor} */
8
8
  const descriptor = Object.freeze({
9
9
  "id": "jetemail",
10
- "version": "0.2.0",
10
+ "version": "0.3.0",
11
11
  "format": "standard",
12
12
  "entrypoint": "@numoteq/emdash-plugin-jetemail/sandbox",
13
13
  "capabilities": [
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "id": "jetemail",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "declaredAccess": {
5
5
  "network": {
6
6
  "request": {
package/dist/plugin.d.mts CHANGED
@@ -6,6 +6,11 @@ interface JetEmailSender {
6
6
  fromName: string;
7
7
  fromEmail: string;
8
8
  }
9
+ interface JetEmailAttachment {
10
+ filename: string;
11
+ /** Raw bytes (Uint8Array or Node Buffer) or a base64 string. */
12
+ content: Uint8Array | string;
13
+ }
9
14
  interface JetEmailMessage {
10
15
  to: string | string[];
11
16
  cc?: string[];
@@ -13,6 +18,7 @@ interface JetEmailMessage {
13
18
  subject: string;
14
19
  text?: string;
15
20
  html?: string;
21
+ attachments?: JetEmailAttachment[];
16
22
  }
17
23
  type FetchFn = (url: string, init?: RequestInit) => Promise<Response>;
18
24
  declare function formatSender(name: string, email: string): string;
package/dist/plugin.mjs CHANGED
@@ -1 +1 @@
1
- function e(e,t){return`${e.replace(/[<>"\r\n]/g,``).trim()} <${t}>`}async function t(t,n,r){let i={from:e(n.fromName,n.fromEmail),to:r.to,subject:r.subject};r.text&&(i.text=r.text),r.html&&(i.html=r.html),r.cc?.length&&(i.cc=r.cc),r.replyTo&&(i.reply_to=r.replyTo);let a=await t(`https://api.jetemail.com/email`,{method:`POST`,headers:{Authorization:`Bearer ${n.apiToken}`,"Content-Type":`application/json`},body:JSON.stringify(i)});if(!a.ok){let e=(await a.text()).slice(0,500);throw Error(`JetEmail rejected the message with HTTP ${a.status}${e?`: ${e}`:``}`)}let o=await a.json().catch(()=>({}));return typeof o.id==`string`?{id:o.id}:{}}async function n(e){let t=await e.kv.get(`settings:apiToken`),n=await e.kv.get(`settings:fromName`),r=await e.kv.get(`settings:fromEmail`);if(!t||!n||!r)throw Error(`JetEmail is not configured. Set the API key, sender name and sender email.`);return{apiToken:t,fromName:n,fromEmail:r}}async function r(e){let t=await e.kv.get(`settings:fromName`)??``,n=await e.kv.get(`settings:fromEmail`)??``,r=!!await e.kv.get(`settings:apiToken`);return{blocks:[{type:`header`,text:`JetEmail`},{type:`section`,text:`Deliver EmDash transactional email through the JetEmail API. The sender domain must be verified in JetEmail and allowed for the API key.`},{type:`form`,block_id:`jetemail-settings`,fields:[{type:`text_input`,action_id:`fromName`,label:`Sender name`,initial_value:t},{type:`text_input`,action_id:`fromEmail`,label:`Sender email`,initial_value:n},{type:`secret_input`,action_id:`apiToken`,label:r?`Transactional API key (leave blank to keep current)`:`Transactional API key`}],submit:{label:`Save settings`,action_id:`save_settings`}}]}}function i(e){return{blocks:[{type:`banner`,style:`error`,text:e}],toast:{message:e,type:`error`}}}async function a(e,t){let n=typeof t.fromName==`string`?t.fromName.trim():``,a=typeof t.fromEmail==`string`?t.fromEmail.trim():``,o=typeof t.apiToken==`string`?t.apiToken.trim():``;return n.replace(/[<>"\r\n]/g,``).trim()?/^[^\s@<>]+@[^\s@<>]+$/.test(a)?o&&!o.startsWith(`transactional_`)?i(`Use a JetEmail transactional API key (transactional_…).`):(await e.kv.set(`settings:fromName`,n),await e.kv.set(`settings:fromEmail`,a),o&&await e.kv.set(`settings:apiToken`,o),{...await r(e),toast:{message:`JetEmail settings saved`,type:`success`}}):i(`Enter a valid sender email.`):i(`Enter a sender name.`)}const o={hooks:{"email:deliver":{exclusive:!0,timeout:3e4,handler:async(e,r)=>{if(!r.http)throw Error(`JetEmail requires network access.`);let i=await n(r);await t(r.http.fetch.bind(r.http),i,e.message),r.log.info(`Email delivered via JetEmail`,{to:e.message.to,subject:e.message.subject})}}},routes:{admin:{handler:async(e,t)=>{let n=e.input;return n.type===`page_load`&&n.page===`/settings`?r(t):n.type===`form_submit`&&n.action_id===`save_settings`?a(t,n.values??{}):{blocks:[]}}}}};export{o as default,t as deliverWithJetEmail,e as formatSender};
1
+ function e(e,t){return`${e.replace(/[<>"\r\n]/g,``).trim()} <${t}>`}function t(e){if(typeof e==`string`)return e;let t=``;for(let n=0;n<e.length;n+=32768)t+=String.fromCharCode(...e.subarray(n,n+32768));return btoa(t)}async function n(n,r,i){let a={from:e(r.fromName,r.fromEmail),to:i.to,subject:i.subject};i.text&&(a.text=i.text),i.html&&(a.html=i.html),i.cc?.length&&(a.cc=i.cc),i.replyTo&&(a.reply_to=i.replyTo),i.attachments?.length&&(a.attachments=i.attachments.map(e=>({filename:e.filename,data:t(e.content)})));let o=await n(`https://api.jetemail.com/email`,{method:`POST`,headers:{Authorization:`Bearer ${r.apiToken}`,"Content-Type":`application/json`},body:JSON.stringify(a)});if(!o.ok){let e=(await o.text()).slice(0,500);throw Error(`JetEmail rejected the message with HTTP ${o.status}${e?`: ${e}`:``}`)}let s=await o.json().catch(()=>({}));return typeof s.id==`string`?{id:s.id}:{}}async function r(e){let t=await e.kv.get(`settings:apiToken`),n=await e.kv.get(`settings:fromName`),r=await e.kv.get(`settings:fromEmail`);if(!t||!n||!r)throw Error(`JetEmail is not configured. Set the API key, sender name and sender email.`);return{apiToken:t,fromName:n,fromEmail:r}}async function i(e){let t=await e.kv.get(`settings:fromName`)??``,n=await e.kv.get(`settings:fromEmail`)??``,r=!!await e.kv.get(`settings:apiToken`);return{blocks:[{type:`header`,text:`JetEmail`},{type:`section`,text:`Deliver EmDash transactional email through the JetEmail API. The sender domain must be verified in JetEmail and allowed for the API key.`},{type:`form`,block_id:`jetemail-settings`,fields:[{type:`text_input`,action_id:`fromName`,label:`Sender name`,initial_value:t},{type:`text_input`,action_id:`fromEmail`,label:`Sender email`,initial_value:n},{type:`secret_input`,action_id:`apiToken`,label:r?`Transactional API key (leave blank to keep current)`:`Transactional API key`}],submit:{label:`Save settings`,action_id:`save_settings`}}]}}function a(e){return{blocks:[{type:`banner`,style:`error`,text:e}],toast:{message:e,type:`error`}}}async function o(e,t){let n=typeof t.fromName==`string`?t.fromName.trim():``,r=typeof t.fromEmail==`string`?t.fromEmail.trim():``,o=typeof t.apiToken==`string`?t.apiToken.trim():``;return n.replace(/[<>"\r\n]/g,``).trim()?/^[^\s@<>]+@[^\s@<>]+$/.test(r)?o&&!o.startsWith(`transactional_`)?a(`Use a JetEmail transactional API key (transactional_…).`):(await e.kv.set(`settings:fromName`,n),await e.kv.set(`settings:fromEmail`,r),o&&await e.kv.set(`settings:apiToken`,o),{...await i(e),toast:{message:`JetEmail settings saved`,type:`success`}}):a(`Enter a valid sender email.`):a(`Enter a sender name.`)}const s={hooks:{"email:deliver":{exclusive:!0,timeout:3e4,handler:async(e,t)=>{if(!t.http)throw Error(`JetEmail requires network access.`);let i=await r(t);await n(t.http.fetch.bind(t.http),i,e.message),t.log.info(`Email delivered via JetEmail`,{to:e.message.to,subject:e.message.subject})}}},routes:{admin:{handler:async(e,t)=>{let n=e.input;return n.type===`page_load`&&n.page===`/settings`?i(t):n.type===`form_submit`&&n.action_id===`save_settings`?o(t,n.values??{}):{blocks:[]}}}}};export{s as default,n as deliverWithJetEmail,e as formatSender};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@numoteq/emdash-plugin-jetemail",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "JetEmail transport provider for EmDash",
5
5
  "keywords": [
6
6
  "email",