emailr-cli 1.7.0 → 1.7.2
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/index.js +122 -76
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {Command}from'commander';import {Emailr}from'emailr';import v,{readFileSync}from'fs';import B from'os';import
|
|
2
|
+
import {Command}from'commander';import {Emailr}from'emailr';import v,{readFileSync}from'fs';import B from'os';import _ from'path';import re from'cli-table3';import S from'chalk';import Je from'http';import {URL}from'url';import ct from'crypto';import {spawn,execSync,exec}from'child_process';var Re=[_.join(B.homedir(),".emailrrc"),_.join(B.homedir(),".config","emailr","config.json")];function m(){if(process.env.EMAILR_API_KEY)return {apiKey:process.env.EMAILR_API_KEY,baseUrl:process.env.EMAILR_BASE_URL,format:process.env.EMAILR_FORMAT||"table"};for(let i of Re)if(v.existsSync(i))try{let t=v.readFileSync(i,"utf-8"),e=JSON.parse(t);if(e.apiKey)return {apiKey:e.apiKey,baseUrl:e.baseUrl,format:e.format||"table"}}catch{}throw new Error(`No API key configured.
|
|
3
3
|
|
|
4
4
|
Set the EMAILR_API_KEY environment variable:
|
|
5
5
|
export EMAILR_API_KEY=your-api-key
|
|
@@ -7,8 +7,8 @@ Set the EMAILR_API_KEY environment variable:
|
|
|
7
7
|
Or create a config file at ~/.emailrrc:
|
|
8
8
|
{ "apiKey": "your-api-key" }
|
|
9
9
|
|
|
10
|
-
Or run: emailr config set api-key <your-api-key>`)}function
|
|
11
|
-
`);}function ne(i){try{return m()[i]?.toString()}catch{return}}function c(i,t="table"){t==="json"?console.log(JSON.stringify(i,null,2)):Me(i);}function Me(i){Array.isArray(i)?Le(i):typeof i=="object"&&i!==null?De(i):console.log(i);}function Le(i){if(i.length===0){console.log(S.gray("No results"));return}let t=i[0];if(typeof t!="object"||t===null){i.forEach(r=>console.log(r));return}let e=Object.keys(t),
|
|
10
|
+
Or run: emailr config set api-key <your-api-key>`)}function I(){let i=_.join(B.homedir(),".config","emailr");return _.join(i,"config.json")}function G(i){let t=I(),e=_.dirname(t);v.existsSync(e)||v.mkdirSync(e,{recursive:true});let o={};if(v.existsSync(t))try{o=JSON.parse(v.readFileSync(t,"utf-8"));}catch{}let r={...o,...i};v.writeFileSync(t,JSON.stringify(r,null,2)+`
|
|
11
|
+
`);}function ne(i){try{return m()[i]?.toString()}catch{return}}function c(i,t="table"){t==="json"?console.log(JSON.stringify(i,null,2)):Me(i);}function Me(i){Array.isArray(i)?Le(i):typeof i=="object"&&i!==null?De(i):console.log(i);}function Le(i){if(i.length===0){console.log(S.gray("No results"));return}let t=i[0];if(typeof t!="object"||t===null){i.forEach(r=>console.log(r));return}let e=Object.keys(t),o=new re({head:e.map(r=>S.cyan(r)),style:{head:[],border:[]}});for(let r of i){let a=e.map(n=>{let s=r[n];return se(s)});o.push(a);}console.log(o.toString());}function De(i){let t=new re({style:{head:[],border:[]}});for(let[e,o]of Object.entries(i))t.push([S.cyan(e),se(o)]);console.log(t.toString());}function se(i){return i==null?S.gray("-"):typeof i=="boolean"?i?S.green("\u2713"):S.red("\u2717"):typeof i=="object"?JSON.stringify(i):String(i)}function d(i){console.log(S.green("\u2713"),i);}function l(i){console.error(S.red("\u2717"),i);}function k(i){console.warn(S.yellow("\u26A0"),i);}function u(i){console.log(S.blue("\u2139"),i);}function ce(){return new Command("send").description(`Send an email
|
|
12
12
|
|
|
13
13
|
USAGE
|
|
14
14
|
emailr send --to <email_address> [options]
|
|
@@ -156,7 +156,7 @@ EXAMPLES
|
|
|
156
156
|
SEE ALSO
|
|
157
157
|
emailr templates Manage email templates
|
|
158
158
|
emailr contacts Manage contacts
|
|
159
|
-
emailr broadcasts Send bulk emails to segments`).requiredOption("--to <email>","Recipient email address (comma-separated for multiple)").option("--from <email>","Sender email address").option("--subject <subject>","Email subject").option("--html <html>","HTML content (inline)").option("--text <text>","Plain text content (inline)").option("--html-file <path>","Read HTML content from file").option("--text-file <path>","Read plain text content from file").option("--template <id>","Template ID to use").option("--template-data <json>","Template data as JSON").option("--cc <emails>","CC recipients (comma-separated)").option("--bcc <emails>","BCC recipients (comma-separated)").option("--reply-to <email>","Reply-to email address").option("--schedule <datetime>","Schedule send time (ISO 8601)").option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=m(),
|
|
159
|
+
emailr broadcasts Send bulk emails to segments`).requiredOption("--to <email>","Recipient email address (comma-separated for multiple)").option("--from <email>","Sender email address").option("--subject <subject>","Email subject").option("--html <html>","HTML content (inline)").option("--text <text>","Plain text content (inline)").option("--html-file <path>","Read HTML content from file").option("--text-file <path>","Read plain text content from file").option("--template <id>","Template ID to use").option("--template-data <json>","Template data as JSON").option("--cc <emails>","CC recipients (comma-separated)").option("--bcc <emails>","BCC recipients (comma-separated)").option("--reply-to <email>","Reply-to email address").option("--schedule <datetime>","Schedule send time (ISO 8601)").option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=m(),o=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),r=t.to.split(",").map(s=>s.trim()),a={to:r.length===1?r[0]:r};if(t.from&&(a.from=t.from),t.subject&&(a.subject=t.subject),t.htmlFile)try{a.html=readFileSync(t.htmlFile,"utf-8");}catch{l(`Failed to read HTML file: ${t.htmlFile}`),process.exit(1);}else t.html&&(a.html=t.html);if(t.textFile)try{a.text=readFileSync(t.textFile,"utf-8");}catch{l(`Failed to read text file: ${t.textFile}`),process.exit(1);}else t.text&&(a.text=t.text);if(t.template&&(a.template_id=t.template),t.templateData)try{a.template_data=JSON.parse(t.templateData);}catch{l("Invalid JSON for --template-data"),process.exit(1);}if(t.cc){let s=t.cc.split(",").map(p=>p.trim());a.cc=s.length===1?s[0]:s;}if(t.bcc){let s=t.bcc.split(",").map(p=>p.trim());a.bcc=s.length===1?s[0]:s;}t.replyTo&&(a.reply_to_email=t.replyTo),t.schedule&&(a.scheduled_at=t.schedule);let n=await o.emails.send(a);t.format==="json"?c(n,"json"):(d("Email sent successfully!"),c({"Message ID":n.message_id,Recipients:n.recipients,Status:n.status,...n.scheduled_at&&{"Scheduled At":n.scheduled_at}},"table"));}catch(e){l(e instanceof Error?e.message:"Failed to send email"),process.exit(1);}})}function me(){let i=new Command("contacts").description(`Manage contacts
|
|
160
160
|
|
|
161
161
|
USAGE
|
|
162
162
|
emailr contacts <subcommand> [options]
|
|
@@ -284,8 +284,8 @@ EXAMPLES
|
|
|
284
284
|
emailr contacts list --format json
|
|
285
285
|
|
|
286
286
|
# Combine filters with pagination
|
|
287
|
-
emailr contacts list --subscribed --limit 100 --offset 0`).option("--limit <number>","Number of contacts to return","20").option("--offset <number>","Offset for pagination","0").option("--subscribed","Only show subscribed contacts").option("--unsubscribed","Only show unsubscribed contacts").option("--tags <tags>","Filter by tags (comma-separated)").option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=m(),
|
|
288
|
-
Total: ${
|
|
287
|
+
emailr contacts list --subscribed --limit 100 --offset 0`).option("--limit <number>","Number of contacts to return","20").option("--offset <number>","Offset for pagination","0").option("--subscribed","Only show subscribed contacts").option("--unsubscribed","Only show unsubscribed contacts").option("--search <query>","Search by email, first name, or last name").option("--tags <tags>","Filter by tags (comma-separated)").option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=m(),o=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),r={limit:parseInt(t.limit,10),offset:parseInt(t.offset,10)};if(t.subscribed&&(r.subscribed=!0),t.unsubscribed&&(r.subscribed=!1),t.search&&(r.search=t.search),t.tags){let n=t.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean);n.length>0&&(r.tags=n.join(","));}let a=await o.contacts.list(r);if(t.format==="json")c(a,"json");else {let n=a.contacts.map(s=>({ID:s.id,Email:s.email,Name:[s.first_name,s.last_name].filter(Boolean).join(" ")||"-",Subscribed:s.subscribed,Tags:s.tags?.join(", ")||"-",Created:s.created_at}));c(n,"table"),console.log(`
|
|
288
|
+
Total: ${a.total}`);}}catch(e){l(e instanceof Error?e.message:"Failed to list contacts"),process.exit(1);}}),i.command("get <contact_id>").description(`Get a contact by ID
|
|
289
289
|
|
|
290
290
|
USAGE
|
|
291
291
|
emailr contacts get <contact_id> [options]
|
|
@@ -312,7 +312,7 @@ EXAMPLES
|
|
|
312
312
|
emailr contacts get con_abc123 --format json
|
|
313
313
|
|
|
314
314
|
# Pipe JSON to jq for processing
|
|
315
|
-
emailr contacts get con_abc123 --format json | jq '.metadata'`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let
|
|
315
|
+
emailr contacts get con_abc123 --format json | jq '.metadata'`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=m(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).contacts.get(t);c(a,e.format);}catch(o){l(o instanceof Error?o.message:"Failed to get contact"),process.exit(1);}}),i.command("create").description(`Create a new contact
|
|
316
316
|
|
|
317
317
|
USAGE
|
|
318
318
|
emailr contacts create --email <email_address> [options]
|
|
@@ -354,7 +354,7 @@ EXAMPLES
|
|
|
354
354
|
emailr contacts create --email "user@example.com" --subscribed false
|
|
355
355
|
|
|
356
356
|
# Get JSON output for scripting
|
|
357
|
-
emailr contacts create --email "user@example.com" --format json`).requiredOption("--email <email>","Contact email address").option("--first-name <name>","First name").option("--last-name <name>","Last name").option("--subscribed","Mark as subscribed (default: true)").option("--metadata <json>","Metadata as JSON").option("--tags <tags>","Comma-separated tags").option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=m(),
|
|
357
|
+
emailr contacts create --email "user@example.com" --format json`).requiredOption("--email <email>","Contact email address").option("--first-name <name>","First name").option("--last-name <name>","Last name").option("--subscribed","Mark as subscribed (default: true)").option("--metadata <json>","Metadata as JSON").option("--tags <tags>","Comma-separated tags").option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=m(),o=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),r={email:t.email};if(t.firstName&&(r.first_name=t.firstName),t.lastName&&(r.last_name=t.lastName),t.subscribed!==void 0&&(r.subscribed=t.subscribed),t.metadata)try{r.metadata=JSON.parse(t.metadata);}catch{l("Invalid JSON for --metadata"),process.exit(1);}t.tags&&(r.tags=t.tags.split(",").map(n=>n.trim().toLowerCase()).filter(Boolean));let a=await o.contacts.create(r);t.format==="json"?c(a,"json"):(d(`Contact created: ${a.id}`),c(a,"table"));}catch(e){l(e instanceof Error?e.message:"Failed to create contact"),process.exit(1);}}),i.command("update <contact_id>").description(`Update a contact
|
|
358
358
|
|
|
359
359
|
USAGE
|
|
360
360
|
emailr contacts update <contact_id> [options]
|
|
@@ -402,7 +402,7 @@ EXAMPLES
|
|
|
402
402
|
emailr contacts update con_abc123 --metadata '{"plan": "enterprise", "upgraded": true}'
|
|
403
403
|
|
|
404
404
|
# Get JSON output
|
|
405
|
-
emailr contacts update con_abc123 --first-name "Jane" --format json`).option("--email <email>","New email address").option("--first-name <name>","First name").option("--last-name <name>","Last name").option("--subscribed","Mark as subscribed").option("--unsubscribed","Mark as unsubscribed").option("--metadata <json>","Metadata as JSON").option("--tags <tags>","Comma-separated tags").option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let
|
|
405
|
+
emailr contacts update con_abc123 --first-name "Jane" --format json`).option("--email <email>","New email address").option("--first-name <name>","First name").option("--last-name <name>","Last name").option("--subscribed","Mark as subscribed").option("--unsubscribed","Mark as unsubscribed").option("--metadata <json>","Metadata as JSON").option("--tags <tags>","Comma-separated tags").option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=m(),r=new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}),a={};if(e.email&&(a.email=e.email),e.firstName&&(a.first_name=e.firstName),e.lastName&&(a.last_name=e.lastName),e.subscribed&&(a.subscribed=!0),e.unsubscribed&&(a.subscribed=!1),e.metadata)try{a.metadata=JSON.parse(e.metadata);}catch{l("Invalid JSON for --metadata"),process.exit(1);}e.tags&&(a.tags=e.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean));let n=await r.contacts.update(t,a);e.format==="json"?c(n,"json"):(d(`Contact updated: ${n.id}`),c(n,"table"));}catch(o){l(o instanceof Error?o.message:"Failed to update contact"),process.exit(1);}}),i.command("delete <contact_id>").description(`Delete a contact
|
|
406
406
|
|
|
407
407
|
USAGE
|
|
408
408
|
emailr contacts delete <contact_id>
|
|
@@ -419,7 +419,7 @@ EXAMPLES
|
|
|
419
419
|
emailr contacts delete con_abc123
|
|
420
420
|
|
|
421
421
|
WARNING
|
|
422
|
-
This action is permanent and cannot be undone.`).action(async t=>{try{let e=m();await new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}).contacts.delete(t),d(`Contact deleted: ${t}`);}catch(e){l(e instanceof Error?e.message:"Failed to delete contact"),process.exit(1);}}),i}function pe(){return
|
|
422
|
+
This action is permanent and cannot be undone.`).action(async t=>{try{let e=m();await new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}).contacts.delete(t),d(`Contact deleted: ${t}`);}catch(e){l(e instanceof Error?e.message:"Failed to delete contact"),process.exit(1);}}),i}function pe(){return _.join(B.homedir(),".config","emailr","templates")}function qe(){let i=pe();v.existsSync(i)||v.mkdirSync(i,{recursive:true});}function W(i){return _.join(pe(),`${i}.html`)}function X(i,t){qe();let e=W(i);v.writeFileSync(e,t,"utf-8");}function ue(i){let t=W(i);return v.existsSync(t)?v.readFileSync(t,"utf-8"):null}function fe(i){let t=W(i);return v.existsSync(t)}var w=null,U=null,H=false;function he(i){return i.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}function $e(i){return i===null||i.trim()===""}function Be(i){return `<!DOCTYPE html>
|
|
423
423
|
<html lang="en">
|
|
424
424
|
<head>
|
|
425
425
|
<meta charset="UTF-8">
|
|
@@ -548,7 +548,7 @@ WARNING
|
|
|
548
548
|
<p style="margin-top: 1rem;">Try creating or retrieving the template first using the CLI.</p>
|
|
549
549
|
</div>
|
|
550
550
|
</body>
|
|
551
|
-
</html>`}function We(i){let t=i.match(/^\/preview\/([^/]+)$/);return t?t[1]:null}function Xe(){return (i,t)=>{if(i.method!=="GET"){t.writeHead(405,{"Content-Type":"text/plain"}),t.end("Method Not Allowed");return}let e=i.url||"/",
|
|
551
|
+
</html>`}function We(i){let t=i.match(/^\/preview\/([^/]+)$/);return t?t[1]:null}function Xe(){return (i,t)=>{if(i.method!=="GET"){t.writeHead(405,{"Content-Type":"text/plain"}),t.end("Method Not Allowed");return}let e=i.url||"/",o=We(e);if(!o){t.writeHead(404,{"Content-Type":"text/plain"}),t.end("Not Found");return}if(!fe(o)){t.writeHead(404,{"Content-Type":"text/html; charset=utf-8"}),t.end(be(o));return}let r=ue(o);if(r===null){t.writeHead(404,{"Content-Type":"text/html; charset=utf-8"}),t.end(be(o));return}if($e(r)){t.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),t.end(Be(o));return}t.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),t.end(r);}}var ge={async start(){return H&&U!==null?U:new Promise((i,t)=>{w=Je.createServer(Xe()),w.listen(0,"127.0.0.1",()=>{let e=w.address();e&&typeof e=="object"?(U=e.port,H=true,w.unref(),i(U)):t(new Error("Failed to get server address"));}),w.on("error",e=>{H=false,U=null,w=null,t(new Error(`Failed to start preview server: ${e.message}`));});})},getPort(){return U},isRunning(){return H},async stop(){if(w)return new Promise(i=>{w.close(()=>{w=null,U=null,H=false,i();});})}};function we(){return ge}async function V(i){try{return `http://127.0.0.1:${await ge.start()}/preview/${i}`}catch{return null}}function ye(){w&&w.ref();}var P=null,z=null,J=null,R=[],ve=`
|
|
552
552
|
<script>
|
|
553
553
|
(function() {
|
|
554
554
|
const evtSource = new EventSource('/__live-reload');
|
|
@@ -564,9 +564,9 @@ WARNING
|
|
|
564
564
|
</script>
|
|
565
565
|
`;function Ye(i){return i.includes("</body>")?i.replace("</body>",`${ve}</body>`):i+ve}function Ze(){R.forEach(i=>{try{i.write(`data: reload
|
|
566
566
|
|
|
567
|
-
`);}catch{}});}async function Y(i,t){let e=
|
|
567
|
+
`);}catch{}});}async function Y(i,t){let e=_.resolve(i);return new Promise((o,r)=>{P=Je.createServer((a,n)=>{if(a.url==="/__live-reload"){n.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive","Access-Control-Allow-Origin":"*"}),n.write(`data: connected
|
|
568
568
|
|
|
569
|
-
`),R.push(n),
|
|
569
|
+
`),R.push(n),a.on("close",()=>{R=R.filter(s=>s!==n);});return}if(a.method==="GET"){try{let s=v.readFileSync(e,"utf-8"),p=Ye(s);n.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),n.end(p);}catch(s){n.writeHead(500,{"Content-Type":"text/plain"}),n.end(`Error reading file: ${s instanceof Error?s.message:String(s)}`);}return}n.writeHead(405,{"Content-Type":"text/plain"}),n.end("Method Not Allowed");}),P.listen(0,"127.0.0.1",()=>{let a=P.address();if(a&&typeof a=="object"){z=a.port;let n=null;J=v.watch(e,s=>{s==="change"&&(n&&clearTimeout(n),n=setTimeout(()=>{Ze(),t?.();},100));}),o(z);}else r(new Error("Failed to get server address"));}),P.on("error",a=>{r(new Error(`Failed to start server: ${a.message}`));});})}async function Z(){if(J&&(J.close(),J=null),R.forEach(i=>{try{i.end();}catch{}}),R=[],P)return new Promise(i=>{P.close(()=>{P=null,z=null,i();});})}async function Te(i){try{let t=i.html_content??"";X(i.id,t);}catch(t){return k(`Could not save template for preview: ${t instanceof Error?t.message:String(t)}`),null}try{let t=await V(i.id);return t===null?(k("Could not start preview server"),null):t}catch(t){return k(`Could not generate preview URL: ${t instanceof Error?t.message:String(t)}`),null}}function Oe(){let i=new Command("templates").description(`Manage email templates
|
|
570
570
|
|
|
571
571
|
USAGE
|
|
572
572
|
emailr templates <subcommand> [options]
|
|
@@ -666,8 +666,8 @@ EXAMPLES
|
|
|
666
666
|
emailr templates list --page 2 --limit 10
|
|
667
667
|
|
|
668
668
|
# Get JSON output for scripting
|
|
669
|
-
emailr templates list --format json`).option("--limit <count>","Number of templates to return","20").option("--page <page_number>","Page number for pagination","1").option("--tags <tags>","Filter by tags (comma-separated)").option("--format <format>","Output format: json | table","table").action(async t=>{try{let e=m(),
|
|
670
|
-
Total: ${
|
|
669
|
+
emailr templates list --format json`).option("--limit <count>","Number of templates to return","20").option("--page <page_number>","Page number for pagination","1").option("--tags <tags>","Filter by tags (comma-separated)").option("--format <format>","Output format: json | table","table").action(async t=>{try{let e=m(),o=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),r={limit:parseInt(t.limit,10),page:parseInt(t.page,10)};if(t.tags){let n=t.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean);n.length>0&&(r.tags=n.join(","));}let a=await o.templates.list(r);if(t.format==="json")c(a,"json");else {let n=a.map(s=>({ID:s.id,Name:s.name,Subject:s.subject,Variables:s.variables?.join(", ")||"-",Tags:s.tags?.join(", ")||"-",Created:s.created_at}));c(n,"table"),console.log(`
|
|
670
|
+
Total: ${a.length}`);}}catch(e){l(e instanceof Error?e.message:"Failed to list templates"),process.exit(1);}}),i.command("get <template_id>").description(`Get a template by ID
|
|
671
671
|
|
|
672
672
|
USAGE
|
|
673
673
|
emailr templates get <template_id> [options]
|
|
@@ -695,7 +695,7 @@ EXAMPLES
|
|
|
695
695
|
emailr templates get tpl_abc123 --format json
|
|
696
696
|
|
|
697
697
|
# Pipe JSON to jq for processing
|
|
698
|
-
emailr templates get tpl_abc123 --format json | jq '.html_content'`).option("--format <format>","Output format: json | table","table").action(async(t,e)=>{try{let
|
|
698
|
+
emailr templates get tpl_abc123 --format json | jq '.html_content'`).option("--format <format>","Output format: json | table","table").action(async(t,e)=>{try{let o=m(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).templates.get(t),n=await Te({id:a.id,html_content:a.html_content??void 0}),s=a.preview_html?`${o.baseUrl}/preview/${a.id}`:null;if(e.format==="json")c({...a,preview_url:s??n},"json");else {let p={ID:a.id,Name:a.name,Subject:a.subject,Variables:a.variables?.join(", ")||"-",Created:a.created_at};s?p["Preview URL"]=s:n&&(p["Local Preview"]=n),c(p,"table");}}catch(o){l(o instanceof Error?o.message:"Failed to get template"),process.exit(1);}}),i.command("fetch <template_id>").description(`Download template HTML to file or stdout
|
|
699
699
|
|
|
700
700
|
USAGE
|
|
701
701
|
emailr templates fetch <template_id> [options]
|
|
@@ -729,8 +729,8 @@ AGENTIC WORKFLOW
|
|
|
729
729
|
This is step 1 of the agentic workflow:
|
|
730
730
|
1. Fetch: emailr templates fetch <id> --output template.html
|
|
731
731
|
2. Edit locally or with AI assistance
|
|
732
|
-
3. Push preview: emailr templates push-preview <id> --html-file template.html`).option("--output <file_path>","Write HTML to file (default: stdout)").option("--preview","Fetch preview HTML instead of published HTML").action(async(t,e)=>{try{let
|
|
733
|
-
Run 'emailr templates push-preview <id> --html-file <path>' to create a preview.`)):l("Template has no HTML content"),process.exit(1)),e.output){let n=
|
|
732
|
+
3. Push preview: emailr templates push-preview <id> --html-file template.html`).option("--output <file_path>","Write HTML to file (default: stdout)").option("--preview","Fetch preview HTML instead of published HTML").action(async(t,e)=>{try{let o=m(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).templates.fetch(t,{preview:e.preview??!1});if(a||(e.preview?(l("No preview HTML exists for this template"),console.log(`
|
|
733
|
+
Run 'emailr templates push-preview <id> --html-file <path>' to create a preview.`)):l("Template has no HTML content"),process.exit(1)),e.output){let n=_.resolve(e.output);v.writeFileSync(n,a,"utf-8"),d(`HTML saved to: ${n}`);}else console.log(a);}catch(o){l(o instanceof Error?o.message:"Failed to fetch template"),process.exit(1);}}),i.command("push-preview <template_id>").description(`Upload HTML to template's preview for sharing with AI agents
|
|
734
734
|
|
|
735
735
|
USAGE
|
|
736
736
|
emailr templates push-preview <template_id> --html-file <file_path>
|
|
@@ -774,8 +774,8 @@ AGENTIC WORKFLOW
|
|
|
774
774
|
3. Push preview: emailr templates push-preview <id> --html-file template.html
|
|
775
775
|
4. Share the preview URL with your AI agent for feedback
|
|
776
776
|
5. Repeat steps 2-4 until satisfied`).option("--html-file <file_path>","Read HTML content from file").option("--html <html_content>","Inline HTML content").option("--format <format>","Output format: json | table","table").action(async(t,e)=>{try{!e.htmlFile&&!e.html&&(l("Either --html-file or --html is required"),console.log(`
|
|
777
|
-
Usage:`),console.log(" emailr templates push-preview <id> --html-file <path>"),console.log(" emailr templates push-preview <id> --html <content>"),process.exit(1)),e.htmlFile&&e.html&&(l("Cannot use both --html-file and --html. Choose one."),process.exit(1));let
|
|
778
|
-
Share this URL with your AI agent for feedback.`));}catch(
|
|
777
|
+
Usage:`),console.log(" emailr templates push-preview <id> --html-file <path>"),console.log(" emailr templates push-preview <id> --html <content>"),process.exit(1)),e.htmlFile&&e.html&&(l("Cannot use both --html-file and --html. Choose one."),process.exit(1));let o=m(),r=new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}),a;if(e.htmlFile){let p=_.resolve(e.htmlFile);try{a=v.readFileSync(p,"utf-8");}catch{l(`Failed to read file: ${p}`),process.exit(1);}}else a=e.html;let n=await r.templates.pushPreview(t,a),s="updated";e.format==="json"?c({template_id:t,preview_url:n.preview_url,status:s},"json"):(d("Preview uploaded successfully"),c({"Template ID":t,"Preview URL":n.preview_url,Status:s},"table"),console.log(`
|
|
778
|
+
Share this URL with your AI agent for feedback.`));}catch(o){l(o instanceof Error?o.message:"Failed to push preview"),process.exit(1);}}),i.command("create").description(`Create a new email template
|
|
779
779
|
|
|
780
780
|
USAGE
|
|
781
781
|
emailr templates create --name <template_name> --subject <subject_line> [options]
|
|
@@ -820,7 +820,7 @@ EXAMPLES
|
|
|
820
820
|
|
|
821
821
|
TIP
|
|
822
822
|
For live preview while building, use "emailr templates draft" first.
|
|
823
|
-
It creates a local file with hot-reload preview, then use this command to save.`).requiredOption("--name <template_name>","Template name").requiredOption("--subject <subject_line>","Email subject line").option("--html <html_content>","Inline HTML content").option("--text <text_content>","Plain text content").option("--html-file <file_path>","Read HTML content from file").option("--text-file <file_path>","Read text content from file").option("--from <email_address>","Default from email address").option("--reply-to <email_address>","Default reply-to email address").option("--preview-text <text>","Preview text shown in email clients").option("--tags <tags>","Comma-separated tags").option("--format <format>","Output format: json | table","table").action(async t=>{try{let e=m(),
|
|
823
|
+
It creates a local file with hot-reload preview, then use this command to save.`).requiredOption("--name <template_name>","Template name").requiredOption("--subject <subject_line>","Email subject line").option("--html <html_content>","Inline HTML content").option("--text <text_content>","Plain text content").option("--html-file <file_path>","Read HTML content from file").option("--text-file <file_path>","Read text content from file").option("--from <email_address>","Default from email address").option("--reply-to <email_address>","Default reply-to email address").option("--preview-text <text>","Preview text shown in email clients").option("--tags <tags>","Comma-separated tags").option("--format <format>","Output format: json | table","table").action(async t=>{try{let e=m(),o=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),r={name:t.name,subject:t.subject};if(t.htmlFile){let s=await import('fs');r.html_content=s.readFileSync(t.htmlFile,"utf-8");}else t.html&&(r.html_content=t.html);if(t.textFile){let s=await import('fs');r.text_content=s.readFileSync(t.textFile,"utf-8");}else t.text&&(r.text_content=t.text);t.from&&(r.from_email=t.from),t.replyTo&&(r.reply_to=t.replyTo),t.previewText&&(r.preview_text=t.previewText),t.tags&&(r.tags=t.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean));let a=await o.templates.create(r),n=await Te({id:a.id,html_content:a.html_content??void 0});if(t.format==="json")c({...a,preview_url:n},"json");else {d(`Template created: ${a.id}`);let s={ID:a.id,Name:a.name,Subject:a.subject,Variables:a.variables?.join(", ")||"-",Tags:a.tags?.join(", ")||"-"};n&&(s["Preview URL"]=n),c(s,"table"),n&&console.log(`
|
|
824
824
|
Open the Preview URL in your browser to view the rendered template.`);}}catch(e){l(e instanceof Error?e.message:"Failed to create template"),process.exit(1);}}),i.command("update <template_id>").description(`Update an existing email template
|
|
825
825
|
|
|
826
826
|
USAGE
|
|
@@ -873,7 +873,7 @@ AGENTIC WORKFLOW
|
|
|
873
873
|
2. Edit locally or with AI assistance
|
|
874
874
|
3. Push preview: emailr templates push-preview <id> --html-file template.html
|
|
875
875
|
4. Share URL with AI agent, iterate on feedback
|
|
876
|
-
5. Publish: emailr templates update <id> --html-file template.html`).option("--name <template_name>","New template name").option("--subject <subject_line>","New email subject line").option("--html <html_content>","New inline HTML content").option("--text <text_content>","New plain text content").option("--html-file <file_path>","Read new HTML content from file").option("--text-file <file_path>","Read new text content from file").option("--from <email_address>","New default from email address").option("--reply-to <email_address>","New default reply-to email address").option("--preview-text <text>","New preview text").option("--tags <tags>","Comma-separated tags").option("--format <format>","Output format: json | table","table").action(async(t,e)=>{try{let
|
|
876
|
+
5. Publish: emailr templates update <id> --html-file template.html`).option("--name <template_name>","New template name").option("--subject <subject_line>","New email subject line").option("--html <html_content>","New inline HTML content").option("--text <text_content>","New plain text content").option("--html-file <file_path>","Read new HTML content from file").option("--text-file <file_path>","Read new text content from file").option("--from <email_address>","New default from email address").option("--reply-to <email_address>","New default reply-to email address").option("--preview-text <text>","New preview text").option("--tags <tags>","Comma-separated tags").option("--format <format>","Output format: json | table","table").action(async(t,e)=>{try{let o=m(),r=new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}),a={};if(e.name&&(a.name=e.name),e.subject&&(a.subject=e.subject),e.htmlFile){let s=await import('fs');a.html_content=s.readFileSync(e.htmlFile,"utf-8");}else e.html&&(a.html_content=e.html);if(e.textFile){let s=await import('fs');a.text_content=s.readFileSync(e.textFile,"utf-8");}else e.text&&(a.text_content=e.text);e.from&&(a.from_email=e.from),e.replyTo&&(a.reply_to=e.replyTo),e.previewText&&(a.preview_text=e.previewText),e.tags&&(a.tags=e.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean));let n=await r.templates.update(t,a);if(e.format==="json")c(n,"json");else {d(`Template updated: ${n.id}`);let s={ID:n.id,Name:n.name,Subject:n.subject,Variables:n.variables?.join(", ")||"-",Tags:n.tags?.join(", ")||"-",Updated:n.updated_at};c(s,"table");}}catch(o){l(o instanceof Error?o.message:"Failed to update template"),process.exit(1);}}),i.command("delete <template_id>").description(`Delete a template
|
|
877
877
|
|
|
878
878
|
USAGE
|
|
879
879
|
emailr templates delete <template_id>
|
|
@@ -919,12 +919,12 @@ EXAMPLES
|
|
|
919
919
|
|
|
920
920
|
SEE ALSO
|
|
921
921
|
emailr templates edit Live editing with hot-reload
|
|
922
|
-
emailr templates stop-preview Stop background preview server`).option("--no-open","Do not automatically open browser").option("--foreground","Keep process running in foreground (blocks terminal)").action(async(t,e)=>{try{let
|
|
923
|
-
Template: ${
|
|
922
|
+
emailr templates stop-preview Stop background preview server`).option("--no-open","Do not automatically open browser").option("--foreground","Keep process running in foreground (blocks terminal)").action(async(t,e)=>{try{let o=m(),r=new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl});console.log(`Fetching template ${t}...`);let a=await r.templates.get(t),n=a.html_content??"";if(X(a.id,n),e.foreground){let f=await V(a.id);if(f||(l("Failed to start preview server"),process.exit(1)),ye(),console.log(`
|
|
923
|
+
Template: ${a.name}`),console.log(`Preview URL: ${f}`),e.open!==!1)try{await(await import('open')).default(f),console.log(`
|
|
924
924
|
Browser opened.`);}catch{console.log(`
|
|
925
925
|
Could not open browser automatically. Open the URL above manually.`);}process.on("SIGINT",async()=>{console.log(`
|
|
926
926
|
|
|
927
|
-
Stopping preview server...`),await we().stop(),console.log("Done."),process.exit(0);});return}let s=
|
|
927
|
+
Stopping preview server...`),await we().stop(),console.log("Done."),process.exit(0);});return}let s=_.join(process.cwd(),`.template-preview-${a.id}.html`);v.writeFileSync(s,n,"utf-8");let{spawn:p}=await import('child_process'),b=await import('os'),T=_.join(b.tmpdir(),"emailr-preview.pid");try{let f=v.readFileSync(T,"utf-8").trim();process.kill(parseInt(f,10),"SIGTERM");}catch{}let h=`
|
|
928
928
|
const http = require('http');
|
|
929
929
|
const fs = require('fs');
|
|
930
930
|
const path = require('path');
|
|
@@ -949,9 +949,9 @@ Stopping preview server...`),await we().stop(),console.log("Done."),process.exit
|
|
|
949
949
|
console.log('PORT:' + port);
|
|
950
950
|
});
|
|
951
951
|
process.on('SIGTERM', () => { try { fs.unlinkSync(pidFile); fs.unlinkSync(portFile); fs.unlinkSync(filePath); } catch {} process.exit(0); });
|
|
952
|
-
`,y=p("node",["-e",h],{detached:!0,stdio:["ignore","pipe","ignore"]}),O="";await new Promise(f=>{y.stdout?.on("data",
|
|
953
|
-
Template: ${
|
|
954
|
-
To stop: emailr templates stop-preview`),e.open!==!1)try{await(await import('open')).default(D);}catch{}process.exit(0);}catch(
|
|
952
|
+
`,y=p("node",["-e",h],{detached:!0,stdio:["ignore","pipe","ignore"]}),O="";await new Promise(f=>{y.stdout?.on("data",N=>{let q=N.toString().match(/PORT:(\d+)/);q&&(O=q[1],f());}),setTimeout(f,3e3);}),y.unref();let D=`http://127.0.0.1:${O}/`;if(console.log(`
|
|
953
|
+
Template: ${a.name}`),console.log(`Preview URL: ${D}`),console.log(`
|
|
954
|
+
To stop: emailr templates stop-preview`),e.open!==!1)try{await(await import('open')).default(D);}catch{}process.exit(0);}catch(o){l(o instanceof Error?o.message:"Failed to preview template"),process.exit(1);}}),i.command("edit <template_id>").description(`Start a live editing session for a template with hot-reload
|
|
955
955
|
|
|
956
956
|
USAGE
|
|
957
957
|
emailr templates edit <template_id> [options]
|
|
@@ -991,17 +991,17 @@ EXAMPLES
|
|
|
991
991
|
SEE ALSO
|
|
992
992
|
emailr templates draft Draft a new template with live preview
|
|
993
993
|
emailr templates update Save changes to the template
|
|
994
|
-
emailr templates stop-preview Stop the background preview server`).option("--file <file_path>","Path to save the HTML file for editing","./template.html").option("--no-open","Do not automatically open browser").option("--foreground","Keep process running in foreground (blocks terminal)").action(async(t,e)=>{try{let
|
|
995
|
-
Template: ${n.name}`),console.log(`Template ID: ${n.id}`),console.log(`Live Preview: ${
|
|
996
|
-
Watching for changes... Edit the file and see live updates.`),console.log(`When done, run: emailr templates update ${t} --html-file ${e.file}`),e.open!==!1)try{await(await import('open')).default(
|
|
994
|
+
emailr templates stop-preview Stop the background preview server`).option("--file <file_path>","Path to save the HTML file for editing","./template.html").option("--no-open","Do not automatically open browser").option("--foreground","Keep process running in foreground (blocks terminal)").action(async(t,e)=>{try{let o=m(),r=new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}),a=_.resolve(e.file);console.log(`Fetching template ${t}...`);let n=await r.templates.get(t),s=n.html_content??"";if(v.writeFileSync(a,s,"utf-8"),console.log(`Template saved to: ${a}`),e.foreground){let N=`http://127.0.0.1:${await Y(a,()=>{console.log("File changed - browser refreshed");})}/`;if(console.log(`
|
|
995
|
+
Template: ${n.name}`),console.log(`Template ID: ${n.id}`),console.log(`Live Preview: ${N}`),console.log(`File: ${a}`),console.log(`
|
|
996
|
+
Watching for changes... Edit the file and see live updates.`),console.log(`When done, run: emailr templates update ${t} --html-file ${e.file}`),e.open!==!1)try{await(await import('open')).default(N);}catch{}process.on("SIGINT",async()=>{console.log(`
|
|
997
997
|
|
|
998
998
|
Stopping live preview server...`),await Z(),console.log("Done."),console.log(`
|
|
999
|
-
To save changes: emailr templates update ${t} --html-file ${e.file}`),process.exit(0);});return}let{spawn:p}=await import('child_process'),b=await import('os'),T=
|
|
999
|
+
To save changes: emailr templates update ${t} --html-file ${e.file}`),process.exit(0);});return}let{spawn:p}=await import('child_process'),b=await import('os'),T=_.join(b.tmpdir(),"emailr-preview.pid");try{let f=v.readFileSync(T,"utf-8").trim();process.kill(parseInt(f,10),"SIGTERM");}catch{}let h=`
|
|
1000
1000
|
const http = require('http');
|
|
1001
1001
|
const fs = require('fs');
|
|
1002
1002
|
const path = require('path');
|
|
1003
1003
|
const os = require('os');
|
|
1004
|
-
const filePath = ${JSON.stringify(
|
|
1004
|
+
const filePath = ${JSON.stringify(a)};
|
|
1005
1005
|
const pidFile = path.join(os.tmpdir(), 'emailr-preview.pid');
|
|
1006
1006
|
const portFile = path.join(os.tmpdir(), 'emailr-preview.port');
|
|
1007
1007
|
let clients = [];
|
|
@@ -1036,10 +1036,10 @@ To save changes: emailr templates update ${t} --html-file ${e.file}`),process.ex
|
|
|
1036
1036
|
});
|
|
1037
1037
|
});
|
|
1038
1038
|
process.on('SIGTERM', () => { try { fs.unlinkSync(pidFile); fs.unlinkSync(portFile); } catch {} process.exit(0); });
|
|
1039
|
-
`,y=p("node",["-e",h],{detached:!0,stdio:["ignore","pipe","ignore"]}),O="";await new Promise(f=>{y.stdout?.on("data",
|
|
1040
|
-
Template: ${n.name}`),console.log(`Template ID: ${n.id}`),console.log(`Live Preview: ${D}`),console.log(`File: ${
|
|
1039
|
+
`,y=p("node",["-e",h],{detached:!0,stdio:["ignore","pipe","ignore"]}),O="";await new Promise(f=>{y.stdout?.on("data",N=>{let ie=N.toString().match(/PORT:(\d+)/);ie&&(O=ie[1],f());}),setTimeout(f,3e3);}),y.unref();let D=`http://127.0.0.1:${O}/`;if(console.log(`
|
|
1040
|
+
Template: ${n.name}`),console.log(`Template ID: ${n.id}`),console.log(`Live Preview: ${D}`),console.log(`File: ${a}`),console.log(`
|
|
1041
1041
|
Edit the file and see live updates in the browser.`),console.log(`
|
|
1042
|
-
When done:`),console.log(` emailr templates update ${t} --html-file ${e.file}`),console.log(" emailr templates stop-preview"),e.open!==!1)try{await(await import('open')).default(D);}catch{}process.exit(0);}catch(
|
|
1042
|
+
When done:`),console.log(` emailr templates update ${t} --html-file ${e.file}`),console.log(" emailr templates stop-preview"),e.open!==!1)try{await(await import('open')).default(D);}catch{}process.exit(0);}catch(o){l(o instanceof Error?o.message:"Failed to edit template"),process.exit(1);}}),i.command("draft").description(`Start a live drafting session for a new template with hot-reload
|
|
1043
1043
|
|
|
1044
1044
|
USAGE
|
|
1045
1045
|
emailr templates draft [options]
|
|
@@ -1081,7 +1081,7 @@ EXAMPLES
|
|
|
1081
1081
|
SEE ALSO
|
|
1082
1082
|
emailr templates edit Edit an existing template with live preview
|
|
1083
1083
|
emailr templates create Create the template from your draft
|
|
1084
|
-
emailr templates stop-preview Stop the background preview server`).option("--file <file_path>","Path to save the HTML file for drafting","./new-template.html").option("--no-open","Do not automatically open browser").option("--blank","Start with a blank file instead of starter template").option("--foreground","Keep process running in foreground (blocks terminal)").action(async t=>{try{let e=
|
|
1084
|
+
emailr templates stop-preview Stop the background preview server`).option("--file <file_path>","Path to save the HTML file for drafting","./new-template.html").option("--no-open","Do not automatically open browser").option("--blank","Start with a blank file instead of starter template").option("--foreground","Keep process running in foreground (blocks terminal)").action(async t=>{try{let e=_.resolve(t.file),o;if(t.blank?o="":o=`<!DOCTYPE html>
|
|
1085
1085
|
<html>
|
|
1086
1086
|
<head>
|
|
1087
1087
|
<meta charset="UTF-8">
|
|
@@ -1116,13 +1116,13 @@ SEE ALSO
|
|
|
1116
1116
|
<p><a href="{{unsubscribe_link}}">Unsubscribe</a></p>
|
|
1117
1117
|
</div>
|
|
1118
1118
|
</body>
|
|
1119
|
-
</html>`,v.writeFileSync(e,
|
|
1119
|
+
</html>`,v.writeFileSync(e,o,"utf-8"),console.log(`Template draft created: ${e}`),t.foreground){let y=`http://127.0.0.1:${await Y(e,()=>{console.log("File changed - browser refreshed");})}/`;if(console.log(`
|
|
1120
1120
|
Live Preview: ${y}`),console.log(`File: ${e}`),console.log(`
|
|
1121
1121
|
Watching for changes... Edit the file and see live updates.`),console.log(`
|
|
1122
1122
|
When done, create the template:`),console.log(` emailr templates create --name "Template Name" --subject "Email Subject" --html-file ${t.file}`),t.open!==!1)try{await(await import('open')).default(y);}catch{}process.on("SIGINT",async()=>{console.log(`
|
|
1123
1123
|
|
|
1124
1124
|
Stopping live preview server...`),await Z(),console.log("Done."),console.log(`
|
|
1125
|
-
To create template: emailr templates create --name "Template Name" --subject "Email Subject" --html-file ${t.file}`),process.exit(0);});return}let{spawn:r}=await import('child_process'),
|
|
1125
|
+
To create template: emailr templates create --name "Template Name" --subject "Email Subject" --html-file ${t.file}`),process.exit(0);});return}let{spawn:r}=await import('child_process'),a=await import('os'),n=_.join(a.tmpdir(),"emailr-preview.pid");try{let h=v.readFileSync(n,"utf-8").trim();process.kill(parseInt(h,10),"SIGTERM");}catch{}let s=`
|
|
1126
1126
|
const http = require('http');
|
|
1127
1127
|
const fs = require('fs');
|
|
1128
1128
|
const path = require('path');
|
|
@@ -1182,7 +1182,7 @@ EXAMPLES
|
|
|
1182
1182
|
SEE ALSO
|
|
1183
1183
|
emailr templates edit Start live editing session
|
|
1184
1184
|
emailr templates draft Start live drafting session
|
|
1185
|
-
emailr templates preview Preview a template in browser`).action(async()=>{let t=await import('os'),e=
|
|
1185
|
+
emailr templates preview Preview a template in browser`).action(async()=>{let t=await import('os'),e=_.join(t.tmpdir(),"emailr-preview.pid");try{let o=v.readFileSync(e,"utf-8").trim();process.kill(parseInt(o,10),"SIGTERM"),v.unlinkSync(e),d("Preview server stopped");}catch{d("No preview server running");}}),i}function Ee(){let i=new Command("domains").description(`Manage sending domains
|
|
1186
1186
|
|
|
1187
1187
|
USAGE
|
|
1188
1188
|
emailr domains <subcommand> [options]
|
|
@@ -1290,7 +1290,7 @@ EXAMPLES
|
|
|
1290
1290
|
emailr domains list --format json | jq '.[] | select(.status == "verified")'
|
|
1291
1291
|
|
|
1292
1292
|
# Count domains
|
|
1293
|
-
emailr domains list --format json | jq 'length'`).option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=m(),r=await new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}).domains.list();if(t.format==="json")c(r,"json");else {let
|
|
1293
|
+
emailr domains list --format json | jq 'length'`).option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=m(),r=await new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}).domains.list();if(t.format==="json")c(r,"json");else {let a=r.map(n=>({ID:n.id,Domain:n.domain,Status:n.status,DKIM:n.dkim_verified,SPF:n.spf_verified,DMARC:n.dmarc_verified,Created:n.created_at}));c(a,"table");}}catch(e){l(e instanceof Error?e.message:"Failed to list domains"),process.exit(1);}}),i.command("get <domain_id>").description(`Get domain details
|
|
1294
1294
|
|
|
1295
1295
|
USAGE
|
|
1296
1296
|
emailr domains get <domain_id> [options]
|
|
@@ -1317,7 +1317,7 @@ EXAMPLES
|
|
|
1317
1317
|
emailr domains get dom_abc123 --format json
|
|
1318
1318
|
|
|
1319
1319
|
# Extract DNS records
|
|
1320
|
-
emailr domains get dom_abc123 --format json | jq '.dns_records'`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let
|
|
1320
|
+
emailr domains get dom_abc123 --format json | jq '.dns_records'`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=m(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).domains.get(t);c(a,e.format);}catch(o){l(o instanceof Error?o.message:"Failed to get domain"),process.exit(1);}}),i.command("add <domain_name>").description(`Add a new domain
|
|
1321
1321
|
|
|
1322
1322
|
USAGE
|
|
1323
1323
|
emailr domains add <domain_name> [options]
|
|
@@ -1370,7 +1370,7 @@ NEXT STEPS
|
|
|
1370
1370
|
1. Copy the DNS records shown in the output
|
|
1371
1371
|
2. Add them to your DNS provider (Cloudflare, Route53, etc.)
|
|
1372
1372
|
3. Wait for DNS propagation (up to 48 hours)
|
|
1373
|
-
4. Run: emailr domains verify <domain_id>`).option("--receiving-subdomain <subdomain>","Subdomain for receiving emails").option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let
|
|
1373
|
+
4. Run: emailr domains verify <domain_id>`).option("--receiving-subdomain <subdomain>","Subdomain for receiving emails").option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=m(),r=new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}),a={domain:t};e.receivingSubdomain&&(a.receivingSubdomain=e.receivingSubdomain);let n=await r.domains.add(a);if(e.format==="json")c(n,"json");else {if(d(`Domain added: ${n.domain}`),u("Add the following DNS records to verify your domain:"),console.log(""),n.dns_records){let s=[{Type:"DKIM",...Q(n.dns_records.dkim)},{Type:"SPF",...Q(n.dns_records.spf)},{Type:"DMARC",...Q(n.dns_records.dmarc)}];c(s,"table");}console.log(""),u(`Run 'emailr domains verify ${n.id}' after adding DNS records`);}}catch(o){l(o instanceof Error?o.message:"Failed to add domain"),process.exit(1);}}),i.command("verify <domain_id>").description(`Verify a domain
|
|
1374
1374
|
|
|
1375
1375
|
USAGE
|
|
1376
1376
|
emailr domains verify <domain_id> [options]
|
|
@@ -1408,7 +1408,7 @@ TROUBLESHOOTING
|
|
|
1408
1408
|
1. Run 'check-dns' to see which records are missing
|
|
1409
1409
|
2. Verify records are correctly configured with your DNS provider
|
|
1410
1410
|
3. Wait for DNS propagation (can take up to 48 hours)
|
|
1411
|
-
4. Try verification again`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let
|
|
1411
|
+
4. Try verification again`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=m(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).domains.verify(t);e.format==="json"?c(a,"json"):a.verified?d("Domain verified successfully!"):(u(`Domain status: ${a.status}`),a.dkim_status&&u(`DKIM status: ${a.dkim_status}`));}catch(o){l(o instanceof Error?o.message:"Failed to verify domain"),process.exit(1);}}),i.command("check-dns <domain_id>").description(`Check DNS records for a domain
|
|
1412
1412
|
|
|
1413
1413
|
USAGE
|
|
1414
1414
|
emailr domains check-dns <domain_id> [options]
|
|
@@ -1455,7 +1455,7 @@ COMMON ISSUES
|
|
|
1455
1455
|
|
|
1456
1456
|
Multiple records found:
|
|
1457
1457
|
- Remove duplicate TXT records
|
|
1458
|
-
- Keep only the Emailr-specific record`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let
|
|
1458
|
+
- Keep only the Emailr-specific record`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=m(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).domains.checkDns(t);if(e.format==="json")c(a,"json");else {let n=Object.entries(a).map(([s,p])=>({Record:s,Verified:p.verified,Expected:p.expected||"-",Found:p.found?.join(", ")||"-"}));c(n,"table");}}catch(o){l(o instanceof Error?o.message:"Failed to check DNS"),process.exit(1);}}),i.command("delete <domain_id>").description(`Delete a domain
|
|
1459
1459
|
|
|
1460
1460
|
USAGE
|
|
1461
1461
|
emailr domains delete <domain_id> [options]
|
|
@@ -1485,7 +1485,7 @@ WARNING
|
|
|
1485
1485
|
This action is permanent and cannot be undone.
|
|
1486
1486
|
- Emails from this domain will fail to send
|
|
1487
1487
|
- DNS records can be removed from your DNS provider
|
|
1488
|
-
- Re-add the domain if you need to restore functionality`).option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=m();await new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}).domains.delete(t),d(`Domain deleted: ${t}`);}catch(e){l(e instanceof Error?e.message:"Failed to delete domain"),process.exit(1);}}),i}function Q(i){return {"Record Type":i.type,Name:i.name,Value:i.value.length>50?i.value.substring(0,47)+"...":i.value,...i.priority!==void 0&&{Priority:i.priority}}}function
|
|
1488
|
+
- Re-add the domain if you need to restore functionality`).option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=m();await new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}).domains.delete(t),d(`Domain deleted: ${t}`);}catch(e){l(e instanceof Error?e.message:"Failed to delete domain"),process.exit(1);}}),i}function Q(i){return {"Record Type":i.type,Name:i.name,Value:i.value.length>50?i.value.substring(0,47)+"...":i.value,...i.priority!==void 0&&{Priority:i.priority}}}function _e(){let i=new Command("config").description(`Manage CLI configuration
|
|
1489
1489
|
|
|
1490
1490
|
USAGE
|
|
1491
1491
|
emailr config <subcommand> [options]
|
|
@@ -1578,7 +1578,7 @@ EXAMPLES
|
|
|
1578
1578
|
|
|
1579
1579
|
NOTE
|
|
1580
1580
|
Environment variables (EMAILR_API_KEY, EMAILR_BASE_URL) take precedence
|
|
1581
|
-
over config file values at runtime.`).action(async(t,e)=>{try{let
|
|
1581
|
+
over config file values at runtime.`).action(async(t,e)=>{try{let o=["api-key","base-url","format"],r=t.toLowerCase();o.includes(r)||(l(`Invalid config key: ${t}`),u(`Valid keys: ${o.join(", ")}`),process.exit(1));let n={"api-key":"apiKey","base-url":"baseUrl",format:"format"}[r];r==="format"&&!["json","table"].includes(e)&&(l(`Invalid format value: ${e}`),u("Valid formats: json, table"),process.exit(1)),G({[n]:e}),d(`Configuration saved: ${t} = ${r==="api-key"?"***":e}`),u(`Config file: ${I()}`);}catch(o){l(o instanceof Error?o.message:"Failed to save configuration"),process.exit(1);}}),i.command("get <key>").description(`Get a configuration value
|
|
1582
1582
|
|
|
1583
1583
|
USAGE
|
|
1584
1584
|
emailr config get <key>
|
|
@@ -1606,7 +1606,7 @@ EXAMPLES
|
|
|
1606
1606
|
emailr config get format
|
|
1607
1607
|
|
|
1608
1608
|
SEE ALSO
|
|
1609
|
-
emailr config list Show all configuration values`).action(async t=>{try{let e=["api-key","base-url","format"],
|
|
1609
|
+
emailr config list Show all configuration values`).action(async t=>{try{let e=["api-key","base-url","format"],o=t.toLowerCase();e.includes(o)||(l(`Invalid config key: ${t}`),u(`Valid keys: ${e.join(", ")}`),process.exit(1));let a={"api-key":"apiKey","base-url":"baseUrl",format:"format"}[o],n=ne(a);n?console.log(o==="api-key"?n.substring(0,8)+"..."+n.substring(n.length-4):n):u(`${t} is not set`);}catch(e){l(e instanceof Error?e.message:"Failed to get configuration"),process.exit(1);}}),i.command("list").description(`List all configuration values
|
|
1610
1610
|
|
|
1611
1611
|
USAGE
|
|
1612
1612
|
emailr config list [options]
|
|
@@ -1634,7 +1634,7 @@ EXAMPLES
|
|
|
1634
1634
|
|
|
1635
1635
|
SEE ALSO
|
|
1636
1636
|
emailr config get Get a single configuration value
|
|
1637
|
-
emailr config path Show config file location`).option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=m(),
|
|
1637
|
+
emailr config path Show config file location`).option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=m(),o={"api-key":e.apiKey?e.apiKey.substring(0,8)+"..."+e.apiKey.substring(e.apiKey.length-4):"(not set)","base-url":e.baseUrl||"(default)",format:e.format||"table"};if(t.format==="json")c(o,"json");else {let r=Object.entries(o).map(([a,n])=>({Key:a,Value:n}));c(r,"table");}console.log(""),u(`Config file: ${I()}`);}catch(e){e instanceof Error&&e.message.includes("No API key configured")?(u("No configuration found."),u("Run 'emailr config set api-key <your-api-key>' to get started.")):(l(e instanceof Error?e.message:"Failed to list configuration"),process.exit(1));}}),i.command("path").description(`Show the configuration file path
|
|
1638
1638
|
|
|
1639
1639
|
USAGE
|
|
1640
1640
|
emailr config path
|
|
@@ -1661,7 +1661,7 @@ EXAMPLES
|
|
|
1661
1661
|
open $(emailr config path)
|
|
1662
1662
|
|
|
1663
1663
|
# View config file contents
|
|
1664
|
-
cat $(emailr config path)`).action(()=>{console.log(
|
|
1664
|
+
cat $(emailr config path)`).action(()=>{console.log(I());}),i.command("init").description(`Initialize configuration interactively
|
|
1665
1665
|
|
|
1666
1666
|
USAGE
|
|
1667
1667
|
emailr config init [options]
|
|
@@ -1694,7 +1694,7 @@ ALTERNATIVE: ENVIRONMENT VARIABLES
|
|
|
1694
1694
|
|
|
1695
1695
|
SEE ALSO
|
|
1696
1696
|
emailr config set Set individual configuration values
|
|
1697
|
-
emailr config list View current configuration`).option("--api-key <key>","API key to use").option("--base-url <url>","Base URL for API").action(async t=>{try{t.apiKey?(G({apiKey:t.apiKey,baseUrl:t.baseUrl}),d("Configuration initialized!"),u(`Config file: ${
|
|
1697
|
+
emailr config list View current configuration`).option("--api-key <key>","API key to use").option("--base-url <url>","Base URL for API").action(async t=>{try{t.apiKey?(G({apiKey:t.apiKey,baseUrl:t.baseUrl}),d("Configuration initialized!"),u(`Config file: ${I()}`)):(u("Initialize your Emailr CLI configuration:"),console.log(""),u("Run with --api-key flag:"),console.log(" emailr config init --api-key <your-api-key>"),console.log(""),u("Or set environment variable:"),console.log(" export EMAILR_API_KEY=<your-api-key>"));}catch(e){l(e instanceof Error?e.message:"Failed to initialize configuration"),process.exit(1);}}),i}function je(){let i=new Command("broadcasts").description(`Manage broadcast campaigns
|
|
1698
1698
|
|
|
1699
1699
|
USAGE
|
|
1700
1700
|
emailr broadcasts <subcommand> [options]
|
|
@@ -1719,6 +1719,7 @@ SUBCOMMANDS
|
|
|
1719
1719
|
list List all broadcasts with optional status filter
|
|
1720
1720
|
get <id> Get broadcast details and delivery statistics
|
|
1721
1721
|
create Create a new broadcast campaign
|
|
1722
|
+
update <id> Update a draft or scheduled broadcast
|
|
1722
1723
|
send <id> Send a broadcast immediately
|
|
1723
1724
|
schedule <id> Schedule a broadcast for future delivery
|
|
1724
1725
|
cancel <id> Cancel a scheduled broadcast
|
|
@@ -1842,7 +1843,7 @@ EXAMPLES
|
|
|
1842
1843
|
emailr broadcasts list --format json
|
|
1843
1844
|
|
|
1844
1845
|
# Pipe JSON to jq for processing
|
|
1845
|
-
emailr broadcasts list --format json | jq '.[] | select(.status == "scheduled")'`).option("--status <status>","Filter by status (draft, scheduled, sending, sent)").option("--limit <number>","Number of broadcasts to return","20").option("--tags <tags>","Filter by tags (comma-separated)").option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=m(),
|
|
1846
|
+
emailr broadcasts list --format json | jq '.[] | select(.status == "scheduled")'`).option("--status <status>","Filter by status (draft, scheduled, sending, sent)").option("--limit <number>","Number of broadcasts to return","20").option("--tags <tags>","Filter by tags (comma-separated)").option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=m(),o=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),r={status:t.status,limit:parseInt(t.limit)};if(t.tags){let n=t.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean);n.length>0&&(r.tags=n.join(","));}let a=await o.broadcasts.list(r);if(t.format==="json")c(a,"json");else {if(a.length===0){console.log("No broadcasts found.");return}let n=a.map(s=>({ID:s.id,Name:s.name,Subject:s.subject.substring(0,30)+(s.subject.length>30?"...":""),Status:s.status,Tags:s.tags?.join(", ")||"-",Recipients:s.total_recipients||0,Sent:s.sent_count||0,Created:new Date(s.created_at).toLocaleDateString()}));c(n,"table");}}catch(e){l(e instanceof Error?e.message:"Failed to list broadcasts"),process.exit(1);}}),i.command("get <broadcast_id>").description(`Get broadcast details
|
|
1846
1847
|
|
|
1847
1848
|
USAGE
|
|
1848
1849
|
emailr broadcasts get <broadcast_id> [options]
|
|
@@ -1877,7 +1878,7 @@ EXAMPLES
|
|
|
1877
1878
|
emailr broadcasts get brd_abc123 --format json
|
|
1878
1879
|
|
|
1879
1880
|
# Pipe JSON to jq for processing
|
|
1880
|
-
emailr broadcasts get brd_abc123 --format json | jq '{sent: .sent_count, opened: .opened_count}'`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let
|
|
1881
|
+
emailr broadcasts get brd_abc123 --format json | jq '{sent: .sent_count, opened: .opened_count}'`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=m(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).broadcasts.get(t);e.format==="json"?c(a,"json"):c({ID:a.id,Name:a.name,Subject:a.subject,"From Email":a.from_email,Status:a.status,Tags:a.tags?.join(", ")||"-","Total Recipients":a.total_recipients||0,"Sent Count":a.sent_count||0,Delivered:a.delivered_count||0,Opened:a.opened_count||0,Clicked:a.clicked_count||0,Bounced:a.bounced_count||0,"Scheduled At":a.scheduled_at||"N/A","Started At":a.started_at||"N/A","Completed At":a.completed_at||"N/A","Created At":a.created_at},"table");}catch(o){l(o instanceof Error?o.message:"Failed to get broadcast"),process.exit(1);}}),i.command("create").description(`Create a new broadcast
|
|
1881
1882
|
|
|
1882
1883
|
USAGE
|
|
1883
1884
|
emailr broadcasts create --name <name> --subject <subject> --from <email> [options]
|
|
@@ -1953,7 +1954,7 @@ EXAMPLES
|
|
|
1953
1954
|
|
|
1954
1955
|
SEE ALSO
|
|
1955
1956
|
emailr templates Create and manage email templates
|
|
1956
|
-
emailr segments Create and manage contact segments`).requiredOption("--name <name>","Broadcast name").requiredOption("--subject <subject>","Email subject").requiredOption("--from <email>","Sender email address").option("--template <id>","Template ID to use").option("--segment <id>","Segment ID to target").option("--html <html>","HTML content").option("--text <text>","Plain text content").option("--schedule <datetime>","Schedule time (ISO 8601)").option("--tags <tags>","Comma-separated tags").option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=m(),
|
|
1957
|
+
emailr segments Create and manage contact segments`).requiredOption("--name <name>","Broadcast name").requiredOption("--subject <subject>","Email subject").requiredOption("--from <email>","Sender email address").option("--template <id>","Template ID to use").option("--segment <id>","Segment ID to target").option("--html <html>","HTML content").option("--text <text>","Plain text content").option("--schedule <datetime>","Schedule time (ISO 8601)").option("--tags <tags>","Comma-separated tags").option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=m(),o=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),r={name:t.name,subject:t.subject,from_email:t.from,template_id:t.template,segment_id:t.segment,html_content:t.html,text_content:t.text,scheduled_at:t.schedule};t.tags&&(r.tags=t.tags.split(",").map(n=>n.trim().toLowerCase()).filter(Boolean));let a=await o.broadcasts.create(r);t.format==="json"?c(a,"json"):(d("Broadcast created successfully!"),c({ID:a.id,Name:a.name,Status:a.status,Tags:a.tags?.join(", ")||"-","Scheduled At":a.scheduled_at||"Not scheduled"},"table"));}catch(e){l(e instanceof Error?e.message:"Failed to create broadcast"),process.exit(1);}}),i.command("update <broadcast_id>").description("Update a draft or scheduled broadcast").option("--name <name>","Broadcast name").option("--subject <subject>","Email subject").option("--from <email>","Sender email address").option("--template <id>","Template ID").option("--segment <id>","Segment ID").option("--html <html>","HTML content").option("--text <text>","Plain text content").option("--schedule <datetime>","Schedule time (ISO 8601)").option("--tags <tags>","Comma-separated tags").option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=m(),r=new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}),a={};e.name&&(a.name=e.name),e.subject&&(a.subject=e.subject),e.from&&(a.from_email=e.from),e.template&&(a.template_id=e.template),e.segment&&(a.segment_id=e.segment),e.html&&(a.html_content=e.html),e.text&&(a.text_content=e.text),e.schedule&&(a.scheduled_at=new Date(e.schedule).toISOString()),e.tags&&(a.tags=e.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean));let n=await r.broadcasts.update(t,a);e.format==="json"?c(n,"json"):(d("Broadcast updated successfully!"),c({ID:n.id,Name:n.name,Status:n.status,Tags:n.tags?.join(", ")||"-"},"table"));}catch(o){l(o instanceof Error?o.message:"Failed to update broadcast"),process.exit(1);}}),i.command("send <broadcast_id>").description(`Send a broadcast immediately
|
|
1957
1958
|
|
|
1958
1959
|
USAGE
|
|
1959
1960
|
emailr broadcasts send <broadcast_id> [options]
|
|
@@ -1986,7 +1987,7 @@ EXAMPLES
|
|
|
1986
1987
|
NOTE
|
|
1987
1988
|
Sending is asynchronous. The command returns when sending starts,
|
|
1988
1989
|
not when all emails are delivered. Use 'emailr broadcasts get' to
|
|
1989
|
-
check delivery progress.`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let
|
|
1990
|
+
check delivery progress.`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=m(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).broadcasts.send(t);e.format==="json"?c(a,"json"):(d("Broadcast sent successfully!"),c({Success:a.success,Sent:a.sent,Total:a.total},"table"));}catch(o){l(o instanceof Error?o.message:"Failed to send broadcast"),process.exit(1);}}),i.command("schedule <broadcast_id>").description(`Schedule a broadcast for future delivery
|
|
1990
1991
|
|
|
1991
1992
|
USAGE
|
|
1992
1993
|
emailr broadcasts schedule <broadcast_id> --at <datetime> [options]
|
|
@@ -2036,7 +2037,7 @@ EXAMPLES
|
|
|
2036
2037
|
emailr broadcasts schedule brd_abc123 --at "2024-12-25T10:00:00Z" --format json
|
|
2037
2038
|
|
|
2038
2039
|
SEE ALSO
|
|
2039
|
-
emailr broadcasts cancel Cancel a scheduled broadcast`).requiredOption("--at <datetime>","Schedule time (ISO 8601)").option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let
|
|
2040
|
+
emailr broadcasts cancel Cancel a scheduled broadcast`).requiredOption("--at <datetime>","Schedule time (ISO 8601)").option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=m(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).broadcasts.schedule(t,e.at);e.format==="json"?c(a,"json"):(d("Broadcast scheduled successfully!"),c({ID:a.id,Name:a.name,Status:a.status,"Scheduled At":a.scheduled_at},"table"));}catch(o){l(o instanceof Error?o.message:"Failed to schedule broadcast"),process.exit(1);}}),i.command("cancel <broadcast_id>").description(`Cancel a scheduled broadcast
|
|
2040
2041
|
|
|
2041
2042
|
USAGE
|
|
2042
2043
|
emailr broadcasts cancel <broadcast_id> [options]
|
|
@@ -2064,7 +2065,52 @@ EXAMPLES
|
|
|
2064
2065
|
emailr broadcasts cancel brd_abc123 --format json
|
|
2065
2066
|
|
|
2066
2067
|
NOTE
|
|
2067
|
-
Broadcasts that are already 'sending' or 'sent' cannot be cancelled.`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let
|
|
2068
|
+
Broadcasts that are already 'sending' or 'sent' cannot be cancelled.`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=m(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).broadcasts.cancel(t);e.format==="json"?c(a,"json"):d("Broadcast cancelled successfully!");}catch(o){l(o instanceof Error?o.message:"Failed to cancel broadcast"),process.exit(1);}}),i.command("update <broadcast_id>").description(`Update a broadcast
|
|
2069
|
+
|
|
2070
|
+
USAGE
|
|
2071
|
+
emailr broadcasts update <broadcast_id> [options]
|
|
2072
|
+
|
|
2073
|
+
DESCRIPTION
|
|
2074
|
+
Updates a broadcast that has not been sent yet (draft or scheduled status).
|
|
2075
|
+
Only the fields you specify will be updated; all others remain unchanged.
|
|
2076
|
+
|
|
2077
|
+
ARGUMENTS
|
|
2078
|
+
<broadcast_id> The unique broadcast identifier (e.g., brd_abc123)
|
|
2079
|
+
|
|
2080
|
+
OPTIONS
|
|
2081
|
+
--name <name> Update broadcast name
|
|
2082
|
+
--subject <subject> Update email subject line
|
|
2083
|
+
--from <email> Update sender email address
|
|
2084
|
+
--template <id> Update template ID (use "none" to clear)
|
|
2085
|
+
--segment <id> Update segment ID (use "none" to clear)
|
|
2086
|
+
--topic <id> Update topic ID (use "none" to clear)
|
|
2087
|
+
--html <html> Update HTML content
|
|
2088
|
+
--text <text> Update plain text content
|
|
2089
|
+
--schedule <datetime> Update schedule time (ISO 8601, use "none" to clear)
|
|
2090
|
+
--tags <tags> Update tags (comma-separated, replaces existing)
|
|
2091
|
+
--format <format> Output format: json | table (default: table)
|
|
2092
|
+
|
|
2093
|
+
EXAMPLES
|
|
2094
|
+
# Update broadcast name and subject
|
|
2095
|
+
emailr broadcasts update brd_abc123 --name "New Name" --subject "New Subject"
|
|
2096
|
+
|
|
2097
|
+
# Change the template
|
|
2098
|
+
emailr broadcasts update brd_abc123 --template tpl_xyz789
|
|
2099
|
+
|
|
2100
|
+
# Clear the template (use inline content instead)
|
|
2101
|
+
emailr broadcasts update brd_abc123 --template none --html "<p>New content</p>"
|
|
2102
|
+
|
|
2103
|
+
# Reschedule a broadcast
|
|
2104
|
+
emailr broadcasts update brd_abc123 --schedule "2024-12-25T10:00:00Z"
|
|
2105
|
+
|
|
2106
|
+
# Update tags
|
|
2107
|
+
emailr broadcasts update brd_abc123 --tags "newsletter,weekly"
|
|
2108
|
+
|
|
2109
|
+
# Get JSON output
|
|
2110
|
+
emailr broadcasts update brd_abc123 --name "Updated" --format json
|
|
2111
|
+
|
|
2112
|
+
NOTE
|
|
2113
|
+
Only broadcasts in 'draft' or 'scheduled' status can be updated.`).option("--name <name>","Broadcast name").option("--subject <subject>","Email subject").option("--from <email>","Sender email address").option("--template <id>",'Template ID (use "none" to clear)').option("--segment <id>",'Segment ID (use "none" to clear)').option("--topic <id>",'Topic ID (use "none" to clear)').option("--html <html>","HTML content").option("--text <text>","Plain text content").option("--schedule <datetime>",'Schedule time ISO 8601 (use "none" to clear)').option("--tags <tags>","Comma-separated tags (replaces existing)").option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=m(),r=new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}),a={};e.name&&(a.name=e.name),e.subject&&(a.subject=e.subject),e.from&&(a.from_email=e.from),e.html&&(a.html_content=e.html),e.text&&(a.text_content=e.text),e.template&&(a.template_id=e.template==="none"?null:e.template),e.segment&&(a.segment_id=e.segment==="none"?null:e.segment),e.topic&&(a.topic_id=e.topic==="none"?null:e.topic),e.schedule&&(a.scheduled_at=e.schedule==="none"?null:e.schedule),e.tags&&(a.tags=e.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean)),Object.keys(a).length===0&&(l("No update fields specified. Use --help to see available options."),process.exit(1));let n=await r.broadcasts.update(t,a);e.format==="json"?c(n,"json"):(d("Broadcast updated successfully!"),c({ID:n.id,Name:n.name,Subject:n.subject,Status:n.status,Tags:n.tags?.join(", ")||"-","Scheduled At":n.scheduled_at||"Not scheduled"},"table"));}catch(o){l(o instanceof Error?o.message:"Failed to update broadcast"),process.exit(1);}}),i.command("delete <broadcast_id>").description(`Delete a broadcast
|
|
2068
2114
|
|
|
2069
2115
|
USAGE
|
|
2070
2116
|
emailr broadcasts delete <broadcast_id> [options]
|
|
@@ -2092,7 +2138,7 @@ EXAMPLES
|
|
|
2092
2138
|
|
|
2093
2139
|
WARNING
|
|
2094
2140
|
This action is permanent and cannot be undone.
|
|
2095
|
-
All delivery statistics will be lost.`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let
|
|
2141
|
+
All delivery statistics will be lost.`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=m(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).broadcasts.delete(t);e.format==="json"?c(a,"json"):d("Broadcast deleted successfully!");}catch(o){l(o instanceof Error?o.message:"Failed to delete broadcast"),process.exit(1);}}),i}function Ne(){let i=new Command("webhooks").description(`Manage webhooks
|
|
2096
2142
|
|
|
2097
2143
|
USAGE
|
|
2098
2144
|
emailr webhooks <subcommand> [options]
|
|
@@ -2245,7 +2291,7 @@ EXAMPLES
|
|
|
2245
2291
|
emailr webhooks list --format json | jq '.[] | select(.active == true)'
|
|
2246
2292
|
|
|
2247
2293
|
# Count webhooks
|
|
2248
|
-
emailr webhooks list --format json | jq 'length'`).option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=m(),r=await new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}).webhooks.list();if(t.format==="json")c(r,"json");else {if(r.data.length===0){console.log("No webhooks found.");return}let
|
|
2294
|
+
emailr webhooks list --format json | jq 'length'`).option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=m(),r=await new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}).webhooks.list();if(t.format==="json")c(r,"json");else {if(r.data.length===0){console.log("No webhooks found.");return}let a=r.data.map(n=>({ID:n.id,Name:n.name,URL:n.url.substring(0,40)+(n.url.length>40?"...":""),Events:n.events.join(", "),Active:n.active?"Yes":"No"}));c(a,"table");}}catch(e){l(e instanceof Error?e.message:"Failed to list webhooks"),process.exit(1);}}),i.command("get <webhook_id>").description(`Get webhook details
|
|
2249
2295
|
|
|
2250
2296
|
USAGE
|
|
2251
2297
|
emailr webhooks get <webhook_id> [options]
|
|
@@ -2276,7 +2322,7 @@ EXAMPLES
|
|
|
2276
2322
|
emailr webhooks get whk_abc123 --format json
|
|
2277
2323
|
|
|
2278
2324
|
# Extract just the secret
|
|
2279
|
-
emailr webhooks get whk_abc123 --format json | jq -r '.secret'`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let
|
|
2325
|
+
emailr webhooks get whk_abc123 --format json | jq -r '.secret'`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=m(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).webhooks.get(t);e.format==="json"?c(a,"json"):c({ID:a.id,Name:a.name,URL:a.url,Events:a.events.join(", "),Active:a.active?"Yes":"No",Secret:a.secret,"Created At":a.created_at},"table");}catch(o){l(o instanceof Error?o.message:"Failed to get webhook"),process.exit(1);}}),i.command("create").description(`Create a new webhook
|
|
2280
2326
|
|
|
2281
2327
|
USAGE
|
|
2282
2328
|
emailr webhooks create --name <name> --url <url> --events <events> [options]
|
|
@@ -2350,7 +2396,7 @@ EXAMPLES
|
|
|
2350
2396
|
|
|
2351
2397
|
NOTE
|
|
2352
2398
|
Save the webhook secret returned by this command. You'll need it
|
|
2353
|
-
to verify webhook signatures in your endpoint.`).requiredOption("--name <name>","Webhook name").requiredOption("--url <url>","Webhook URL").requiredOption("--events <events>","Events to subscribe to (comma-separated)").option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=m(),
|
|
2399
|
+
to verify webhook signatures in your endpoint.`).requiredOption("--name <name>","Webhook name").requiredOption("--url <url>","Webhook URL").requiredOption("--events <events>","Events to subscribe to (comma-separated)").option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=m(),o=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),r=t.events.split(",").map(n=>n.trim()),a=await o.webhooks.create({name:t.name,url:t.url,events:r});t.format==="json"?c(a,"json"):(d("Webhook created successfully!"),c({ID:a.id,Name:a.name,URL:a.url,Secret:a.secret},"table"));}catch(e){l(e instanceof Error?e.message:"Failed to create webhook"),process.exit(1);}}),i.command("update <webhook_id>").description(`Update a webhook
|
|
2354
2400
|
|
|
2355
2401
|
USAGE
|
|
2356
2402
|
emailr webhooks update <webhook_id> [options]
|
|
@@ -2395,7 +2441,7 @@ EXAMPLES
|
|
|
2395
2441
|
--events "email.delivered,email.bounced"
|
|
2396
2442
|
|
|
2397
2443
|
# Get JSON output
|
|
2398
|
-
emailr webhooks update whk_abc123 --name "New Name" --format json`).option("--name <name>","New webhook name").option("--url <url>","New webhook URL").option("--events <events>","New events (comma-separated)").option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let
|
|
2444
|
+
emailr webhooks update whk_abc123 --name "New Name" --format json`).option("--name <name>","New webhook name").option("--url <url>","New webhook URL").option("--events <events>","New events (comma-separated)").option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=m(),r=new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}),a={};e.name&&(a.name=e.name),e.url&&(a.url=e.url),e.events&&(a.events=e.events.split(",").map(s=>s.trim()));let n=await r.webhooks.update(t,a);e.format==="json"?c(n,"json"):(d("Webhook updated successfully!"),c({ID:n.id,Name:n.name,URL:n.url},"table"));}catch(o){l(o instanceof Error?o.message:"Failed to update webhook"),process.exit(1);}}),i.command("enable <webhook_id>").description(`Enable a webhook
|
|
2399
2445
|
|
|
2400
2446
|
USAGE
|
|
2401
2447
|
emailr webhooks enable <webhook_id> [options]
|
|
@@ -2419,7 +2465,7 @@ EXAMPLES
|
|
|
2419
2465
|
emailr webhooks enable whk_abc123
|
|
2420
2466
|
|
|
2421
2467
|
# Get JSON output
|
|
2422
|
-
emailr webhooks enable whk_abc123 --format json`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let
|
|
2468
|
+
emailr webhooks enable whk_abc123 --format json`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=m(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).webhooks.enable(t);e.format==="json"?c(a,"json"):d("Webhook enabled successfully!");}catch(o){l(o instanceof Error?o.message:"Failed to enable webhook"),process.exit(1);}}),i.command("disable <webhook_id>").description(`Disable a webhook
|
|
2423
2469
|
|
|
2424
2470
|
USAGE
|
|
2425
2471
|
emailr webhooks disable <webhook_id> [options]
|
|
@@ -2448,7 +2494,7 @@ EXAMPLES
|
|
|
2448
2494
|
|
|
2449
2495
|
NOTE
|
|
2450
2496
|
Events are not queued while webhook is disabled. If you need to
|
|
2451
|
-
temporarily stop processing, consider handling this in your endpoint.`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let
|
|
2497
|
+
temporarily stop processing, consider handling this in your endpoint.`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=m(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).webhooks.disable(t);e.format==="json"?c(a,"json"):d("Webhook disabled successfully!");}catch(o){l(o instanceof Error?o.message:"Failed to disable webhook"),process.exit(1);}}),i.command("delete <webhook_id>").description(`Delete a webhook
|
|
2452
2498
|
|
|
2453
2499
|
USAGE
|
|
2454
2500
|
emailr webhooks delete <webhook_id> [options]
|
|
@@ -2476,7 +2522,7 @@ EXAMPLES
|
|
|
2476
2522
|
|
|
2477
2523
|
WARNING
|
|
2478
2524
|
This action is permanent and cannot be undone.
|
|
2479
|
-
Create a new webhook if you need to restore functionality.`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let
|
|
2525
|
+
Create a new webhook if you need to restore functionality.`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=m(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).webhooks.delete(t);e.format==="json"?c(a,"json"):d("Webhook deleted successfully!");}catch(o){l(o instanceof Error?o.message:"Failed to delete webhook"),process.exit(1);}}),i}function Ie(){let i=new Command("segments").description(`Manage contact segments
|
|
2480
2526
|
|
|
2481
2527
|
USAGE
|
|
2482
2528
|
emailr segments <subcommand> [options]
|
|
@@ -2615,7 +2661,7 @@ EXAMPLES
|
|
|
2615
2661
|
emailr segments list --format json
|
|
2616
2662
|
|
|
2617
2663
|
# Pipe JSON to jq for processing
|
|
2618
|
-
emailr segments list --format json | jq '.[].name'`).option("--tags <tags>","Filter by tags (comma-separated)").option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=m(),
|
|
2664
|
+
emailr segments list --format json | jq '.[].name'`).option("--tags <tags>","Filter by tags (comma-separated)").option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=m(),o=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),r={};if(t.tags){let n=t.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean);n.length>0&&(r.tags=n.join(","));}let a=await o.segments.list(r);if(t.format==="json")c(a,"json");else {if(a.length===0){console.log("No segments found.");return}let n=a.map(s=>({ID:s.id,Name:s.name,Description:(s.description||"").substring(0,30)+((s.description?.length||0)>30?"...":""),Tags:s.tags?.join(", ")||"-","Created At":new Date(s.created_at).toLocaleDateString()}));c(n,"table");}}catch(e){l(e instanceof Error?e.message:"Failed to list segments"),process.exit(1);}}),i.command("get <segment_id>").description(`Get segment details
|
|
2619
2665
|
|
|
2620
2666
|
USAGE
|
|
2621
2667
|
emailr segments get <segment_id> [options]
|
|
@@ -2642,7 +2688,7 @@ EXAMPLES
|
|
|
2642
2688
|
emailr segments get seg_abc123 --format json
|
|
2643
2689
|
|
|
2644
2690
|
# Pipe JSON to jq to view conditions
|
|
2645
|
-
emailr segments get seg_abc123 --format json | jq '.conditions'`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let
|
|
2691
|
+
emailr segments get seg_abc123 --format json | jq '.conditions'`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=m(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).segments.get(t);e.format==="json"?c(a,"json"):c({ID:a.id,Name:a.name,Description:a.description||"N/A",Conditions:JSON.stringify(a.conditions),Tags:a.tags?.join(", ")||"-","Created At":a.created_at,"Updated At":a.updated_at},"table");}catch(o){l(o instanceof Error?o.message:"Failed to get segment"),process.exit(1);}}),i.command("create").description(`Create a new segment
|
|
2646
2692
|
|
|
2647
2693
|
USAGE
|
|
2648
2694
|
emailr segments create --name <segment_name> --conditions <json> [options]
|
|
@@ -2691,7 +2737,7 @@ EXAMPLES
|
|
|
2691
2737
|
# Get JSON output for scripting
|
|
2692
2738
|
emailr segments create --name "Test" \\
|
|
2693
2739
|
--conditions '[{"field": "subscribed", "operator": "equals", "value": true}]' \\
|
|
2694
|
-
--format json`).requiredOption("--name <name>","Segment name").requiredOption("--conditions <json>","Segment conditions as JSON").option("--description <description>","Segment description").option("--tags <tags>","Comma-separated tags").option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=m(),
|
|
2740
|
+
--format json`).requiredOption("--name <name>","Segment name").requiredOption("--conditions <json>","Segment conditions as JSON").option("--description <description>","Segment description").option("--tags <tags>","Comma-separated tags").option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=m(),o=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),r;try{r=JSON.parse(t.conditions);}catch{l("Invalid JSON for --conditions"),process.exit(1);}let a={name:t.name,description:t.description,conditions:r};t.tags&&(a.tags=t.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean));let n=await o.segments.create(a);t.format==="json"?c(n,"json"):(d("Segment created successfully!"),c({ID:n.id,Name:n.name,Tags:n.tags?.join(", ")||"-"},"table"));}catch(e){l(e instanceof Error?e.message:"Failed to create segment"),process.exit(1);}}),i.command("update <segment_id>").description(`Update a segment
|
|
2695
2741
|
|
|
2696
2742
|
USAGE
|
|
2697
2743
|
emailr segments update <segment_id> [options]
|
|
@@ -2736,7 +2782,7 @@ EXAMPLES
|
|
|
2736
2782
|
--conditions '[{"field": "metadata.plan", "operator": "equals", "value": "enterprise"}]'
|
|
2737
2783
|
|
|
2738
2784
|
# Get JSON output
|
|
2739
|
-
emailr segments update seg_abc123 --name "Updated" --format json`).option("--name <name>","New segment name").option("--description <description>","New description").option("--conditions <json>","New conditions as JSON").option("--tags <tags>","Comma-separated tags").option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let
|
|
2785
|
+
emailr segments update seg_abc123 --name "Updated" --format json`).option("--name <name>","New segment name").option("--description <description>","New description").option("--conditions <json>","New conditions as JSON").option("--tags <tags>","Comma-separated tags").option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=m(),r=new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}),a={};if(e.name&&(a.name=e.name),e.description&&(a.description=e.description),e.conditions)try{a.conditions=JSON.parse(e.conditions);}catch{l("Invalid JSON for --conditions"),process.exit(1);}e.tags&&(a.tags=e.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean));let n=await r.segments.update(t,a);e.format==="json"?c(n,"json"):(d("Segment updated successfully!"),c({ID:n.id,Name:n.name,Tags:n.tags?.join(", ")||"-"},"table"));}catch(o){l(o instanceof Error?o.message:"Failed to update segment"),process.exit(1);}}),i.command("delete <segment_id>").description(`Delete a segment
|
|
2740
2786
|
|
|
2741
2787
|
USAGE
|
|
2742
2788
|
emailr segments delete <segment_id>
|
|
@@ -2761,7 +2807,7 @@ EXAMPLES
|
|
|
2761
2807
|
|
|
2762
2808
|
WARNING
|
|
2763
2809
|
This action is permanent and cannot be undone.
|
|
2764
|
-
Any broadcasts targeting this segment will need to be updated.`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let
|
|
2810
|
+
Any broadcasts targeting this segment will need to be updated.`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=m(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).segments.delete(t);e.format==="json"?c(a,"json"):d("Segment deleted successfully!");}catch(o){l(o instanceof Error?o.message:"Failed to delete segment"),process.exit(1);}}),i.command("count <segment_id>").description(`Get the number of contacts in a segment
|
|
2765
2811
|
|
|
2766
2812
|
USAGE
|
|
2767
2813
|
emailr segments count <segment_id> [options]
|
|
@@ -2792,7 +2838,7 @@ EXAMPLES
|
|
|
2792
2838
|
|
|
2793
2839
|
TIP
|
|
2794
2840
|
Use this before sending broadcasts to verify your segment
|
|
2795
|
-
targets the expected number of contacts.`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let
|
|
2841
|
+
targets the expected number of contacts.`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=m(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).segments.getContactsCount(t);e.format==="json"?c(a,"json"):console.log(`Segment contains ${a.count} contacts.`);}catch(o){l(o instanceof Error?o.message:"Failed to get segment count"),process.exit(1);}}),i}function st(i){try{let t=i.startsWith("http")?i:`http://localhost${i}`,e=new URL(t);return {key:e.searchParams.get("key")??void 0,code:e.searchParams.get("code")??void 0,state:e.searchParams.get("state")??void 0,error:e.searchParams.get("error")??void 0,message:e.searchParams.get("message")??void 0}}catch{return {}}}function lt(){return `<!DOCTYPE html>
|
|
2796
2842
|
<html lang="en">
|
|
2797
2843
|
<head>
|
|
2798
2844
|
<meta charset="UTF-8">
|
|
@@ -2893,7 +2939,7 @@ TIP
|
|
|
2893
2939
|
<p style="margin-top: 1rem;">Please close this window and try again.</p>
|
|
2894
2940
|
</div>
|
|
2895
2941
|
</body>
|
|
2896
|
-
</html>`}function
|
|
2942
|
+
</html>`}function ke(){let i=null,t=0,e=null,o=null,r=null;return {async start(){return new Promise((a,n)=>{i=Je.createServer((s,p)=>{if(s.method!=="GET"||!s.url?.startsWith("/callback")){p.writeHead(404,{"Content-Type":"text/plain"}),p.end("Not Found");return}let b=st(s.url);if(r&&b.state!==r){p.writeHead(400,{"Content-Type":"text/html"}),p.end(ee("Security verification failed. State parameter mismatch.")),e&&e({success:false,error:"State parameter mismatch"});return}if(b.error){let h=b.message||b.error;p.writeHead(200,{"Content-Type":"text/html"}),p.end(ee(h)),e&&e({success:false,error:h});return}let T=b.key||b.code;if(T){p.writeHead(200,{"Content-Type":"text/html"}),p.end(lt()),e&&e({success:true,apiKey:T});return}p.writeHead(400,{"Content-Type":"text/html"}),p.end(ee("Invalid callback: missing required parameters.")),e&&e({success:false,error:"Invalid callback: missing required parameters"});}),i.listen(0,"127.0.0.1",()=>{let s=i.address();s&&typeof s=="object"?(t=s.port,a({port:t,url:`http://127.0.0.1:${t}/callback`})):n(new Error("Failed to get server address"));}),i.on("error",s=>{n(new Error(`Failed to start callback server: ${s.message}`));});})},async waitForCallback(a,n){return r=a,new Promise(s=>{e=s,o=setTimeout(()=>{e&&e({success:false,error:"Login timed out. Please try again."});},n);})},async stop(){if(o&&(clearTimeout(o),o=null),i)return new Promise(a=>{i.close(()=>{i=null,a();});})}}}function Ce(){return ct.randomBytes(32).toString("hex")}function Ue(i){return new Promise(t=>{let e=process.platform,o;switch(e){case "darwin":o=`open "${i}"`;break;case "win32":o=`start "" "${i}"`;break;default:o=`xdg-open "${i}"`;break}exec(o,r=>{t(!r);});})}var $=120,pt=process.env.EMAILR_WEB_URL||"https://app.emailr.dev";function ut(i,t){let e=`http://127.0.0.1:${t}/callback`,o=new URLSearchParams({state:i,callback_url:e});return `${pt}/consent/authorize?${o.toString()}`}function Pe(){return new Command("login").description("Log in to Emailr via browser authentication").option("-t, --timeout <seconds>","Timeout in seconds",String($)).option("--no-browser","Don't automatically open the browser").action(async t=>{await ft({timeout:parseInt(t.timeout,10)||$,noBrowser:t.browser===false});})}async function ft(i){let t=ke(),e=(i.timeout||$)*1e3;try{u("Starting authentication server...");let{port:o,url:r}=await t.start(),a=Ce(),n=ut(a,o);console.log(""),u("Authorization URL:"),console.log(` ${n}`),console.log(""),i.noBrowser?u("Please open the URL above in your browser to continue."):await Ue(n)?u("Browser opened. Please complete authentication in your browser."):(k("Could not open browser automatically."),u("Please open the URL above in your browser to continue.")),console.log(""),u(`Waiting for authentication (timeout: ${i.timeout||$}s)...`);let s=await t.waitForCallback(a,e);s.success&&s.apiKey?(G({apiKey:s.apiKey}),console.log(""),d("Login successful!"),u(`API key saved to: ${I()}`),u("You can now use the Emailr CLI.")):(console.log(""),l(s.error||"Authentication failed."),u("Please try again or use manual configuration:"),console.log(" emailr config set api-key <your-api-key>"),process.exit(1));}catch(o){console.log(""),l(o instanceof Error?o.message:"An unexpected error occurred."),u("Please try again or use manual configuration:"),console.log(" emailr config set api-key <your-api-key>"),process.exit(1);}finally{await t.stop();}}var ae=_.join(B.homedir(),".config","opencode","skills","emailr-cli"),wt=`---
|
|
2897
2943
|
name: emailr-cli
|
|
2898
2944
|
description: Operate the Emailr CLI to send emails, manage contacts, templates, domains, broadcasts, webhooks, and segments. Includes LIVE PREVIEW editing for templates with hot-reload.
|
|
2899
2945
|
---
|
|
@@ -2933,7 +2979,7 @@ IMPORTANT: Always use \`--background\` flag so the command returns immediately a
|
|
|
2933
2979
|
- Create: \`emailr templates create --name "Name" --subject "Subject" --html-file ./template.html\`
|
|
2934
2980
|
- Update: \`emailr templates update <id> --html-file ./template.html\`
|
|
2935
2981
|
- Delete: \`emailr templates delete <id>\`
|
|
2936
|
-
`;function yt(){try{return execSync("which opencode",{stdio:"ignore"}),!0}catch{return false}}function St(){console.log("Installing OpenCode AI agent...");try{return execSync("npm install -g opencode-ai@latest",{stdio:"inherit"}),!0}catch{if(process.platform==="darwin")try{return execSync("brew install anomalyco/tap/opencode",{stdio:"inherit"}),!0}catch{return false}return false}}function vt(){v.existsSync(ae)||v.mkdirSync(ae,{recursive:true});let i=
|
|
2982
|
+
`;function yt(){try{return execSync("which opencode",{stdio:"ignore"}),!0}catch{return false}}function St(){console.log("Installing OpenCode AI agent...");try{return execSync("npm install -g opencode-ai@latest",{stdio:"inherit"}),!0}catch{if(process.platform==="darwin")try{return execSync("brew install anomalyco/tap/opencode",{stdio:"inherit"}),!0}catch{return false}return false}}function vt(){v.existsSync(ae)||v.mkdirSync(ae,{recursive:true});let i=_.join(ae,"SKILL.md");v.writeFileSync(i,wt,"utf-8");}function xe(){return new Command("agent").description(`Launch an AI agent with Emailr CLI expertise
|
|
2937
2983
|
|
|
2938
2984
|
This opens OpenCode (opencode.ai), an AI coding agent that knows how to use all Emailr CLI commands.
|
|
2939
2985
|
The agent can help you:
|
|
@@ -2942,9 +2988,9 @@ The agent can help you:
|
|
|
2942
2988
|
- Configure domains and webhooks
|
|
2943
2989
|
|
|
2944
2990
|
The agent runs in your terminal with full access to the emailr CLI.`).option("--install","Install OpenCode if not already installed").option("--model <model>","Model to use (e.g., anthropic/claude-sonnet-4)").action(async t=>{yt()||(t.install?St()||(l("Failed to install OpenCode. Please install manually:"),console.log(" npm install -g opencode-ai@latest"),console.log(" # or"),console.log(" brew install anomalyco/tap/opencode"),process.exit(1)):(l("OpenCode AI agent is not installed."),console.log(`
|
|
2945
|
-
Install it with one of:`),console.log(" emailr agent --install"),console.log(" npm install -g opencode-ai@latest"),console.log(" brew install anomalyco/tap/opencode"),process.exit(1)));try{vt(),d("Emailr CLI skill loaded");}catch(r){
|
|
2991
|
+
Install it with one of:`),console.log(" emailr agent --install"),console.log(" npm install -g opencode-ai@latest"),console.log(" brew install anomalyco/tap/opencode"),process.exit(1)));try{vt(),d("Emailr CLI skill loaded");}catch(r){k(`Could not install skill: ${r instanceof Error?r.message:String(r)}`);}let e=[];t.model&&e.push("--model",t.model),console.log(`
|
|
2946
2992
|
Starting Emailr AI Agent...`),console.log("The agent has the emailr-cli skill loaded."),console.log(`Ask it to help with emails, templates, contacts, or broadcasts.
|
|
2947
|
-
`);let
|
|
2993
|
+
`);let o=spawn("opencode",e,{stdio:"inherit",env:process.env});o.on("error",r=>{l(`Failed to start agent: ${r.message}`),process.exit(1);}),o.on("exit",r=>{process.exit(r??0);});})}var g=new Command;g.name("emailr").description(`Emailr CLI - Send emails and manage your email infrastructure
|
|
2948
2994
|
|
|
2949
2995
|
USAGE
|
|
2950
2996
|
emailr <command> [subcommand] [options]
|
|
@@ -3030,4 +3076,4 @@ AGENTIC WORKFLOW
|
|
|
3030
3076
|
|
|
3031
3077
|
MORE INFORMATION
|
|
3032
3078
|
Run 'emailr <command> --help' for detailed help on any command.
|
|
3033
|
-
Run 'emailr <command> <subcommand> --help' for subcommand details.`).version("1.5.4");g.addCommand(ce());g.addCommand(me());g.addCommand(Oe());g.addCommand(Ee());g.addCommand(
|
|
3079
|
+
Run 'emailr <command> <subcommand> --help' for subcommand details.`).version("1.5.4");g.addCommand(ce());g.addCommand(me());g.addCommand(Oe());g.addCommand(Ee());g.addCommand(je());g.addCommand(Ne());g.addCommand(Ie());g.addCommand(_e());g.addCommand(Pe());g.addCommand(xe());g.parse();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "emailr-cli",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.2",
|
|
4
4
|
"description": "Command-line interface for the Emailr email API",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"chalk": "^5.3.0",
|
|
24
24
|
"cli-table3": "^0.6.3",
|
|
25
25
|
"commander": "^12.0.0",
|
|
26
|
-
"emailr": "^1.3.
|
|
26
|
+
"emailr": "^1.3.1",
|
|
27
27
|
"open": "^11.0.0"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|