emailr-cli 1.10.0 → 1.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +112 -103
  2. 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 x,{readFileSync}from'fs';import V from'os';import E from'path';import de from'cli-table3';import T from'chalk';import at from'http';import {URL}from'url';import vt from'crypto';import {spawn,execSync,exec}from'child_process';var We=[E.join(V.homedir(),".emailrrc"),E.join(V.homedir(),".config","emailr","config.json")];function d(){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 o of We)if(x.existsSync(o))try{let a=x.readFileSync(o,"utf-8"),e=JSON.parse(a);if(e.apiKey)return {apiKey:e.apiKey,baseUrl:e.baseUrl,format:e.format||"table"}}catch{}throw new Error(`No API key configured.
2
+ import {Command}from'commander';import {Emailr}from'emailr';import x,{readFileSync}from'fs';import V from'os';import E from'path';import de from'cli-table3';import T from'chalk';import at from'http';import {URL}from'url';import vt from'crypto';import {spawn,execSync,exec}from'child_process';var We=[E.join(V.homedir(),".emailrrc"),E.join(V.homedir(),".config","emailr","config.json")];function d(){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 We)if(x.existsSync(i))try{let a=x.readFileSync(i,"utf-8"),e=JSON.parse(a);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 I(){let o=E.join(V.homedir(),".config","emailr");return E.join(o,"config.json")}function K(o){let a=I(),e=E.dirname(a);x.existsSync(e)||x.mkdirSync(e,{recursive:true});let t={};if(x.existsSync(a))try{t=JSON.parse(x.readFileSync(a,"utf-8"));}catch{}let n={...t,...o};x.writeFileSync(a,JSON.stringify(n,null,2)+`
11
- `);}function ce(o){try{return d()[o]?.toString()}catch{return}}function m(o,a="table"){a==="json"?console.log(JSON.stringify(o,null,2)):Xe(o);}function Xe(o){Array.isArray(o)?Ve(o):typeof o=="object"&&o!==null?ze(o):console.log(o);}function Ve(o){if(o.length===0){console.log(T.gray("No results"));return}let a=o[0];if(typeof a!="object"||a===null){o.forEach(n=>console.log(n));return}let e=Object.keys(a),t=new de({head:e.map(n=>T.cyan(n)),style:{head:[],border:[]}});for(let n of o){let i=e.map(r=>{let s=n[r];return pe(s)});t.push(i);}console.log(t.toString());}function ze(o){let a=new de({style:{head:[],border:[]}});for(let[e,t]of Object.entries(o))a.push([T.cyan(e),pe(t)]);console.log(a.toString());}function pe(o){return o==null?T.gray("-"):typeof o=="boolean"?o?T.green("\u2713"):T.red("\u2717"):typeof o=="object"?JSON.stringify(o):String(o)}function p(o){console.log(T.green("\u2713"),o);}function l(o){console.error(T.red("\u2717"),o);}function N(o){console.warn(T.yellow("\u26A0"),o);}function u(o){console.log(T.blue("\u2139"),o);}function fe(){return new Command("send").description(`Send an email
10
+ Or run: emailr config set api-key <your-api-key>`)}function I(){let i=E.join(V.homedir(),".config","emailr");return E.join(i,"config.json")}function K(i){let a=I(),e=E.dirname(a);x.existsSync(e)||x.mkdirSync(e,{recursive:true});let o={};if(x.existsSync(a))try{o=JSON.parse(x.readFileSync(a,"utf-8"));}catch{}let n={...o,...i};x.writeFileSync(a,JSON.stringify(n,null,2)+`
11
+ `);}function ce(i){try{return d()[i]?.toString()}catch{return}}function m(i,a="table"){a==="json"?console.log(JSON.stringify(i,null,2)):Xe(i);}function Xe(i){Array.isArray(i)?Ve(i):typeof i=="object"&&i!==null?ze(i):console.log(i);}function Ve(i){if(i.length===0){console.log(T.gray("No results"));return}let a=i[0];if(typeof a!="object"||a===null){i.forEach(n=>console.log(n));return}let e=Object.keys(a),o=new de({head:e.map(n=>T.cyan(n)),style:{head:[],border:[]}});for(let n of i){let t=e.map(r=>{let s=n[r];return pe(s)});o.push(t);}console.log(o.toString());}function ze(i){let a=new de({style:{head:[],border:[]}});for(let[e,o]of Object.entries(i))a.push([T.cyan(e),pe(o)]);console.log(a.toString());}function pe(i){return i==null?T.gray("-"):typeof i=="boolean"?i?T.green("\u2713"):T.red("\u2717"):typeof i=="object"?JSON.stringify(i):String(i)}function p(i){console.log(T.green("\u2713"),i);}function l(i){console.error(T.red("\u2717"),i);}function N(i){console.warn(T.yellow("\u26A0"),i);}function u(i){console.log(T.blue("\u2139"),i);}function fe(){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 a=>{try{let e=d(),t=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),n=a.to.split(",").map(s=>s.trim()),i={to:n.length===1?n[0]:n};if(a.from&&(i.from=a.from),a.subject&&(i.subject=a.subject),a.htmlFile)try{i.html=readFileSync(a.htmlFile,"utf-8");}catch{l(`Failed to read HTML file: ${a.htmlFile}`),process.exit(1);}else a.html&&(i.html=a.html);if(a.textFile)try{i.text=readFileSync(a.textFile,"utf-8");}catch{l(`Failed to read text file: ${a.textFile}`),process.exit(1);}else a.text&&(i.text=a.text);if(a.template&&(i.template_id=a.template),a.templateData)try{i.template_data=JSON.parse(a.templateData);}catch{l("Invalid JSON for --template-data"),process.exit(1);}if(a.cc){let s=a.cc.split(",").map(c=>c.trim());i.cc=s.length===1?s[0]:s;}if(a.bcc){let s=a.bcc.split(",").map(c=>c.trim());i.bcc=s.length===1?s[0]:s;}a.replyTo&&(i.reply_to_email=a.replyTo),a.schedule&&(i.scheduled_at=a.schedule);let r=await t.emails.send(i);a.format==="json"?m(r,"json"):(p("Email sent successfully!"),m({"Message ID":r.message_id,Recipients:r.recipients,Status:r.status,...r.scheduled_at&&{"Scheduled At":r.scheduled_at}},"table"));}catch(e){l(e instanceof Error?e.message:"Failed to send email"),process.exit(1);}})}function be(){let o=new Command("contacts").description(`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 a=>{try{let e=d(),o=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),n=a.to.split(",").map(s=>s.trim()),t={to:n.length===1?n[0]:n};if(a.from&&(t.from=a.from),a.subject&&(t.subject=a.subject),a.htmlFile)try{t.html=readFileSync(a.htmlFile,"utf-8");}catch{l(`Failed to read HTML file: ${a.htmlFile}`),process.exit(1);}else a.html&&(t.html=a.html);if(a.textFile)try{t.text=readFileSync(a.textFile,"utf-8");}catch{l(`Failed to read text file: ${a.textFile}`),process.exit(1);}else a.text&&(t.text=a.text);if(a.template&&(t.template_id=a.template),a.templateData)try{t.template_data=JSON.parse(a.templateData);}catch{l("Invalid JSON for --template-data"),process.exit(1);}if(a.cc){let s=a.cc.split(",").map(c=>c.trim());t.cc=s.length===1?s[0]:s;}if(a.bcc){let s=a.bcc.split(",").map(c=>c.trim());t.bcc=s.length===1?s[0]:s;}a.replyTo&&(t.reply_to_email=a.replyTo),a.schedule&&(t.scheduled_at=a.schedule);let r=await o.emails.send(t);a.format==="json"?m(r,"json"):(p("Email sent successfully!"),m({"Message ID":r.message_id,Recipients:r.recipients,Status:r.status,...r.scheduled_at&&{"Scheduled At":r.scheduled_at}},"table"));}catch(e){l(e instanceof Error?e.message:"Failed to send email"),process.exit(1);}})}function be(){let i=new Command("contacts").description(`Manage contacts
160
160
 
161
161
  USAGE
162
162
  emailr contacts <subcommand> [options]
@@ -238,7 +238,7 @@ EXAMPLES
238
238
 
239
239
  SEE ALSO
240
240
  emailr segments Manage contact segments
241
- emailr broadcasts Send emails to contacts`);return o.command("list").description(`List all contacts
241
+ emailr broadcasts Send emails to contacts`);return i.command("list").description(`List all contacts
242
242
 
243
243
  USAGE
244
244
  emailr contacts list [options]
@@ -286,8 +286,8 @@ EXAMPLES
286
286
  emailr contacts list --format json
287
287
 
288
288
  # Combine filters with pagination
289
- 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 a=>{try{let e=d(),t=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),n={limit:parseInt(a.limit,10),offset:parseInt(a.offset,10)};if(a.subscribed&&(n.subscribed=!0),a.unsubscribed&&(n.subscribed=!1),a.search&&(n.search=a.search),a.tags){let r=a.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean);r.length>0&&(n.tags=r.join(","));}let i=await t.contacts.list(n);if(a.format==="json")m(i,"json");else {let r=i.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}));m(r,"table"),console.log(`
290
- Total: ${i.total}`);}}catch(e){l(e instanceof Error?e.message:"Failed to list contacts"),process.exit(1);}}),o.command("get <contact_id>").description(`Get a contact by ID
289
+ 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 a=>{try{let e=d(),o=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),n={limit:parseInt(a.limit,10),offset:parseInt(a.offset,10)};if(a.subscribed&&(n.subscribed=!0),a.unsubscribed&&(n.subscribed=!1),a.search&&(n.search=a.search),a.tags){let r=a.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean);r.length>0&&(n.tags=r.join(","));}let t=await o.contacts.list(n);if(a.format==="json")m(t,"json");else {let r=t.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}));m(r,"table"),console.log(`
290
+ Total: ${t.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
291
291
 
292
292
  USAGE
293
293
  emailr contacts get <contact_id> [options]
@@ -314,7 +314,7 @@ EXAMPLES
314
314
  emailr contacts get con_abc123 --format json
315
315
 
316
316
  # Pipe JSON to jq for processing
317
- emailr contacts get con_abc123 --format json | jq '.metadata'`).option("--format <format>","Output format (json|table)","table").action(async(a,e)=>{try{let t=d(),i=await new Emailr({apiKey:t.apiKey,baseUrl:t.baseUrl}).contacts.get(a);m(i,e.format);}catch(t){l(t instanceof Error?t.message:"Failed to get contact"),process.exit(1);}}),o.command("create").description(`Create a new contact
317
+ emailr contacts get con_abc123 --format json | jq '.metadata'`).option("--format <format>","Output format (json|table)","table").action(async(a,e)=>{try{let o=d(),t=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).contacts.get(a);m(t,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
318
318
 
319
319
  USAGE
320
320
  emailr contacts create --email <email_address> [options]
@@ -357,7 +357,7 @@ EXAMPLES
357
357
  emailr contacts create --email "user@example.com" --subscribed false
358
358
 
359
359
  # Get JSON output for scripting
360
- 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 a=>{try{let e=d(),t=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),n={email:a.email};if(a.firstName&&(n.first_name=a.firstName),a.lastName&&(n.last_name=a.lastName),a.subscribed!==void 0&&(n.subscribed=a.subscribed),a.metadata)try{n.metadata=JSON.parse(a.metadata);}catch{l("Invalid JSON for --metadata"),process.exit(1);}a.tags&&(n.tags=a.tags.split(",").map(r=>r.trim().toLowerCase()).filter(Boolean));let i=await t.contacts.create(n);a.format==="json"?m(i,"json"):(p(`Contact created: ${i.id}`),m(i,"table"));}catch(e){l(e instanceof Error?e.message:"Failed to create contact"),process.exit(1);}}),o.command("update <contact_id>").description(`Update a contact
360
+ 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 a=>{try{let e=d(),o=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),n={email:a.email};if(a.firstName&&(n.first_name=a.firstName),a.lastName&&(n.last_name=a.lastName),a.subscribed!==void 0&&(n.subscribed=a.subscribed),a.metadata)try{n.metadata=JSON.parse(a.metadata);}catch{l("Invalid JSON for --metadata"),process.exit(1);}a.tags&&(n.tags=a.tags.split(",").map(r=>r.trim().toLowerCase()).filter(Boolean));let t=await o.contacts.create(n);a.format==="json"?m(t,"json"):(p(`Contact created: ${t.id}`),m(t,"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
361
361
 
362
362
  USAGE
363
363
  emailr contacts update <contact_id> [options]
@@ -406,7 +406,7 @@ EXAMPLES
406
406
  emailr contacts update con_abc123 --metadata '{"plan": "enterprise", "upgraded": true}'
407
407
 
408
408
  # Get JSON output
409
- 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(a,e)=>{try{let t=d(),n=new Emailr({apiKey:t.apiKey,baseUrl:t.baseUrl}),i={};if(e.email&&(i.email=e.email),e.firstName&&(i.first_name=e.firstName),e.lastName&&(i.last_name=e.lastName),e.subscribed&&(i.subscribed=!0),e.unsubscribed&&(i.subscribed=!1),e.metadata)try{i.metadata=JSON.parse(e.metadata);}catch{l("Invalid JSON for --metadata"),process.exit(1);}e.tags&&(i.tags=e.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean));let r=await n.contacts.update(a,i);e.format==="json"?m(r,"json"):(p(`Contact updated: ${r.id}`),m(r,"table"));}catch(t){l(t instanceof Error?t.message:"Failed to update contact"),process.exit(1);}}),o.command("delete <contact_id>").description(`Delete a contact
409
+ 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(a,e)=>{try{let o=d(),n=new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}),t={};if(e.email&&(t.email=e.email),e.firstName&&(t.first_name=e.firstName),e.lastName&&(t.last_name=e.lastName),e.subscribed&&(t.subscribed=!0),e.unsubscribed&&(t.subscribed=!1),e.metadata)try{t.metadata=JSON.parse(e.metadata);}catch{l("Invalid JSON for --metadata"),process.exit(1);}e.tags&&(t.tags=e.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean));let r=await n.contacts.update(a,t);e.format==="json"?m(r,"json"):(p(`Contact updated: ${r.id}`),m(r,"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
410
410
 
411
411
  USAGE
412
412
  emailr contacts delete <contact_id>
@@ -423,7 +423,7 @@ EXAMPLES
423
423
  emailr contacts delete con_abc123
424
424
 
425
425
  WARNING
426
- This action is permanent and cannot be undone.`).action(async a=>{try{let e=d();await new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}).contacts.delete(a),p(`Contact deleted: ${a}`);}catch(e){l(e instanceof Error?e.message:"Failed to delete contact"),process.exit(1);}}),o}function ge(){return E.join(V.homedir(),".config","emailr","templates")}function tt(){let o=ge();x.existsSync(o)||x.mkdirSync(o,{recursive:true});}function z(o){return E.join(ge(),`${o}.html`)}function Y(o,a){tt();let e=z(o);x.writeFileSync(e,a,"utf-8");}function we(o){let a=z(o);return x.existsSync(a)?x.readFileSync(a,"utf-8"):null}function ye(o){let a=z(o);return x.existsSync(a)}var v=null,k=null,q=false;function ve(o){return o.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#039;")}function it(o){return o===null||o.trim()===""}function ot(o){return `<!DOCTYPE html>
426
+ This action is permanent and cannot be undone.`).action(async a=>{try{let e=d();await new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}).contacts.delete(a),p(`Contact deleted: ${a}`);}catch(e){l(e instanceof Error?e.message:"Failed to delete contact"),process.exit(1);}}),i}function ge(){return E.join(V.homedir(),".config","emailr","templates")}function tt(){let i=ge();x.existsSync(i)||x.mkdirSync(i,{recursive:true});}function z(i){return E.join(ge(),`${i}.html`)}function Y(i,a){tt();let e=z(i);x.writeFileSync(e,a,"utf-8");}function we(i){let a=z(i);return x.existsSync(a)?x.readFileSync(a,"utf-8"):null}function ye(i){let a=z(i);return x.existsSync(a)}var v=null,k=null,q=false;function ve(i){return i.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#039;")}function ot(i){return i===null||i.trim()===""}function it(i){return `<!DOCTYPE html>
427
427
  <html lang="en">
428
428
  <head>
429
429
  <meta charset="UTF-8">
@@ -489,14 +489,14 @@ WARNING
489
489
  <div class="icon">\u{1F4ED}</div>
490
490
  <h1>No Content Available</h1>
491
491
  <p>This template exists but has no HTML content to display.</p>
492
- <div class="template-id">${ve(o)}</div>
492
+ <div class="template-id">${ve(i)}</div>
493
493
  <div class="hint">
494
494
  <p><strong>To add content:</strong></p>
495
495
  <p>Update the template using the CLI with the <code>--html</code> option or provide HTML content when creating the template.</p>
496
496
  </div>
497
497
  </div>
498
498
  </body>
499
- </html>`}function Se(o){return `<!DOCTYPE html>
499
+ </html>`}function Se(i){return `<!DOCTYPE html>
500
500
  <html lang="en">
501
501
  <head>
502
502
  <meta charset="UTF-8">
@@ -548,11 +548,11 @@ WARNING
548
548
  <div class="icon">404</div>
549
549
  <h1>Template Not Found</h1>
550
550
  <p>The requested template could not be found in local storage.</p>
551
- <div class="template-id">${ve(o)}</div>
551
+ <div class="template-id">${ve(i)}</div>
552
552
  <p style="margin-top: 1rem;">Try creating or retrieving the template first using the CLI.</p>
553
553
  </div>
554
554
  </body>
555
- </html>`}function rt(o){let a=o.match(/^\/preview\/([^/]+)$/);return a?a[1]:null}function nt(){return (o,a)=>{if(o.method!=="GET"){a.writeHead(405,{"Content-Type":"text/plain"}),a.end("Method Not Allowed");return}let e=o.url||"/",t=rt(e);if(!t){a.writeHead(404,{"Content-Type":"text/plain"}),a.end("Not Found");return}if(!ye(t)){a.writeHead(404,{"Content-Type":"text/html; charset=utf-8"}),a.end(Se(t));return}let n=we(t);if(n===null){a.writeHead(404,{"Content-Type":"text/html; charset=utf-8"}),a.end(Se(t));return}if(it(n)){a.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),a.end(ot(t));return}a.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),a.end(n);}}var Te={async start(){return q&&k!==null?k:new Promise((o,a)=>{v=at.createServer(nt()),v.listen(0,"127.0.0.1",()=>{let e=v.address();e&&typeof e=="object"?(k=e.port,q=true,v.unref(),o(k)):a(new Error("Failed to get server address"));}),v.on("error",e=>{q=false,k=null,v=null,a(new Error(`Failed to start preview server: ${e.message}`));});})},getPort(){return k},isRunning(){return q},async stop(){if(v)return new Promise(o=>{v.close(()=>{v=null,k=null,q=false,o();});})}};function xe(){return Te}async function Z(o){try{return `http://127.0.0.1:${await Te.start()}/preview/${o}`}catch{return null}}function Oe(){v&&v.ref();}var P=null,Q=null,W=null,D=[],_e=`
555
+ </html>`}function rt(i){let a=i.match(/^\/preview\/([^/]+)$/);return a?a[1]:null}function nt(){return (i,a)=>{if(i.method!=="GET"){a.writeHead(405,{"Content-Type":"text/plain"}),a.end("Method Not Allowed");return}let e=i.url||"/",o=rt(e);if(!o){a.writeHead(404,{"Content-Type":"text/plain"}),a.end("Not Found");return}if(!ye(o)){a.writeHead(404,{"Content-Type":"text/html; charset=utf-8"}),a.end(Se(o));return}let n=we(o);if(n===null){a.writeHead(404,{"Content-Type":"text/html; charset=utf-8"}),a.end(Se(o));return}if(ot(n)){a.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),a.end(it(o));return}a.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),a.end(n);}}var Te={async start(){return q&&k!==null?k:new Promise((i,a)=>{v=at.createServer(nt()),v.listen(0,"127.0.0.1",()=>{let e=v.address();e&&typeof e=="object"?(k=e.port,q=true,v.unref(),i(k)):a(new Error("Failed to get server address"));}),v.on("error",e=>{q=false,k=null,v=null,a(new Error(`Failed to start preview server: ${e.message}`));});})},getPort(){return k},isRunning(){return q},async stop(){if(v)return new Promise(i=>{v.close(()=>{v=null,k=null,q=false,i();});})}};function xe(){return Te}async function Z(i){try{return `http://127.0.0.1:${await Te.start()}/preview/${i}`}catch{return null}}function Oe(){v&&v.ref();}var P=null,Q=null,W=null,M=[],_e=`
556
556
  <script>
557
557
  (function() {
558
558
  const evtSource = new EventSource('/__live-reload');
@@ -566,11 +566,11 @@ WARNING
566
566
  };
567
567
  })();
568
568
  </script>
569
- `;function mt(o){return o.includes("</body>")?o.replace("</body>",`${_e}</body>`):o+_e}function ct(){D.forEach(o=>{try{o.write(`data: reload
569
+ `;function mt(i){return i.includes("</body>")?i.replace("</body>",`${_e}</body>`):i+_e}function ct(){M.forEach(i=>{try{i.write(`data: reload
570
570
 
571
- `);}catch{}});}async function ee(o,a){let e=E.resolve(o);return new Promise((t,n)=>{P=at.createServer((i,r)=>{if(i.url==="/__live-reload"){r.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive","Access-Control-Allow-Origin":"*"}),r.write(`data: connected
571
+ `);}catch{}});}async function ee(i,a){let e=E.resolve(i);return new Promise((o,n)=>{P=at.createServer((t,r)=>{if(t.url==="/__live-reload"){r.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive","Access-Control-Allow-Origin":"*"}),r.write(`data: connected
572
572
 
573
- `),D.push(r),i.on("close",()=>{D=D.filter(s=>s!==r);});return}if(i.method==="GET"){try{let s=x.readFileSync(e,"utf-8"),c=mt(s);r.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),r.end(c);}catch(s){r.writeHead(500,{"Content-Type":"text/plain"}),r.end(`Error reading file: ${s instanceof Error?s.message:String(s)}`);}return}r.writeHead(405,{"Content-Type":"text/plain"}),r.end("Method Not Allowed");}),P.listen(0,"127.0.0.1",()=>{let i=P.address();if(i&&typeof i=="object"){Q=i.port;let r=null;W=x.watch(e,s=>{s==="change"&&(r&&clearTimeout(r),r=setTimeout(()=>{ct(),a?.();},100));}),t(Q);}else n(new Error("Failed to get server address"));}),P.on("error",i=>{n(new Error(`Failed to start server: ${i.message}`));});})}async function te(){if(W&&(W.close(),W=null),D.forEach(o=>{try{o.end();}catch{}}),D=[],P)return new Promise(o=>{P.close(()=>{P=null,Q=null,o();});})}async function je(o){try{let a=o.html_content??"";Y(o.id,a);}catch(a){return N(`Could not save template for preview: ${a instanceof Error?a.message:String(a)}`),null}try{let a=await Z(o.id);return a===null?(N("Could not start preview server"),null):a}catch(a){return N(`Could not generate preview URL: ${a instanceof Error?a.message:String(a)}`),null}}function Ie(){let o=new Command("templates").description(`Manage email templates
573
+ `),M.push(r),t.on("close",()=>{M=M.filter(s=>s!==r);});return}if(t.method==="GET"){try{let s=x.readFileSync(e,"utf-8"),c=mt(s);r.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),r.end(c);}catch(s){r.writeHead(500,{"Content-Type":"text/plain"}),r.end(`Error reading file: ${s instanceof Error?s.message:String(s)}`);}return}r.writeHead(405,{"Content-Type":"text/plain"}),r.end("Method Not Allowed");}),P.listen(0,"127.0.0.1",()=>{let t=P.address();if(t&&typeof t=="object"){Q=t.port;let r=null;W=x.watch(e,s=>{s==="change"&&(r&&clearTimeout(r),r=setTimeout(()=>{ct(),a?.();},100));}),o(Q);}else n(new Error("Failed to get server address"));}),P.on("error",t=>{n(new Error(`Failed to start server: ${t.message}`));});})}async function te(){if(W&&(W.close(),W=null),M.forEach(i=>{try{i.end();}catch{}}),M=[],P)return new Promise(i=>{P.close(()=>{P=null,Q=null,i();});})}async function je(i){try{let a=i.html_content??"";Y(i.id,a);}catch(a){return N(`Could not save template for preview: ${a instanceof Error?a.message:String(a)}`),null}try{let a=await Z(i.id);return a===null?(N("Could not start preview server"),null):a}catch(a){return N(`Could not generate preview URL: ${a instanceof Error?a.message:String(a)}`),null}}function Ie(){let i=new Command("templates").description(`Manage email templates
574
574
 
575
575
  USAGE
576
576
  emailr templates <subcommand> [options]
@@ -641,7 +641,7 @@ AGENTIC WORKFLOW
641
641
 
642
642
  SEE ALSO
643
643
  emailr send Send emails using templates
644
- emailr broadcasts Send bulk emails to segments`);return o.command("list").description(`List all templates
644
+ emailr broadcasts Send bulk emails to segments`);return i.command("list").description(`List all templates
645
645
 
646
646
  USAGE
647
647
  emailr templates list [options]
@@ -671,8 +671,8 @@ EXAMPLES
671
671
  emailr templates list --page 2 --limit 10
672
672
 
673
673
  # Get JSON output for scripting
674
- 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 a=>{try{let e=d(),t=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),n={limit:parseInt(a.limit,10),page:parseInt(a.page,10)};if(a.tags){let r=a.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean);r.length>0&&(n.tags=r.join(","));}let i=await t.templates.list(n);if(a.format==="json")m(i,"json");else {let r=i.map(s=>({ID:s.id,Name:s.name,Subject:s.subject,Variables:s.variables?.join(", ")||"-",Tags:s.tags?.join(", ")||"-",Created:s.created_at}));m(r,"table"),console.log(`
675
- Total: ${i.length}`);}}catch(e){l(e instanceof Error?e.message:"Failed to list templates"),process.exit(1);}}),o.command("get <template_id>").description(`Get a template by ID
674
+ 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 a=>{try{let e=d(),o=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),n={limit:parseInt(a.limit,10),page:parseInt(a.page,10)};if(a.tags){let r=a.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean);r.length>0&&(n.tags=r.join(","));}let t=await o.templates.list(n);if(a.format==="json")m(t,"json");else {let r=t.map(s=>({ID:s.id,Name:s.name,Subject:s.subject,Variables:s.variables?.join(", ")||"-",Tags:s.tags?.join(", ")||"-",Created:s.created_at}));m(r,"table"),console.log(`
675
+ Total: ${t.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
676
676
 
677
677
  USAGE
678
678
  emailr templates get <template_id> [options]
@@ -700,7 +700,7 @@ EXAMPLES
700
700
  emailr templates get tpl_abc123 --format json
701
701
 
702
702
  # Pipe JSON to jq for processing
703
- emailr templates get tpl_abc123 --format json | jq '.html_content'`).option("--format <format>","Output format: json | table","table").action(async(a,e)=>{try{let t=d(),i=await new Emailr({apiKey:t.apiKey,baseUrl:t.baseUrl}).templates.get(a),r=await je({id:i.id,html_content:i.html_content??void 0}),s=i.preview_html?`${t.baseUrl}/preview/${i.id}`:null;if(e.format==="json")m({...i,preview_url:s??r},"json");else {let c={ID:i.id,Name:i.name,Subject:i.subject,Variables:i.variables?.join(", ")||"-",Created:i.created_at};s?c["Preview URL"]=s:r&&(c["Local Preview"]=r),m(c,"table");}}catch(t){l(t instanceof Error?t.message:"Failed to get template"),process.exit(1);}}),o.command("fetch <template_id>").description(`Download template HTML to file or stdout
703
+ emailr templates get tpl_abc123 --format json | jq '.html_content'`).option("--format <format>","Output format: json | table","table").action(async(a,e)=>{try{let o=d(),t=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).templates.get(a),r=await je({id:t.id,html_content:t.html_content??void 0}),s=t.preview_html?`${o.baseUrl}/preview/${t.id}`:null;if(e.format==="json")m({...t,preview_url:s??r},"json");else {let c={ID:t.id,Name:t.name,Subject:t.subject,Variables:t.variables?.join(", ")||"-",Created:t.created_at};s?c["Preview URL"]=s:r&&(c["Local Preview"]=r),m(c,"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
704
704
 
705
705
  USAGE
706
706
  emailr templates fetch <template_id> [options]
@@ -734,8 +734,8 @@ AGENTIC WORKFLOW
734
734
  This is step 1 of the agentic workflow:
735
735
  1. Fetch: emailr templates fetch <id> --output template.html
736
736
  2. Edit locally or with AI assistance
737
- 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(a,e)=>{try{let t=d(),i=await new Emailr({apiKey:t.apiKey,baseUrl:t.baseUrl}).templates.fetch(a,{preview:e.preview??!1});if(i||(e.preview?(l("No preview HTML exists for this template"),console.log(`
738
- 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 r=E.resolve(e.output);x.writeFileSync(r,i,"utf-8"),p(`HTML saved to: ${r}`);}else console.log(i);}catch(t){l(t instanceof Error?t.message:"Failed to fetch template"),process.exit(1);}}),o.command("push-preview <template_id>").description(`Upload HTML to template's preview for sharing with AI agents
737
+ 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(a,e)=>{try{let o=d(),t=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).templates.fetch(a,{preview:e.preview??!1});if(t||(e.preview?(l("No preview HTML exists for this template"),console.log(`
738
+ 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 r=E.resolve(e.output);x.writeFileSync(r,t,"utf-8"),p(`HTML saved to: ${r}`);}else console.log(t);}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
739
739
 
740
740
  USAGE
741
741
  emailr templates push-preview <template_id> --html-file <file_path>
@@ -779,8 +779,8 @@ AGENTIC WORKFLOW
779
779
  3. Push preview: emailr templates push-preview <id> --html-file template.html
780
780
  4. Share the preview URL with your AI agent for feedback
781
781
  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(a,e)=>{try{!e.htmlFile&&!e.html&&(l("Either --html-file or --html is required"),console.log(`
782
- 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 t=d(),n=new Emailr({apiKey:t.apiKey,baseUrl:t.baseUrl}),i;if(e.htmlFile){let c=E.resolve(e.htmlFile);try{i=x.readFileSync(c,"utf-8");}catch{l(`Failed to read file: ${c}`),process.exit(1);}}else i=e.html;let r=await n.templates.pushPreview(a,i),s="updated";e.format==="json"?m({template_id:a,preview_url:r.preview_url,status:s},"json"):(p("Preview uploaded successfully"),m({"Template ID":a,"Preview URL":r.preview_url,Status:s},"table"),console.log(`
783
- Share this URL with your AI agent for feedback.`));}catch(t){l(t instanceof Error?t.message:"Failed to push preview"),process.exit(1);}}),o.command("create").description(`Create a new email template
782
+ 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=d(),n=new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}),t;if(e.htmlFile){let c=E.resolve(e.htmlFile);try{t=x.readFileSync(c,"utf-8");}catch{l(`Failed to read file: ${c}`),process.exit(1);}}else t=e.html;let r=await n.templates.pushPreview(a,t),s="updated";e.format==="json"?m({template_id:a,preview_url:r.preview_url,status:s},"json"):(p("Preview uploaded successfully"),m({"Template ID":a,"Preview URL":r.preview_url,Status:s},"table"),console.log(`
783
+ 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
784
784
 
785
785
  USAGE
786
786
  emailr templates create --name <template_name> --subject <subject_line> [options]
@@ -828,8 +828,8 @@ EXAMPLES
828
828
 
829
829
  TIP
830
830
  For live preview while building, use "emailr templates draft" first.
831
- 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("--from-name <name>","Sender display name").option("--reply-to <email_address>","Default reply-to email address").option("--preview-text <text>","Preview text shown in email clients").option("--inbox-id <inbox_id>","Inbox ID for sender identity defaults").option("--tags <tags>","Comma-separated tags").option("--format <format>","Output format: json | table","table").action(async a=>{try{let e=d(),t=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),n={name:a.name,subject:a.subject};if(a.htmlFile){let s=await import('fs');n.html_content=s.readFileSync(a.htmlFile,"utf-8");}else a.html&&(n.html_content=a.html);if(a.textFile){let s=await import('fs');n.text_content=s.readFileSync(a.textFile,"utf-8");}else a.text&&(n.text_content=a.text);a.from&&(n.from_email=a.from),a.fromName&&(n.from_name=a.fromName),a.replyTo&&(n.reply_to=a.replyTo),a.previewText&&(n.preview_text=a.previewText),a.inboxId&&(n.inbox_id=a.inboxId),a.tags&&(n.tags=a.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean));let i=await t.templates.create(n),r=await je({id:i.id,html_content:i.html_content??void 0});if(a.format==="json")m({...i,preview_url:r},"json");else {p(`Template created: ${i.id}`);let s={ID:i.id,Name:i.name,Subject:i.subject,Variables:i.variables?.join(", ")||"-",Tags:i.tags?.join(", ")||"-"};r&&(s["Preview URL"]=r),m(s,"table"),r&&console.log(`
832
- 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);}}),o.command("update <template_id>").description(`Update an existing email template
831
+ 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("--from-name <name>","Sender display name").option("--reply-to <email_address>","Default reply-to email address").option("--preview-text <text>","Preview text shown in email clients").option("--inbox-id <inbox_id>","Inbox ID for sender identity defaults").option("--tags <tags>","Comma-separated tags").option("--format <format>","Output format: json | table","table").action(async a=>{try{let e=d(),o=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),n={name:a.name,subject:a.subject};if(a.htmlFile){let s=await import('fs');n.html_content=s.readFileSync(a.htmlFile,"utf-8");}else a.html&&(n.html_content=a.html);if(a.textFile){let s=await import('fs');n.text_content=s.readFileSync(a.textFile,"utf-8");}else a.text&&(n.text_content=a.text);a.from&&(n.from_email=a.from),a.fromName&&(n.from_name=a.fromName),a.replyTo&&(n.reply_to=a.replyTo),a.previewText&&(n.preview_text=a.previewText),a.inboxId&&(n.inbox_id=a.inboxId),a.tags&&(n.tags=a.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean));let t=await o.templates.create(n),r=await je({id:t.id,html_content:t.html_content??void 0});if(a.format==="json")m({...t,preview_url:r},"json");else {p(`Template created: ${t.id}`);let s={ID:t.id,Name:t.name,Subject:t.subject,Variables:t.variables?.join(", ")||"-",Tags:t.tags?.join(", ")||"-"};r&&(s["Preview URL"]=r),m(s,"table"),r&&console.log(`
832
+ 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
833
833
 
834
834
  USAGE
835
835
  emailr templates update <template_id> [options]
@@ -884,7 +884,7 @@ AGENTIC WORKFLOW
884
884
  2. Edit locally or with AI assistance
885
885
  3. Push preview: emailr templates push-preview <id> --html-file template.html
886
886
  4. Share URL with AI agent, iterate on feedback
887
- 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("--from-name <name>","New sender display name").option("--reply-to <email_address>","New default reply-to email address").option("--preview-text <text>","New preview text").option("--inbox-id <inbox_id>",'Inbox ID for sender identity (use "none" to clear)').option("--tags <tags>","Comma-separated tags").option("--format <format>","Output format: json | table","table").action(async(a,e)=>{try{let t=d(),n=new Emailr({apiKey:t.apiKey,baseUrl:t.baseUrl}),i={};if(e.name&&(i.name=e.name),e.subject&&(i.subject=e.subject),e.htmlFile){let s=await import('fs');i.html_content=s.readFileSync(e.htmlFile,"utf-8");}else e.html&&(i.html_content=e.html);if(e.textFile){let s=await import('fs');i.text_content=s.readFileSync(e.textFile,"utf-8");}else e.text&&(i.text_content=e.text);e.from&&(i.from_email=e.from),e.fromName&&(i.from_name=e.fromName),e.replyTo&&(i.reply_to=e.replyTo),e.previewText&&(i.preview_text=e.previewText),e.inboxId&&(i.inbox_id=e.inboxId==="none"?null:e.inboxId),e.tags&&(i.tags=e.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean));let r=await n.templates.update(a,i);if(e.format==="json")m(r,"json");else {p(`Template updated: ${r.id}`);let s={ID:r.id,Name:r.name,Subject:r.subject,Variables:r.variables?.join(", ")||"-",Tags:r.tags?.join(", ")||"-",Updated:r.updated_at};m(s,"table");}}catch(t){l(t instanceof Error?t.message:"Failed to update template"),process.exit(1);}}),o.command("delete <template_id>").description(`Delete a template
887
+ 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("--from-name <name>","New sender display name").option("--reply-to <email_address>","New default reply-to email address").option("--preview-text <text>","New preview text").option("--inbox-id <inbox_id>",'Inbox ID for sender identity (use "none" to clear)').option("--tags <tags>","Comma-separated tags").option("--format <format>","Output format: json | table","table").action(async(a,e)=>{try{let o=d(),n=new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}),t={};if(e.name&&(t.name=e.name),e.subject&&(t.subject=e.subject),e.htmlFile){let s=await import('fs');t.html_content=s.readFileSync(e.htmlFile,"utf-8");}else e.html&&(t.html_content=e.html);if(e.textFile){let s=await import('fs');t.text_content=s.readFileSync(e.textFile,"utf-8");}else e.text&&(t.text_content=e.text);e.from&&(t.from_email=e.from),e.fromName&&(t.from_name=e.fromName),e.replyTo&&(t.reply_to=e.replyTo),e.previewText&&(t.preview_text=e.previewText),e.inboxId&&(t.inbox_id=e.inboxId==="none"?null:e.inboxId),e.tags&&(t.tags=e.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean));let r=await n.templates.update(a,t);if(e.format==="json")m(r,"json");else {p(`Template updated: ${r.id}`);let s={ID:r.id,Name:r.name,Subject:r.subject,Variables:r.variables?.join(", ")||"-",Tags:r.tags?.join(", ")||"-",Updated:r.updated_at};m(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
888
888
 
889
889
  USAGE
890
890
  emailr templates delete <template_id>
@@ -901,7 +901,7 @@ EXAMPLES
901
901
  emailr templates delete tpl_abc123
902
902
 
903
903
  WARNING
904
- This action is permanent and cannot be undone.`).action(async a=>{try{let e=d();await new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}).templates.delete(a),p(`Template deleted: ${a}`);}catch(e){l(e instanceof Error?e.message:"Failed to delete template"),process.exit(1);}}),o.command("preview <template_id>").description(`Preview a template in the browser
904
+ This action is permanent and cannot be undone.`).action(async a=>{try{let e=d();await new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}).templates.delete(a),p(`Template deleted: ${a}`);}catch(e){l(e instanceof Error?e.message:"Failed to delete template"),process.exit(1);}}),i.command("preview <template_id>").description(`Preview a template in the browser
905
905
 
906
906
  USAGE
907
907
  emailr templates preview <template_id> [options]
@@ -930,12 +930,12 @@ EXAMPLES
930
930
 
931
931
  SEE ALSO
932
932
  emailr templates edit Live editing with hot-reload
933
- 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(a,e)=>{try{let t=d(),n=new Emailr({apiKey:t.apiKey,baseUrl:t.baseUrl});console.log(`Fetching template ${a}...`);let i=await n.templates.get(a),r=i.html_content??"";if(Y(i.id,r),e.foreground){let w=await Z(i.id);if(w||(l("Failed to start preview server"),process.exit(1)),Oe(),console.log(`
934
- Template: ${i.name}`),console.log(`Preview URL: ${w}`),e.open!==!1)try{await(await import('open')).default(w),console.log(`
933
+ 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(a,e)=>{try{let o=d(),n=new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl});console.log(`Fetching template ${a}...`);let t=await n.templates.get(a),r=t.html_content??"";if(Y(t.id,r),e.foreground){let w=await Z(t.id);if(w||(l("Failed to start preview server"),process.exit(1)),Oe(),console.log(`
934
+ Template: ${t.name}`),console.log(`Preview URL: ${w}`),e.open!==!1)try{await(await import('open')).default(w),console.log(`
935
935
  Browser opened.`);}catch{console.log(`
936
936
  Could not open browser automatically. Open the URL above manually.`);}process.on("SIGINT",async()=>{console.log(`
937
937
 
938
- Stopping preview server...`),await xe().stop(),console.log("Done."),process.exit(0);});return}let s=E.join(process.cwd(),`.template-preview-${i.id}.html`);x.writeFileSync(s,r,"utf-8");let{spawn:c}=await import('child_process'),b=await import('os'),g=E.join(b.tmpdir(),"emailr-preview.pid");try{let w=x.readFileSync(g,"utf-8").trim();process.kill(parseInt(w,10),"SIGTERM");}catch{}let f=`
938
+ Stopping preview server...`),await xe().stop(),console.log("Done."),process.exit(0);});return}let s=E.join(process.cwd(),`.template-preview-${t.id}.html`);x.writeFileSync(s,r,"utf-8");let{spawn:c}=await import('child_process'),b=await import('os'),g=E.join(b.tmpdir(),"emailr-preview.pid");try{let w=x.readFileSync(g,"utf-8").trim();process.kill(parseInt(w,10),"SIGTERM");}catch{}let f=`
939
939
  const http = require('http');
940
940
  const fs = require('fs');
941
941
  const path = require('path');
@@ -961,8 +961,8 @@ Stopping preview server...`),await xe().stop(),console.log("Done."),process.exit
961
961
  });
962
962
  process.on('SIGTERM', () => { try { fs.unlinkSync(pidFile); fs.unlinkSync(portFile); fs.unlinkSync(filePath); } catch {} process.exit(0); });
963
963
  `,h=c("node",["-e",f],{detached:!0,stdio:["ignore","pipe","ignore"]}),S="";await new Promise(w=>{h.stdout?.on("data",j=>{let B=j.toString().match(/PORT:(\d+)/);B&&(S=B[1],w());}),setTimeout(w,3e3);}),h.unref();let _=`http://127.0.0.1:${S}/`;if(console.log(`
964
- Template: ${i.name}`),console.log(`Preview URL: ${_}`),console.log(`
965
- To stop: emailr templates stop-preview`),e.open!==!1)try{await(await import('open')).default(_);}catch{}process.exit(0);}catch(t){l(t instanceof Error?t.message:"Failed to preview template"),process.exit(1);}}),o.command("edit <template_id>").description(`Start a live editing session for a template with hot-reload
964
+ Template: ${t.name}`),console.log(`Preview URL: ${_}`),console.log(`
965
+ To stop: emailr templates stop-preview`),e.open!==!1)try{await(await import('open')).default(_);}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
966
966
 
967
967
  USAGE
968
968
  emailr templates edit <template_id> [options]
@@ -1002,8 +1002,8 @@ EXAMPLES
1002
1002
  SEE ALSO
1003
1003
  emailr templates draft Draft a new template with live preview
1004
1004
  emailr templates update Save changes to the template
1005
- 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(a,e)=>{try{let t=d(),n=new Emailr({apiKey:t.apiKey,baseUrl:t.baseUrl}),i=E.resolve(e.file);console.log(`Fetching template ${a}...`);let r=await n.templates.get(a),s=r.html_content??"";if(x.writeFileSync(i,s,"utf-8"),console.log(`Template saved to: ${i}`),e.foreground){let j=`http://127.0.0.1:${await ee(i,()=>{console.log("File changed - browser refreshed");})}/`;if(console.log(`
1006
- Template: ${r.name}`),console.log(`Template ID: ${r.id}`),console.log(`Live Preview: ${j}`),console.log(`File: ${i}`),console.log(`
1005
+ 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(a,e)=>{try{let o=d(),n=new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}),t=E.resolve(e.file);console.log(`Fetching template ${a}...`);let r=await n.templates.get(a),s=r.html_content??"";if(x.writeFileSync(t,s,"utf-8"),console.log(`Template saved to: ${t}`),e.foreground){let j=`http://127.0.0.1:${await ee(t,()=>{console.log("File changed - browser refreshed");})}/`;if(console.log(`
1006
+ Template: ${r.name}`),console.log(`Template ID: ${r.id}`),console.log(`Live Preview: ${j}`),console.log(`File: ${t}`),console.log(`
1007
1007
  Watching for changes... Edit the file and see live updates.`),console.log(`When done, run: emailr templates update ${a} --html-file ${e.file}`),e.open!==!1)try{await(await import('open')).default(j);}catch{}process.on("SIGINT",async()=>{console.log(`
1008
1008
 
1009
1009
  Stopping live preview server...`),await te(),console.log("Done."),console.log(`
@@ -1012,7 +1012,7 @@ To save changes: emailr templates update ${a} --html-file ${e.file}`),process.ex
1012
1012
  const fs = require('fs');
1013
1013
  const path = require('path');
1014
1014
  const os = require('os');
1015
- const filePath = ${JSON.stringify(i)};
1015
+ const filePath = ${JSON.stringify(t)};
1016
1016
  const pidFile = path.join(os.tmpdir(), 'emailr-preview.pid');
1017
1017
  const portFile = path.join(os.tmpdir(), 'emailr-preview.port');
1018
1018
  let clients = [];
@@ -1048,9 +1048,9 @@ To save changes: emailr templates update ${a} --html-file ${e.file}`),process.ex
1048
1048
  });
1049
1049
  process.on('SIGTERM', () => { try { fs.unlinkSync(pidFile); fs.unlinkSync(portFile); } catch {} process.exit(0); });
1050
1050
  `,h=c("node",["-e",f],{detached:!0,stdio:["ignore","pipe","ignore"]}),S="";await new Promise(w=>{h.stdout?.on("data",j=>{let me=j.toString().match(/PORT:(\d+)/);me&&(S=me[1],w());}),setTimeout(w,3e3);}),h.unref();let _=`http://127.0.0.1:${S}/`;if(console.log(`
1051
- Template: ${r.name}`),console.log(`Template ID: ${r.id}`),console.log(`Live Preview: ${_}`),console.log(`File: ${i}`),console.log(`
1051
+ Template: ${r.name}`),console.log(`Template ID: ${r.id}`),console.log(`Live Preview: ${_}`),console.log(`File: ${t}`),console.log(`
1052
1052
  Edit the file and see live updates in the browser.`),console.log(`
1053
- When done:`),console.log(` emailr templates update ${a} --html-file ${e.file}`),console.log(" emailr templates stop-preview"),e.open!==!1)try{await(await import('open')).default(_);}catch{}process.exit(0);}catch(t){l(t instanceof Error?t.message:"Failed to edit template"),process.exit(1);}}),o.command("draft").description(`Start a live drafting session for a new template with hot-reload
1053
+ When done:`),console.log(` emailr templates update ${a} --html-file ${e.file}`),console.log(" emailr templates stop-preview"),e.open!==!1)try{await(await import('open')).default(_);}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
1054
1054
 
1055
1055
  USAGE
1056
1056
  emailr templates draft [options]
@@ -1092,7 +1092,7 @@ EXAMPLES
1092
1092
  SEE ALSO
1093
1093
  emailr templates edit Edit an existing template with live preview
1094
1094
  emailr templates create Create the template from your draft
1095
- 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 a=>{try{let e=E.resolve(a.file),t;if(a.blank?t="":t=`<!DOCTYPE html>
1095
+ 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 a=>{try{let e=E.resolve(a.file),o;if(a.blank?o="":o=`<!DOCTYPE html>
1096
1096
  <html>
1097
1097
  <head>
1098
1098
  <meta charset="UTF-8">
@@ -1127,13 +1127,13 @@ SEE ALSO
1127
1127
  <p><a href="{{unsubscribe_link}}">Unsubscribe</a></p>
1128
1128
  </div>
1129
1129
  </body>
1130
- </html>`,x.writeFileSync(e,t,"utf-8"),console.log(`Template draft created: ${e}`),a.foreground){let h=`http://127.0.0.1:${await ee(e,()=>{console.log("File changed - browser refreshed");})}/`;if(console.log(`
1130
+ </html>`,x.writeFileSync(e,o,"utf-8"),console.log(`Template draft created: ${e}`),a.foreground){let h=`http://127.0.0.1:${await ee(e,()=>{console.log("File changed - browser refreshed");})}/`;if(console.log(`
1131
1131
  Live Preview: ${h}`),console.log(`File: ${e}`),console.log(`
1132
1132
  Watching for changes... Edit the file and see live updates.`),console.log(`
1133
1133
  When done, create the template:`),console.log(` emailr templates create --name "Template Name" --subject "Email Subject" --html-file ${a.file}`),a.open!==!1)try{await(await import('open')).default(h);}catch{}process.on("SIGINT",async()=>{console.log(`
1134
1134
 
1135
1135
  Stopping live preview server...`),await te(),console.log("Done."),console.log(`
1136
- To create template: emailr templates create --name "Template Name" --subject "Email Subject" --html-file ${a.file}`),process.exit(0);});return}let{spawn:n}=await import('child_process'),i=await import('os'),r=E.join(i.tmpdir(),"emailr-preview.pid");try{let f=x.readFileSync(r,"utf-8").trim();process.kill(parseInt(f,10),"SIGTERM");}catch{}let s=`
1136
+ To create template: emailr templates create --name "Template Name" --subject "Email Subject" --html-file ${a.file}`),process.exit(0);});return}let{spawn:n}=await import('child_process'),t=await import('os'),r=E.join(t.tmpdir(),"emailr-preview.pid");try{let f=x.readFileSync(r,"utf-8").trim();process.kill(parseInt(f,10),"SIGTERM");}catch{}let s=`
1137
1137
  const http = require('http');
1138
1138
  const fs = require('fs');
1139
1139
  const path = require('path');
@@ -1176,7 +1176,7 @@ To create template: emailr templates create --name "Template Name" --subject "Em
1176
1176
  `,c=n("node",["-e",s],{detached:!0,stdio:["ignore","pipe","ignore"]}),b="";await new Promise(f=>{c.stdout?.on("data",h=>{let S=h.toString().match(/PORT:(\d+)/);S&&(b=S[1],f());}),setTimeout(f,3e3);}),c.unref();let g=`http://127.0.0.1:${b}/`;if(console.log(`
1177
1177
  Live Preview: ${g}`),console.log(`File: ${e}`),console.log(`
1178
1178
  Edit the file and see live updates in the browser.`),console.log(`
1179
- When done:`),console.log(` emailr templates create --name "Template Name" --subject "Email Subject" --html-file ${a.file}`),console.log(" emailr templates stop-preview"),a.open!==!1)try{await(await import('open')).default(g);}catch{}process.exit(0);}catch(e){l(e instanceof Error?e.message:"Failed to start draft session"),process.exit(1);}}),o.command("stop-preview").description(`Stop any running background preview server
1179
+ When done:`),console.log(` emailr templates create --name "Template Name" --subject "Email Subject" --html-file ${a.file}`),console.log(" emailr templates stop-preview"),a.open!==!1)try{await(await import('open')).default(g);}catch{}process.exit(0);}catch(e){l(e instanceof Error?e.message:"Failed to start draft session"),process.exit(1);}}),i.command("stop-preview").description(`Stop any running background preview server
1180
1180
 
1181
1181
  USAGE
1182
1182
  emailr templates stop-preview
@@ -1193,7 +1193,7 @@ EXAMPLES
1193
1193
  SEE ALSO
1194
1194
  emailr templates edit Start live editing session
1195
1195
  emailr templates draft Start live drafting session
1196
- emailr templates preview Preview a template in browser`).action(async()=>{let a=await import('os'),e=E.join(a.tmpdir(),"emailr-preview.pid");try{let t=x.readFileSync(e,"utf-8").trim();process.kill(parseInt(t,10),"SIGTERM"),x.unlinkSync(e),p("Preview server stopped");}catch{p("No preview server running");}}),o}function Ne(){let o=new Command("domains").description(`Manage sending domains
1196
+ emailr templates preview Preview a template in browser`).action(async()=>{let a=await import('os'),e=E.join(a.tmpdir(),"emailr-preview.pid");try{let o=x.readFileSync(e,"utf-8").trim();process.kill(parseInt(o,10),"SIGTERM"),x.unlinkSync(e),p("Preview server stopped");}catch{p("No preview server running");}}),i}function Ne(){let i=new Command("domains").description(`Manage sending domains
1197
1197
 
1198
1198
  USAGE
1199
1199
  emailr domains <subcommand> [options]
@@ -1274,7 +1274,7 @@ VERIFICATION STATUS
1274
1274
 
1275
1275
  SEE ALSO
1276
1276
  emailr send Send emails using verified domains
1277
- emailr webhooks Receive domain verification events`);return o.command("list").description(`List all domains
1277
+ emailr webhooks Receive domain verification events`);return i.command("list").description(`List all domains
1278
1278
 
1279
1279
  USAGE
1280
1280
  emailr domains list [options]
@@ -1301,7 +1301,7 @@ EXAMPLES
1301
1301
  emailr domains list --format json | jq '.[] | select(.status == "verified")'
1302
1302
 
1303
1303
  # Count domains
1304
- emailr domains list --format json | jq 'length'`).option("--format <format>","Output format (json|table)","table").action(async a=>{try{let e=d(),n=await new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}).domains.list();if(a.format==="json")m(n,"json");else {let i=n.map(r=>({ID:r.id,Domain:r.domain,Status:r.status,DKIM:r.dkim_verified,SPF:r.spf_verified,DMARC:r.dmarc_verified,Created:r.created_at}));m(i,"table");}}catch(e){l(e instanceof Error?e.message:"Failed to list domains"),process.exit(1);}}),o.command("get <domain_id>").description(`Get domain details
1304
+ emailr domains list --format json | jq 'length'`).option("--format <format>","Output format (json|table)","table").action(async a=>{try{let e=d(),n=await new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}).domains.list();if(a.format==="json")m(n,"json");else {let t=n.map(r=>({ID:r.id,Domain:r.domain,Status:r.status,DKIM:r.dkim_verified,SPF:r.spf_verified,DMARC:r.dmarc_verified,Created:r.created_at}));m(t,"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
1305
1305
 
1306
1306
  USAGE
1307
1307
  emailr domains get <domain_id> [options]
@@ -1328,7 +1328,7 @@ EXAMPLES
1328
1328
  emailr domains get dom_abc123 --format json
1329
1329
 
1330
1330
  # Extract DNS records
1331
- emailr domains get dom_abc123 --format json | jq '.dns_records'`).option("--format <format>","Output format (json|table)","table").action(async(a,e)=>{try{let t=d(),i=await new Emailr({apiKey:t.apiKey,baseUrl:t.baseUrl}).domains.get(a);m(i,e.format);}catch(t){l(t instanceof Error?t.message:"Failed to get domain"),process.exit(1);}}),o.command("add <domain_name>").description(`Add a new domain
1331
+ emailr domains get dom_abc123 --format json | jq '.dns_records'`).option("--format <format>","Output format (json|table)","table").action(async(a,e)=>{try{let o=d(),t=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).domains.get(a);m(t,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
1332
1332
 
1333
1333
  USAGE
1334
1334
  emailr domains add <domain_name> [options]
@@ -1381,7 +1381,7 @@ NEXT STEPS
1381
1381
  1. Copy the DNS records shown in the output
1382
1382
  2. Add them to your DNS provider (Cloudflare, Route53, etc.)
1383
1383
  3. Wait for DNS propagation (up to 48 hours)
1384
- 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(a,e)=>{try{let t=d(),n=new Emailr({apiKey:t.apiKey,baseUrl:t.baseUrl}),i={domain:a};e.receivingSubdomain&&(i.receivingSubdomain=e.receivingSubdomain);let r=await n.domains.add(i);if(e.format==="json")m(r,"json");else {if(p(`Domain added: ${r.domain}`),u("Add the following DNS records to verify your domain:"),console.log(""),r.dns_records){let s=[{Type:"DKIM",...ae(r.dns_records.dkim)},{Type:"SPF",...ae(r.dns_records.spf)},{Type:"DMARC",...ae(r.dns_records.dmarc)}];m(s,"table");}console.log(""),u(`Run 'emailr domains verify ${r.id}' after adding DNS records`);}}catch(t){l(t instanceof Error?t.message:"Failed to add domain"),process.exit(1);}}),o.command("verify <domain_id>").description(`Verify a domain
1384
+ 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(a,e)=>{try{let o=d(),n=new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}),t={domain:a};e.receivingSubdomain&&(t.receivingSubdomain=e.receivingSubdomain);let r=await n.domains.add(t);if(e.format==="json")m(r,"json");else {if(p(`Domain added: ${r.domain}`),u("Add the following DNS records to verify your domain:"),console.log(""),r.dns_records){let s=[{Type:"DKIM",...ae(r.dns_records.dkim)},{Type:"SPF",...ae(r.dns_records.spf)},{Type:"DMARC",...ae(r.dns_records.dmarc)}];m(s,"table");}console.log(""),u(`Run 'emailr domains verify ${r.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
1385
1385
 
1386
1386
  USAGE
1387
1387
  emailr domains verify <domain_id> [options]
@@ -1419,7 +1419,7 @@ TROUBLESHOOTING
1419
1419
  1. Run 'check-dns' to see which records are missing
1420
1420
  2. Verify records are correctly configured with your DNS provider
1421
1421
  3. Wait for DNS propagation (can take up to 48 hours)
1422
- 4. Try verification again`).option("--format <format>","Output format (json|table)","table").action(async(a,e)=>{try{let t=d(),i=await new Emailr({apiKey:t.apiKey,baseUrl:t.baseUrl}).domains.verify(a);e.format==="json"?m(i,"json"):i.verified?p("Domain verified successfully!"):(u(`Domain status: ${i.status}`),i.dkim_status&&u(`DKIM status: ${i.dkim_status}`));}catch(t){l(t instanceof Error?t.message:"Failed to verify domain"),process.exit(1);}}),o.command("check-dns <domain_id>").description(`Check DNS records for a domain
1422
+ 4. Try verification again`).option("--format <format>","Output format (json|table)","table").action(async(a,e)=>{try{let o=d(),t=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).domains.verify(a);e.format==="json"?m(t,"json"):t.verified?p("Domain verified successfully!"):(u(`Domain status: ${t.status}`),t.dkim_status&&u(`DKIM status: ${t.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
1423
1423
 
1424
1424
  USAGE
1425
1425
  emailr domains check-dns <domain_id> [options]
@@ -1466,7 +1466,7 @@ COMMON ISSUES
1466
1466
 
1467
1467
  Multiple records found:
1468
1468
  - Remove duplicate TXT records
1469
- - Keep only the Emailr-specific record`).option("--format <format>","Output format (json|table)","table").action(async(a,e)=>{try{let t=d(),i=await new Emailr({apiKey:t.apiKey,baseUrl:t.baseUrl}).domains.checkDns(a);if(e.format==="json")m(i,"json");else {let r=Object.entries(i).map(([s,c])=>({Record:s,Verified:c.verified,Expected:c.expected||"-",Found:c.found?.join(", ")||"-"}));m(r,"table");}}catch(t){l(t instanceof Error?t.message:"Failed to check DNS"),process.exit(1);}}),o.command("delete <domain_id>").description(`Delete a domain
1469
+ - Keep only the Emailr-specific record`).option("--format <format>","Output format (json|table)","table").action(async(a,e)=>{try{let o=d(),t=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).domains.checkDns(a);if(e.format==="json")m(t,"json");else {let r=Object.entries(t).map(([s,c])=>({Record:s,Verified:c.verified,Expected:c.expected||"-",Found:c.found?.join(", ")||"-"}));m(r,"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
1470
1470
 
1471
1471
  USAGE
1472
1472
  emailr domains delete <domain_id> [options]
@@ -1496,7 +1496,7 @@ WARNING
1496
1496
  This action is permanent and cannot be undone.
1497
1497
  - Emails from this domain will fail to send
1498
1498
  - DNS records can be removed from your DNS provider
1499
- - Re-add the domain if you need to restore functionality`).option("--format <format>","Output format (json|table)","table").action(async a=>{try{let e=d();await new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}).domains.delete(a),p(`Domain deleted: ${a}`);}catch(e){l(e instanceof Error?e.message:"Failed to delete domain"),process.exit(1);}}),o}function ae(o){return {"Record Type":o.type,Name:o.name,Value:o.value.length>50?o.value.substring(0,47)+"...":o.value,...o.priority!==void 0&&{Priority:o.priority}}}function Ce(){let o=new Command("config").description(`Manage CLI configuration
1499
+ - Re-add the domain if you need to restore functionality`).option("--format <format>","Output format (json|table)","table").action(async a=>{try{let e=d();await new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}).domains.delete(a),p(`Domain deleted: ${a}`);}catch(e){l(e instanceof Error?e.message:"Failed to delete domain"),process.exit(1);}}),i}function ae(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 Ce(){let i=new Command("config").description(`Manage CLI configuration
1500
1500
 
1501
1501
  USAGE
1502
1502
  emailr config <subcommand> [options]
@@ -1559,7 +1559,7 @@ EXAMPLES
1559
1559
  emailr templates list
1560
1560
 
1561
1561
  SEE ALSO
1562
- emailr --help Show all available commands`);return o.command("set <key> <value>").description(`Set a configuration value
1562
+ emailr --help Show all available commands`);return i.command("set <key> <value>").description(`Set a configuration value
1563
1563
 
1564
1564
  USAGE
1565
1565
  emailr config set <key> <value>
@@ -1589,7 +1589,7 @@ EXAMPLES
1589
1589
 
1590
1590
  NOTE
1591
1591
  Environment variables (EMAILR_API_KEY, EMAILR_BASE_URL) take precedence
1592
- over config file values at runtime.`).action(async(a,e)=>{try{let t=["api-key","base-url","format"],n=a.toLowerCase();t.includes(n)||(l(`Invalid config key: ${a}`),u(`Valid keys: ${t.join(", ")}`),process.exit(1));let r={"api-key":"apiKey","base-url":"baseUrl",format:"format"}[n];n==="format"&&!["json","table"].includes(e)&&(l(`Invalid format value: ${e}`),u("Valid formats: json, table"),process.exit(1)),K({[r]:e}),p(`Configuration saved: ${a} = ${n==="api-key"?"***":e}`),u(`Config file: ${I()}`);}catch(t){l(t instanceof Error?t.message:"Failed to save configuration"),process.exit(1);}}),o.command("get <key>").description(`Get a configuration value
1592
+ over config file values at runtime.`).action(async(a,e)=>{try{let o=["api-key","base-url","format"],n=a.toLowerCase();o.includes(n)||(l(`Invalid config key: ${a}`),u(`Valid keys: ${o.join(", ")}`),process.exit(1));let r={"api-key":"apiKey","base-url":"baseUrl",format:"format"}[n];n==="format"&&!["json","table"].includes(e)&&(l(`Invalid format value: ${e}`),u("Valid formats: json, table"),process.exit(1)),K({[r]:e}),p(`Configuration saved: ${a} = ${n==="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
1593
1593
 
1594
1594
  USAGE
1595
1595
  emailr config get <key>
@@ -1617,7 +1617,7 @@ EXAMPLES
1617
1617
  emailr config get format
1618
1618
 
1619
1619
  SEE ALSO
1620
- emailr config list Show all configuration values`).action(async a=>{try{let e=["api-key","base-url","format"],t=a.toLowerCase();e.includes(t)||(l(`Invalid config key: ${a}`),u(`Valid keys: ${e.join(", ")}`),process.exit(1));let i={"api-key":"apiKey","base-url":"baseUrl",format:"format"}[t],r=ce(i);r?console.log(t==="api-key"?r.substring(0,8)+"..."+r.substring(r.length-4):r):u(`${a} is not set`);}catch(e){l(e instanceof Error?e.message:"Failed to get configuration"),process.exit(1);}}),o.command("list").description(`List all configuration values
1620
+ emailr config list Show all configuration values`).action(async a=>{try{let e=["api-key","base-url","format"],o=a.toLowerCase();e.includes(o)||(l(`Invalid config key: ${a}`),u(`Valid keys: ${e.join(", ")}`),process.exit(1));let t={"api-key":"apiKey","base-url":"baseUrl",format:"format"}[o],r=ce(t);r?console.log(o==="api-key"?r.substring(0,8)+"..."+r.substring(r.length-4):r):u(`${a} 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
1621
1621
 
1622
1622
  USAGE
1623
1623
  emailr config list [options]
@@ -1645,7 +1645,7 @@ EXAMPLES
1645
1645
 
1646
1646
  SEE ALSO
1647
1647
  emailr config get Get a single configuration value
1648
- emailr config path Show config file location`).option("--format <format>","Output format (json|table)","table").action(async a=>{try{let e=d(),t={"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(a.format==="json")m(t,"json");else {let n=Object.entries(t).map(([i,r])=>({Key:i,Value:r}));m(n,"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));}}),o.command("path").description(`Show the configuration file path
1648
+ emailr config path Show config file location`).option("--format <format>","Output format (json|table)","table").action(async a=>{try{let e=d(),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(a.format==="json")m(o,"json");else {let n=Object.entries(o).map(([t,r])=>({Key:t,Value:r}));m(n,"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
1649
1649
 
1650
1650
  USAGE
1651
1651
  emailr config path
@@ -1672,7 +1672,7 @@ EXAMPLES
1672
1672
  open $(emailr config path)
1673
1673
 
1674
1674
  # View config file contents
1675
- cat $(emailr config path)`).action(()=>{console.log(I());}),o.command("init").description(`Initialize configuration interactively
1675
+ cat $(emailr config path)`).action(()=>{console.log(I());}),i.command("init").description(`Initialize configuration interactively
1676
1676
 
1677
1677
  USAGE
1678
1678
  emailr config init [options]
@@ -1705,7 +1705,7 @@ ALTERNATIVE: ENVIRONMENT VARIABLES
1705
1705
 
1706
1706
  SEE ALSO
1707
1707
  emailr config set Set individual configuration values
1708
- emailr config list View current configuration`).option("--api-key <key>","API key to use").option("--base-url <url>","Base URL for API").action(async a=>{try{a.apiKey?(K({apiKey:a.apiKey,baseUrl:a.baseUrl}),p("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);}}),o}function Ue(){let o=new Command("broadcasts").description(`Manage broadcast campaigns
1708
+ emailr config list View current configuration`).option("--api-key <key>","API key to use").option("--base-url <url>","Base URL for API").action(async a=>{try{a.apiKey?(K({apiKey:a.apiKey,baseUrl:a.baseUrl}),p("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 Ue(){let i=new Command("broadcasts").description(`Manage broadcast campaigns
1709
1709
 
1710
1710
  USAGE
1711
1711
  emailr broadcasts <subcommand> [options]
@@ -1810,7 +1810,7 @@ EXAMPLES
1810
1810
  SEE ALSO
1811
1811
  emailr templates Manage email templates
1812
1812
  emailr segments Manage contact segments
1813
- emailr contacts Manage individual contacts`);return o.command("list").description(`List all broadcasts
1813
+ emailr contacts Manage individual contacts`);return i.command("list").description(`List all broadcasts
1814
1814
 
1815
1815
  USAGE
1816
1816
  emailr broadcasts list [options]
@@ -1855,7 +1855,7 @@ EXAMPLES
1855
1855
  emailr broadcasts list --format json
1856
1856
 
1857
1857
  # Pipe JSON to jq for processing
1858
- 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 a=>{try{let e=d(),t=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),n={status:a.status,limit:parseInt(a.limit)};if(a.tags){let r=a.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean);r.length>0&&(n.tags=r.join(","));}let i=await t.broadcasts.list(n);if(a.format==="json")m(i,"json");else {if(i.length===0){console.log("No broadcasts found.");return}let r=i.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()}));m(r,"table");}}catch(e){l(e instanceof Error?e.message:"Failed to list broadcasts"),process.exit(1);}}),o.command("get <broadcast_id>").description(`Get broadcast details
1858
+ 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 a=>{try{let e=d(),o=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),n={status:a.status,limit:parseInt(a.limit)};if(a.tags){let r=a.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean);r.length>0&&(n.tags=r.join(","));}let t=await o.broadcasts.list(n);if(a.format==="json")m(t,"json");else {if(t.length===0){console.log("No broadcasts found.");return}let r=t.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()}));m(r,"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
1859
1859
 
1860
1860
  USAGE
1861
1861
  emailr broadcasts get <broadcast_id> [options]
@@ -1890,7 +1890,7 @@ EXAMPLES
1890
1890
  emailr broadcasts get brd_abc123 --format json
1891
1891
 
1892
1892
  # Pipe JSON to jq for processing
1893
- emailr broadcasts get brd_abc123 --format json | jq '{sent: .sent_count, opened: .opened_count}'`).option("--format <format>","Output format (json|table)","table").action(async(a,e)=>{try{let t=d(),i=await new Emailr({apiKey:t.apiKey,baseUrl:t.baseUrl}).broadcasts.get(a);e.format==="json"?m(i,"json"):m({ID:i.id,Name:i.name,Subject:i.subject,"From Email":i.from_email,"From Name":i.from_name||"-",Status:i.status,Tags:i.tags?.join(", ")||"-","Total Recipients":i.total_recipients||0,"Sent Count":i.sent_count||0,Delivered:i.delivered_count||0,Opened:i.opened_count||0,Clicked:i.clicked_count||0,Bounced:i.bounced_count||0,"Scheduled At":i.scheduled_at||"N/A","Started At":i.started_at||"N/A","Completed At":i.completed_at||"N/A","Created At":i.created_at},"table");}catch(t){l(t instanceof Error?t.message:"Failed to get broadcast"),process.exit(1);}}),o.command("create").description(`Create a new broadcast
1893
+ emailr broadcasts get brd_abc123 --format json | jq '{sent: .sent_count, opened: .opened_count}'`).option("--format <format>","Output format (json|table)","table").action(async(a,e)=>{try{let o=d(),t=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).broadcasts.get(a);e.format==="json"?m(t,"json"):m({ID:t.id,Name:t.name,Subject:t.subject,"From Email":t.from_email,"From Name":t.from_name||"-",Status:t.status,Tags:t.tags?.join(", ")||"-","Total Recipients":t.total_recipients||0,"Sent Count":t.sent_count||0,Delivered:t.delivered_count||0,Opened:t.opened_count||0,Clicked:t.clicked_count||0,Bounced:t.bounced_count||0,"Scheduled At":t.scheduled_at||"N/A","Started At":t.started_at||"N/A","Completed At":t.completed_at||"N/A","Created At":t.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
1894
1894
 
1895
1895
  USAGE
1896
1896
  emailr broadcasts create --name <name> --subject <subject> --from <email> [options]
@@ -1971,7 +1971,7 @@ EXAMPLES
1971
1971
 
1972
1972
  SEE ALSO
1973
1973
  emailr templates Create and manage email templates
1974
- emailr segments Create and manage contact segments`).requiredOption("--name <name>","Broadcast name").requiredOption("--subject <subject>","Email subject").requiredOption("--from <email>","Sender email address").option("--from-name <name>","Sender display name").option("--reply-to <email>","Reply-To email address").option("--preview-text <text>","Preview text (preheader)").option("--inbox-id <inbox_id>","Inbox ID for sender identity defaults").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 a=>{try{let e=d(),t=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),n={name:a.name,subject:a.subject,from_email:a.from,from_name:a.fromName,reply_to:a.replyTo,preview_text:a.previewText,inbox_id:a.inboxId,template_id:a.template,segment_id:a.segment,html_content:a.html,text_content:a.text,scheduled_at:a.schedule};a.tags&&(n.tags=a.tags.split(",").map(r=>r.trim().toLowerCase()).filter(Boolean));let i=await t.broadcasts.create(n);a.format==="json"?m(i,"json"):(p("Broadcast created successfully!"),m({ID:i.id,Name:i.name,Status:i.status,Tags:i.tags?.join(", ")||"-","Scheduled At":i.scheduled_at||"Not scheduled"},"table"));}catch(e){l(e instanceof Error?e.message:"Failed to create broadcast"),process.exit(1);}}),o.command("send <broadcast_id>").description(`Send a broadcast immediately
1974
+ emailr segments Create and manage contact segments`).requiredOption("--name <name>","Broadcast name").requiredOption("--subject <subject>","Email subject").requiredOption("--from <email>","Sender email address").option("--from-name <name>","Sender display name").option("--reply-to <email>","Reply-To email address").option("--preview-text <text>","Preview text (preheader)").option("--inbox-id <inbox_id>","Inbox ID for sender identity defaults").option("--inbox-ids <ids>","Comma-separated inbox IDs for inbox rotation").option("--sending-speed <speed>","Sending speed: auto | slow | normal | instant (default: auto)").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 a=>{try{let e=d(),o=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),n={name:a.name,subject:a.subject,from_email:a.from,from_name:a.fromName,reply_to:a.replyTo,preview_text:a.previewText,inbox_id:a.inboxId,template_id:a.template,segment_id:a.segment,html_content:a.html,text_content:a.text,scheduled_at:a.schedule};a.inboxIds&&(n.inbox_ids=a.inboxIds.split(",").map(r=>r.trim()).filter(Boolean)),a.sendingSpeed&&(n.sending_speed=a.sendingSpeed),a.tags&&(n.tags=a.tags.split(",").map(r=>r.trim().toLowerCase()).filter(Boolean));let t=await o.broadcasts.create(n);a.format==="json"?m(t,"json"):(p("Broadcast created successfully!"),m({ID:t.id,Name:t.name,Status:t.status,Tags:t.tags?.join(", ")||"-","Scheduled At":t.scheduled_at||"Not scheduled"},"table"));}catch(e){l(e instanceof Error?e.message:"Failed to create broadcast"),process.exit(1);}}),i.command("send <broadcast_id>").description(`Send a broadcast immediately
1975
1975
 
1976
1976
  USAGE
1977
1977
  emailr broadcasts send <broadcast_id> [options]
@@ -2004,7 +2004,7 @@ EXAMPLES
2004
2004
  NOTE
2005
2005
  Sending is asynchronous. The command returns when sending starts,
2006
2006
  not when all emails are delivered. Use 'emailr broadcasts get' to
2007
- check delivery progress.`).option("--format <format>","Output format (json|table)","table").action(async(a,e)=>{try{let t=d(),i=await new Emailr({apiKey:t.apiKey,baseUrl:t.baseUrl}).broadcasts.send(a);e.format==="json"?m(i,"json"):(p("Broadcast sent successfully!"),m({Success:i.success,Sent:i.sent,Total:i.total},"table"));}catch(t){l(t instanceof Error?t.message:"Failed to send broadcast"),process.exit(1);}}),o.command("schedule <broadcast_id>").description(`Schedule a broadcast for future delivery
2007
+ check delivery progress.`).option("--format <format>","Output format (json|table)","table").action(async(a,e)=>{try{let o=d(),t=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).broadcasts.send(a);e.format==="json"?m(t,"json"):(p("Broadcast sent successfully!"),m({Success:t.success,Sent:t.sent,Total:t.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
2008
2008
 
2009
2009
  USAGE
2010
2010
  emailr broadcasts schedule <broadcast_id> --at <datetime> [options]
@@ -2054,7 +2054,7 @@ EXAMPLES
2054
2054
  emailr broadcasts schedule brd_abc123 --at "2024-12-25T10:00:00Z" --format json
2055
2055
 
2056
2056
  SEE ALSO
2057
- emailr broadcasts cancel Cancel a scheduled broadcast`).requiredOption("--at <datetime>","Schedule time (ISO 8601)").option("--format <format>","Output format (json|table)","table").action(async(a,e)=>{try{let t=d(),i=await new Emailr({apiKey:t.apiKey,baseUrl:t.baseUrl}).broadcasts.schedule(a,e.at);e.format==="json"?m(i,"json"):(p("Broadcast scheduled successfully!"),m({ID:i.id,Name:i.name,Status:i.status,"Scheduled At":i.scheduled_at},"table"));}catch(t){l(t instanceof Error?t.message:"Failed to schedule broadcast"),process.exit(1);}}),o.command("cancel <broadcast_id>").description(`Cancel a scheduled broadcast
2057
+ emailr broadcasts cancel Cancel a scheduled broadcast`).requiredOption("--at <datetime>","Schedule time (ISO 8601)").option("--format <format>","Output format (json|table)","table").action(async(a,e)=>{try{let o=d(),t=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).broadcasts.schedule(a,e.at);e.format==="json"?m(t,"json"):(p("Broadcast scheduled successfully!"),m({ID:t.id,Name:t.name,Status:t.status,"Scheduled At":t.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
2058
2058
 
2059
2059
  USAGE
2060
2060
  emailr broadcasts cancel <broadcast_id> [options]
@@ -2082,7 +2082,7 @@ EXAMPLES
2082
2082
  emailr broadcasts cancel brd_abc123 --format json
2083
2083
 
2084
2084
  NOTE
2085
- Broadcasts that are already 'sending' or 'sent' cannot be cancelled.`).option("--format <format>","Output format (json|table)","table").action(async(a,e)=>{try{let t=d(),i=await new Emailr({apiKey:t.apiKey,baseUrl:t.baseUrl}).broadcasts.cancel(a);e.format==="json"?m(i,"json"):p("Broadcast cancelled successfully!");}catch(t){l(t instanceof Error?t.message:"Failed to cancel broadcast"),process.exit(1);}}),o.command("update <broadcast_id>").description(`Update a broadcast
2085
+ Broadcasts that are already 'sending' or 'sent' cannot be cancelled.`).option("--format <format>","Output format (json|table)","table").action(async(a,e)=>{try{let o=d(),t=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).broadcasts.cancel(a);e.format==="json"?m(t,"json"):p("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
2086
2086
 
2087
2087
  USAGE
2088
2088
  emailr broadcasts update <broadcast_id> [options]
@@ -2135,7 +2135,7 @@ EXAMPLES
2135
2135
  emailr broadcasts update brd_abc123 --name "Updated" --format json
2136
2136
 
2137
2137
  NOTE
2138
- 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("--from-name <name>","Sender display name").option("--reply-to <email>","Reply-To email address").option("--preview-text <text>","Preview text (preheader)").option("--inbox-id <inbox_id>",'Inbox ID for sender identity (use "none" to clear)').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(a,e)=>{try{let t=d(),n=new Emailr({apiKey:t.apiKey,baseUrl:t.baseUrl}),i={};e.name&&(i.name=e.name),e.subject&&(i.subject=e.subject),e.from&&(i.from_email=e.from),e.fromName&&(i.from_name=e.fromName),e.replyTo&&(i.reply_to=e.replyTo),e.previewText&&(i.preview_text=e.previewText),e.html&&(i.html_content=e.html),e.text&&(i.text_content=e.text),e.inboxId&&(i.inbox_id=e.inboxId==="none"?null:e.inboxId),e.template&&(i.template_id=e.template==="none"?null:e.template),e.segment&&(i.segment_id=e.segment==="none"?null:e.segment),e.topic&&(i.topic_id=e.topic==="none"?null:e.topic),e.schedule&&(i.scheduled_at=e.schedule==="none"?null:e.schedule),e.tags&&(i.tags=e.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean)),Object.keys(i).length===0&&(l("No update fields specified. Use --help to see available options."),process.exit(1));let r=await n.broadcasts.update(a,i);e.format==="json"?m(r,"json"):(p("Broadcast updated successfully!"),m({ID:r.id,Name:r.name,Subject:r.subject,Status:r.status,Tags:r.tags?.join(", ")||"-","Scheduled At":r.scheduled_at||"Not scheduled"},"table"));}catch(t){l(t instanceof Error?t.message:"Failed to update broadcast"),process.exit(1);}}),o.command("delete <broadcast_id>").description(`Delete a broadcast
2138
+ 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("--from-name <name>","Sender display name").option("--reply-to <email>","Reply-To email address").option("--preview-text <text>","Preview text (preheader)").option("--inbox-id <inbox_id>",'Inbox ID for sender identity (use "none" to clear)').option("--inbox-ids <ids>",'Comma-separated inbox IDs for rotation (use "none" to clear)').option("--sending-speed <speed>",'Sending speed: auto | slow | normal | instant (use "none" to clear)').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(a,e)=>{try{let o=d(),n=new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}),t={};e.name&&(t.name=e.name),e.subject&&(t.subject=e.subject),e.from&&(t.from_email=e.from),e.fromName&&(t.from_name=e.fromName),e.replyTo&&(t.reply_to=e.replyTo),e.previewText&&(t.preview_text=e.previewText),e.html&&(t.html_content=e.html),e.text&&(t.text_content=e.text),e.inboxId&&(t.inbox_id=e.inboxId==="none"?null:e.inboxId),e.inboxIds&&(t.inbox_ids=e.inboxIds==="none"?null:e.inboxIds.split(",").map(s=>s.trim()).filter(Boolean)),e.sendingSpeed&&(t.sending_speed=e.sendingSpeed==="none"?null:e.sendingSpeed),e.template&&(t.template_id=e.template==="none"?null:e.template),e.segment&&(t.segment_id=e.segment==="none"?null:e.segment),e.topic&&(t.topic_id=e.topic==="none"?null:e.topic),e.schedule&&(t.scheduled_at=e.schedule==="none"?null:e.schedule),e.tags&&(t.tags=e.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean)),Object.keys(t).length===0&&(l("No update fields specified. Use --help to see available options."),process.exit(1));let r=await n.broadcasts.update(a,t);e.format==="json"?m(r,"json"):(p("Broadcast updated successfully!"),m({ID:r.id,Name:r.name,Subject:r.subject,Status:r.status,Tags:r.tags?.join(", ")||"-","Scheduled At":r.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
2139
2139
 
2140
2140
  USAGE
2141
2141
  emailr broadcasts delete <broadcast_id> [options]
@@ -2163,7 +2163,7 @@ EXAMPLES
2163
2163
 
2164
2164
  WARNING
2165
2165
  This action is permanent and cannot be undone.
2166
- All delivery statistics will be lost.`).option("--format <format>","Output format (json|table)","table").action(async(a,e)=>{try{let t=d(),i=await new Emailr({apiKey:t.apiKey,baseUrl:t.baseUrl}).broadcasts.delete(a);e.format==="json"?m(i,"json"):p("Broadcast deleted successfully!");}catch(t){l(t instanceof Error?t.message:"Failed to delete broadcast"),process.exit(1);}}),o}function ke(){let o=new Command("webhooks").description(`Manage webhooks
2166
+ All delivery statistics will be lost.`).option("--format <format>","Output format (json|table)","table").action(async(a,e)=>{try{let o=d(),t=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).broadcasts.delete(a);e.format==="json"?m(t,"json"):p("Broadcast deleted successfully!");}catch(o){l(o instanceof Error?o.message:"Failed to delete broadcast"),process.exit(1);}}),i}function ke(){let i=new Command("webhooks").description(`Manage webhooks
2167
2167
 
2168
2168
  USAGE
2169
2169
  emailr webhooks <subcommand> [options]
@@ -2289,7 +2289,7 @@ SIGNATURE VERIFICATION
2289
2289
 
2290
2290
  SEE ALSO
2291
2291
  emailr domains Manage sending domains
2292
- emailr send Send emails directly`);return o.command("list").description(`List all webhooks
2292
+ emailr send Send emails directly`);return i.command("list").description(`List all webhooks
2293
2293
 
2294
2294
  USAGE
2295
2295
  emailr webhooks list [options]
@@ -2316,7 +2316,7 @@ EXAMPLES
2316
2316
  emailr webhooks list --format json | jq '.[] | select(.active == true)'
2317
2317
 
2318
2318
  # Count webhooks
2319
- emailr webhooks list --format json | jq 'length'`).option("--format <format>","Output format (json|table)","table").action(async a=>{try{let e=d(),n=await new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}).webhooks.list();if(a.format==="json")m(n,"json");else {if(n.data.length===0){console.log("No webhooks found.");return}let i=n.data.map(r=>({ID:r.id,Name:r.name,URL:r.url.substring(0,40)+(r.url.length>40?"...":""),Events:r.events.join(", "),Active:r.active?"Yes":"No"}));m(i,"table");}}catch(e){l(e instanceof Error?e.message:"Failed to list webhooks"),process.exit(1);}}),o.command("get <webhook_id>").description(`Get webhook details
2319
+ emailr webhooks list --format json | jq 'length'`).option("--format <format>","Output format (json|table)","table").action(async a=>{try{let e=d(),n=await new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}).webhooks.list();if(a.format==="json")m(n,"json");else {if(n.data.length===0){console.log("No webhooks found.");return}let t=n.data.map(r=>({ID:r.id,Name:r.name,URL:r.url.substring(0,40)+(r.url.length>40?"...":""),Events:r.events.join(", "),Active:r.active?"Yes":"No"}));m(t,"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
2320
2320
 
2321
2321
  USAGE
2322
2322
  emailr webhooks get <webhook_id> [options]
@@ -2347,7 +2347,7 @@ EXAMPLES
2347
2347
  emailr webhooks get whk_abc123 --format json
2348
2348
 
2349
2349
  # Extract just the secret
2350
- emailr webhooks get whk_abc123 --format json | jq -r '.secret'`).option("--format <format>","Output format (json|table)","table").action(async(a,e)=>{try{let t=d(),i=await new Emailr({apiKey:t.apiKey,baseUrl:t.baseUrl}).webhooks.get(a);e.format==="json"?m(i,"json"):m({ID:i.id,Name:i.name,URL:i.url,Events:i.events.join(", "),Active:i.active?"Yes":"No",Secret:i.secret,"Created At":i.created_at},"table");}catch(t){l(t instanceof Error?t.message:"Failed to get webhook"),process.exit(1);}}),o.command("create").description(`Create a new webhook
2350
+ emailr webhooks get whk_abc123 --format json | jq -r '.secret'`).option("--format <format>","Output format (json|table)","table").action(async(a,e)=>{try{let o=d(),t=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).webhooks.get(a);e.format==="json"?m(t,"json"):m({ID:t.id,Name:t.name,URL:t.url,Events:t.events.join(", "),Active:t.active?"Yes":"No",Secret:t.secret,"Created At":t.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
2351
2351
 
2352
2352
  USAGE
2353
2353
  emailr webhooks create --name <name> --url <url> --events <events> [options]
@@ -2421,7 +2421,7 @@ EXAMPLES
2421
2421
 
2422
2422
  NOTE
2423
2423
  Save the webhook secret returned by this command. You'll need it
2424
- 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 a=>{try{let e=d(),t=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),n=a.events.split(",").map(r=>r.trim()),i=await t.webhooks.create({name:a.name,url:a.url,events:n});a.format==="json"?m(i,"json"):(p("Webhook created successfully!"),m({ID:i.id,Name:i.name,URL:i.url,Secret:i.secret},"table"));}catch(e){l(e instanceof Error?e.message:"Failed to create webhook"),process.exit(1);}}),o.command("update <webhook_id>").description(`Update a webhook
2424
+ 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 a=>{try{let e=d(),o=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),n=a.events.split(",").map(r=>r.trim()),t=await o.webhooks.create({name:a.name,url:a.url,events:n});a.format==="json"?m(t,"json"):(p("Webhook created successfully!"),m({ID:t.id,Name:t.name,URL:t.url,Secret:t.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
2425
2425
 
2426
2426
  USAGE
2427
2427
  emailr webhooks update <webhook_id> [options]
@@ -2466,7 +2466,7 @@ EXAMPLES
2466
2466
  --events "email.delivered,email.bounced"
2467
2467
 
2468
2468
  # Get JSON output
2469
- 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(a,e)=>{try{let t=d(),n=new Emailr({apiKey:t.apiKey,baseUrl:t.baseUrl}),i={};e.name&&(i.name=e.name),e.url&&(i.url=e.url),e.events&&(i.events=e.events.split(",").map(s=>s.trim()));let r=await n.webhooks.update(a,i);e.format==="json"?m(r,"json"):(p("Webhook updated successfully!"),m({ID:r.id,Name:r.name,URL:r.url},"table"));}catch(t){l(t instanceof Error?t.message:"Failed to update webhook"),process.exit(1);}}),o.command("enable <webhook_id>").description(`Enable a webhook
2469
+ 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(a,e)=>{try{let o=d(),n=new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}),t={};e.name&&(t.name=e.name),e.url&&(t.url=e.url),e.events&&(t.events=e.events.split(",").map(s=>s.trim()));let r=await n.webhooks.update(a,t);e.format==="json"?m(r,"json"):(p("Webhook updated successfully!"),m({ID:r.id,Name:r.name,URL:r.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
2470
2470
 
2471
2471
  USAGE
2472
2472
  emailr webhooks enable <webhook_id> [options]
@@ -2490,7 +2490,7 @@ EXAMPLES
2490
2490
  emailr webhooks enable whk_abc123
2491
2491
 
2492
2492
  # Get JSON output
2493
- emailr webhooks enable whk_abc123 --format json`).option("--format <format>","Output format (json|table)","table").action(async(a,e)=>{try{let t=d(),i=await new Emailr({apiKey:t.apiKey,baseUrl:t.baseUrl}).webhooks.enable(a);e.format==="json"?m(i,"json"):p("Webhook enabled successfully!");}catch(t){l(t instanceof Error?t.message:"Failed to enable webhook"),process.exit(1);}}),o.command("disable <webhook_id>").description(`Disable a webhook
2493
+ emailr webhooks enable whk_abc123 --format json`).option("--format <format>","Output format (json|table)","table").action(async(a,e)=>{try{let o=d(),t=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).webhooks.enable(a);e.format==="json"?m(t,"json"):p("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
2494
2494
 
2495
2495
  USAGE
2496
2496
  emailr webhooks disable <webhook_id> [options]
@@ -2519,7 +2519,7 @@ EXAMPLES
2519
2519
 
2520
2520
  NOTE
2521
2521
  Events are not queued while webhook is disabled. If you need to
2522
- temporarily stop processing, consider handling this in your endpoint.`).option("--format <format>","Output format (json|table)","table").action(async(a,e)=>{try{let t=d(),i=await new Emailr({apiKey:t.apiKey,baseUrl:t.baseUrl}).webhooks.disable(a);e.format==="json"?m(i,"json"):p("Webhook disabled successfully!");}catch(t){l(t instanceof Error?t.message:"Failed to disable webhook"),process.exit(1);}}),o.command("delete <webhook_id>").description(`Delete a webhook
2522
+ temporarily stop processing, consider handling this in your endpoint.`).option("--format <format>","Output format (json|table)","table").action(async(a,e)=>{try{let o=d(),t=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).webhooks.disable(a);e.format==="json"?m(t,"json"):p("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
2523
2523
 
2524
2524
  USAGE
2525
2525
  emailr webhooks delete <webhook_id> [options]
@@ -2547,7 +2547,7 @@ EXAMPLES
2547
2547
 
2548
2548
  WARNING
2549
2549
  This action is permanent and cannot be undone.
2550
- Create a new webhook if you need to restore functionality.`).option("--format <format>","Output format (json|table)","table").action(async(a,e)=>{try{let t=d(),i=await new Emailr({apiKey:t.apiKey,baseUrl:t.baseUrl}).webhooks.delete(a);e.format==="json"?m(i,"json"):p("Webhook deleted successfully!");}catch(t){l(t instanceof Error?t.message:"Failed to delete webhook"),process.exit(1);}}),o}function Pe(){let o=new Command("segments").description(`Manage contact segments
2550
+ Create a new webhook if you need to restore functionality.`).option("--format <format>","Output format (json|table)","table").action(async(a,e)=>{try{let o=d(),t=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).webhooks.delete(a);e.format==="json"?m(t,"json"):p("Webhook deleted successfully!");}catch(o){l(o instanceof Error?o.message:"Failed to delete webhook"),process.exit(1);}}),i}function Pe(){let i=new Command("segments").description(`Manage contact segments
2551
2551
 
2552
2552
  USAGE
2553
2553
  emailr segments <subcommand> [options]
@@ -2662,7 +2662,7 @@ EXAMPLES
2662
2662
 
2663
2663
  SEE ALSO
2664
2664
  emailr contacts Manage individual contacts
2665
- emailr broadcasts Send emails to segments`);return o.command("list").description(`List all segments
2665
+ emailr broadcasts Send emails to segments`);return i.command("list").description(`List all segments
2666
2666
 
2667
2667
  USAGE
2668
2668
  emailr segments list [options]
@@ -2687,7 +2687,7 @@ EXAMPLES
2687
2687
  emailr segments list --format json
2688
2688
 
2689
2689
  # Pipe JSON to jq for processing
2690
- 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 a=>{try{let e=d(),t=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),n={};if(a.tags){let r=a.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean);r.length>0&&(n.tags=r.join(","));}let i=await t.segments.list(n);if(a.format==="json")m(i,"json");else {if(i.length===0){console.log("No segments found.");return}let r=i.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()}));m(r,"table");}}catch(e){l(e instanceof Error?e.message:"Failed to list segments"),process.exit(1);}}),o.command("get <segment_id>").description(`Get segment details
2690
+ 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 a=>{try{let e=d(),o=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),n={};if(a.tags){let r=a.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean);r.length>0&&(n.tags=r.join(","));}let t=await o.segments.list(n);if(a.format==="json")m(t,"json");else {if(t.length===0){console.log("No segments found.");return}let r=t.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()}));m(r,"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
2691
2691
 
2692
2692
  USAGE
2693
2693
  emailr segments get <segment_id> [options]
@@ -2714,7 +2714,7 @@ EXAMPLES
2714
2714
  emailr segments get seg_abc123 --format json
2715
2715
 
2716
2716
  # Pipe JSON to jq to view conditions
2717
- emailr segments get seg_abc123 --format json | jq '.conditions'`).option("--format <format>","Output format (json|table)","table").action(async(a,e)=>{try{let t=d(),i=await new Emailr({apiKey:t.apiKey,baseUrl:t.baseUrl}).segments.get(a);e.format==="json"?m(i,"json"):m({ID:i.id,Name:i.name,Description:i.description||"N/A",Conditions:JSON.stringify(i.conditions),Tags:i.tags?.join(", ")||"-","Created At":i.created_at,"Updated At":i.updated_at},"table");}catch(t){l(t instanceof Error?t.message:"Failed to get segment"),process.exit(1);}}),o.command("create").description(`Create a new segment
2717
+ emailr segments get seg_abc123 --format json | jq '.conditions'`).option("--format <format>","Output format (json|table)","table").action(async(a,e)=>{try{let o=d(),t=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).segments.get(a);e.format==="json"?m(t,"json"):m({ID:t.id,Name:t.name,Description:t.description||"N/A",Conditions:JSON.stringify(t.conditions),Tags:t.tags?.join(", ")||"-","Created At":t.created_at,"Updated At":t.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
2718
2718
 
2719
2719
  USAGE
2720
2720
  emailr segments create --name <segment_name> --conditions <json> [options]
@@ -2764,7 +2764,7 @@ EXAMPLES
2764
2764
  # Get JSON output for scripting
2765
2765
  emailr segments create --name "Test" \\
2766
2766
  --conditions '[{"field": "subscribed", "operator": "equals", "value": true}]' \\
2767
- --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 a=>{try{let e=d(),t=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),n;try{n=JSON.parse(a.conditions);}catch{l("Invalid JSON for --conditions"),process.exit(1);}let i={name:a.name,description:a.description,conditions:n};a.tags&&(i.tags=a.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean));let r=await t.segments.create(i);a.format==="json"?m(r,"json"):(p("Segment created successfully!"),m({ID:r.id,Name:r.name,Tags:r.tags?.join(", ")||"-"},"table"));}catch(e){l(e instanceof Error?e.message:"Failed to create segment"),process.exit(1);}}),o.command("update <segment_id>").description(`Update a segment
2767
+ --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 a=>{try{let e=d(),o=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),n;try{n=JSON.parse(a.conditions);}catch{l("Invalid JSON for --conditions"),process.exit(1);}let t={name:a.name,description:a.description,conditions:n};a.tags&&(t.tags=a.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean));let r=await o.segments.create(t);a.format==="json"?m(r,"json"):(p("Segment created successfully!"),m({ID:r.id,Name:r.name,Tags:r.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
2768
2768
 
2769
2769
  USAGE
2770
2770
  emailr segments update <segment_id> [options]
@@ -2810,7 +2810,7 @@ EXAMPLES
2810
2810
  --conditions '[{"field": "metadata.plan", "operator": "equals", "value": "enterprise"}]'
2811
2811
 
2812
2812
  # Get JSON output
2813
- 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(a,e)=>{try{let t=d(),n=new Emailr({apiKey:t.apiKey,baseUrl:t.baseUrl}),i={};if(e.name&&(i.name=e.name),e.description&&(i.description=e.description),e.conditions)try{i.conditions=JSON.parse(e.conditions);}catch{l("Invalid JSON for --conditions"),process.exit(1);}e.tags&&(i.tags=e.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean));let r=await n.segments.update(a,i);e.format==="json"?m(r,"json"):(p("Segment updated successfully!"),m({ID:r.id,Name:r.name,Tags:r.tags?.join(", ")||"-"},"table"));}catch(t){l(t instanceof Error?t.message:"Failed to update segment"),process.exit(1);}}),o.command("delete <segment_id>").description(`Delete a segment
2813
+ 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(a,e)=>{try{let o=d(),n=new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}),t={};if(e.name&&(t.name=e.name),e.description&&(t.description=e.description),e.conditions)try{t.conditions=JSON.parse(e.conditions);}catch{l("Invalid JSON for --conditions"),process.exit(1);}e.tags&&(t.tags=e.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean));let r=await n.segments.update(a,t);e.format==="json"?m(r,"json"):(p("Segment updated successfully!"),m({ID:r.id,Name:r.name,Tags:r.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
2814
2814
 
2815
2815
  USAGE
2816
2816
  emailr segments delete <segment_id>
@@ -2835,7 +2835,7 @@ EXAMPLES
2835
2835
 
2836
2836
  WARNING
2837
2837
  This action is permanent and cannot be undone.
2838
- Any broadcasts targeting this segment will need to be updated.`).option("--format <format>","Output format (json|table)","table").action(async(a,e)=>{try{let t=d(),i=await new Emailr({apiKey:t.apiKey,baseUrl:t.baseUrl}).segments.delete(a);e.format==="json"?m(i,"json"):p("Segment deleted successfully!");}catch(t){l(t instanceof Error?t.message:"Failed to delete segment"),process.exit(1);}}),o.command("count <segment_id>").description(`Get the number of contacts in a segment
2838
+ Any broadcasts targeting this segment will need to be updated.`).option("--format <format>","Output format (json|table)","table").action(async(a,e)=>{try{let o=d(),t=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).segments.delete(a);e.format==="json"?m(t,"json"):p("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
2839
2839
 
2840
2840
  USAGE
2841
2841
  emailr segments count <segment_id> [options]
@@ -2866,7 +2866,7 @@ EXAMPLES
2866
2866
 
2867
2867
  TIP
2868
2868
  Use this before sending broadcasts to verify your segment
2869
- targets the expected number of contacts.`).option("--format <format>","Output format (json|table)","table").action(async(a,e)=>{try{let t=d(),i=await new Emailr({apiKey:t.apiKey,baseUrl:t.baseUrl}).segments.getContactsCount(a);e.format==="json"?m(i,"json"):console.log(`Segment contains ${i.count} contacts.`);}catch(t){l(t instanceof Error?t.message:"Failed to get segment count"),process.exit(1);}}),o}function yt(o){try{let a=o.startsWith("http")?o:`http://localhost${o}`,e=new URL(a);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 St(){return `<!DOCTYPE html>
2869
+ targets the expected number of contacts.`).option("--format <format>","Output format (json|table)","table").action(async(a,e)=>{try{let o=d(),t=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).segments.getContactsCount(a);e.format==="json"?m(t,"json"):console.log(`Segment contains ${t.count} contacts.`);}catch(o){l(o instanceof Error?o.message:"Failed to get segment count"),process.exit(1);}}),i}function yt(i){try{let a=i.startsWith("http")?i:`http://localhost${i}`,e=new URL(a);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 St(){return `<!DOCTYPE html>
2870
2870
  <html lang="en">
2871
2871
  <head>
2872
2872
  <meta charset="UTF-8">
@@ -2912,7 +2912,7 @@ TIP
2912
2912
  <p>You can close this window and return to your terminal.</p>
2913
2913
  </div>
2914
2914
  </body>
2915
- </html>`}function ie(o){return `<!DOCTYPE html>
2915
+ </html>`}function oe(i){return `<!DOCTYPE html>
2916
2916
  <html lang="en">
2917
2917
  <head>
2918
2918
  <meta charset="UTF-8">
@@ -2963,11 +2963,11 @@ TIP
2963
2963
  <div class="icon">\u2717</div>
2964
2964
  <h1>Login Failed</h1>
2965
2965
  <p>Something went wrong during authentication.</p>
2966
- <div class="error-message">${o.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#039;")}</div>
2966
+ <div class="error-message">${i.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#039;")}</div>
2967
2967
  <p style="margin-top: 1rem;">Please close this window and try again.</p>
2968
2968
  </div>
2969
2969
  </body>
2970
- </html>`}function Ae(){let o=null,a=0,e=null,t=null,n=null;return {async start(){return new Promise((i,r)=>{o=at.createServer((s,c)=>{if(s.method!=="GET"||!s.url?.startsWith("/callback")){c.writeHead(404,{"Content-Type":"text/plain"}),c.end("Not Found");return}let b=yt(s.url);if(n&&b.state!==n){c.writeHead(400,{"Content-Type":"text/html"}),c.end(ie("Security verification failed. State parameter mismatch.")),e&&e({success:false,error:"State parameter mismatch"});return}if(b.error){let f=b.message||b.error;c.writeHead(200,{"Content-Type":"text/html"}),c.end(ie(f)),e&&e({success:false,error:f});return}let g=b.key||b.code;if(g){c.writeHead(200,{"Content-Type":"text/html"}),c.end(St()),e&&e({success:true,apiKey:g});return}c.writeHead(400,{"Content-Type":"text/html"}),c.end(ie("Invalid callback: missing required parameters.")),e&&e({success:false,error:"Invalid callback: missing required parameters"});}),o.listen(0,"127.0.0.1",()=>{let s=o.address();s&&typeof s=="object"?(a=s.port,i({port:a,url:`http://127.0.0.1:${a}/callback`})):r(new Error("Failed to get server address"));}),o.on("error",s=>{r(new Error(`Failed to start callback server: ${s.message}`));});})},async waitForCallback(i,r){return n=i,new Promise(s=>{e=s,t=setTimeout(()=>{e&&e({success:false,error:"Login timed out. Please try again."});},r);})},async stop(){if(t&&(clearTimeout(t),t=null),o)return new Promise(i=>{o.close(()=>{o=null,i();});})}}}function Re(){return vt.randomBytes(32).toString("hex")}function Me(o){return new Promise(a=>{let e=process.platform,t;switch(e){case "darwin":t=`open "${o}"`;break;case "win32":t=`start "" "${o}"`;break;default:t=`xdg-open "${o}"`;break}exec(t,n=>{a(!n);});})}var X=120,Ot=process.env.EMAILR_WEB_URL||"https://app.emailr.dev";function Et(o,a){let e=`http://127.0.0.1:${a}/callback`,t=new URLSearchParams({state:o,callback_url:e});return `${Ot}/consent/authorize?${t.toString()}`}function De(){return new Command("login").description("Log in to Emailr via browser authentication").option("-t, --timeout <seconds>","Timeout in seconds",String(X)).option("--no-browser","Don't automatically open the browser").action(async a=>{await _t({timeout:parseInt(a.timeout,10)||X,noBrowser:a.browser===false});})}async function _t(o){let a=Ae(),e=(o.timeout||X)*1e3;try{u("Starting authentication server...");let{port:t,url:n}=await a.start(),i=Re(),r=Et(i,t);console.log(""),u("Authorization URL:"),console.log(` ${r}`),console.log(""),o.noBrowser?u("Please open the URL above in your browser to continue."):await Me(r)?u("Browser opened. Please complete authentication in your browser."):(N("Could not open browser automatically."),u("Please open the URL above in your browser to continue.")),console.log(""),u(`Waiting for authentication (timeout: ${o.timeout||X}s)...`);let s=await a.waitForCallback(i,e);s.success&&s.apiKey?(K({apiKey:s.apiKey}),console.log(""),p("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(t){console.log(""),l(t instanceof Error?t.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 a.stop();}}var re=E.join(V.homedir(),".config","opencode","skills","emailr-cli"),Ct=`---
2970
+ </html>`}function Ae(){let i=null,a=0,e=null,o=null,n=null;return {async start(){return new Promise((t,r)=>{i=at.createServer((s,c)=>{if(s.method!=="GET"||!s.url?.startsWith("/callback")){c.writeHead(404,{"Content-Type":"text/plain"}),c.end("Not Found");return}let b=yt(s.url);if(n&&b.state!==n){c.writeHead(400,{"Content-Type":"text/html"}),c.end(oe("Security verification failed. State parameter mismatch.")),e&&e({success:false,error:"State parameter mismatch"});return}if(b.error){let f=b.message||b.error;c.writeHead(200,{"Content-Type":"text/html"}),c.end(oe(f)),e&&e({success:false,error:f});return}let g=b.key||b.code;if(g){c.writeHead(200,{"Content-Type":"text/html"}),c.end(St()),e&&e({success:true,apiKey:g});return}c.writeHead(400,{"Content-Type":"text/html"}),c.end(oe("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"?(a=s.port,t({port:a,url:`http://127.0.0.1:${a}/callback`})):r(new Error("Failed to get server address"));}),i.on("error",s=>{r(new Error(`Failed to start callback server: ${s.message}`));});})},async waitForCallback(t,r){return n=t,new Promise(s=>{e=s,o=setTimeout(()=>{e&&e({success:false,error:"Login timed out. Please try again."});},r);})},async stop(){if(o&&(clearTimeout(o),o=null),i)return new Promise(t=>{i.close(()=>{i=null,t();});})}}}function Re(){return vt.randomBytes(32).toString("hex")}function De(i){return new Promise(a=>{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,n=>{a(!n);});})}var X=120,Ot=process.env.EMAILR_WEB_URL||"https://app.emailr.dev";function Et(i,a){let e=`http://127.0.0.1:${a}/callback`,o=new URLSearchParams({state:i,callback_url:e});return `${Ot}/consent/authorize?${o.toString()}`}function Me(){return new Command("login").description("Log in to Emailr via browser authentication").option("-t, --timeout <seconds>","Timeout in seconds",String(X)).option("--no-browser","Don't automatically open the browser").action(async a=>{await _t({timeout:parseInt(a.timeout,10)||X,noBrowser:a.browser===false});})}async function _t(i){let a=Ae(),e=(i.timeout||X)*1e3;try{u("Starting authentication server...");let{port:o,url:n}=await a.start(),t=Re(),r=Et(t,o);console.log(""),u("Authorization URL:"),console.log(` ${r}`),console.log(""),i.noBrowser?u("Please open the URL above in your browser to continue."):await De(r)?u("Browser opened. Please complete authentication in your browser."):(N("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||X}s)...`);let s=await a.waitForCallback(t,e);s.success&&s.apiKey?(K({apiKey:s.apiKey}),console.log(""),p("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 a.stop();}}var re=E.join(V.homedir(),".config","opencode","skills","emailr-cli"),Ct=`---
2971
2971
  name: emailr-cli
2972
2972
  description: Operate the Emailr CLI to send emails, reply to threads, manage contacts, templates, inboxes, domains, broadcasts, webhooks, and segments. Includes thread reply auto-resolution and live preview editing for templates.
2973
2973
  ---
@@ -3083,7 +3083,7 @@ emailr domains add example.com
3083
3083
  emailr domains verify example.com
3084
3084
  emailr domains list
3085
3085
  \`\`\`
3086
- `;function Ut(){try{return execSync("which opencode",{stdio:"ignore"}),!0}catch{return false}}function kt(){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 Pt(){x.existsSync(re)||x.mkdirSync(re,{recursive:true});let o=E.join(re,"SKILL.md");x.writeFileSync(o,Ct,"utf-8");}function Fe(){return new Command("agent").description(`Launch an AI agent with Emailr CLI expertise
3086
+ `;function Ut(){try{return execSync("which opencode",{stdio:"ignore"}),!0}catch{return false}}function kt(){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 Pt(){x.existsSync(re)||x.mkdirSync(re,{recursive:true});let i=E.join(re,"SKILL.md");x.writeFileSync(i,Ct,"utf-8");}function Fe(){return new Command("agent").description(`Launch an AI agent with Emailr CLI expertise
3087
3087
 
3088
3088
  This opens OpenCode (opencode.ai), an AI coding agent that knows how to use all Emailr CLI commands.
3089
3089
  The agent can help you:
@@ -3094,7 +3094,7 @@ The agent can help you:
3094
3094
  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 a=>{Ut()||(a.install?kt()||(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(`
3095
3095
  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{Pt(),p("Emailr CLI skill loaded");}catch(n){N(`Could not install skill: ${n instanceof Error?n.message:String(n)}`);}let e=[];a.model&&e.push("--model",a.model),console.log(`
3096
3096
  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.
3097
- `);let t=spawn("opencode",e,{stdio:"inherit",env:process.env});t.on("error",n=>{l(`Failed to start agent: ${n.message}`),process.exit(1);}),t.on("exit",n=>{process.exit(n??0);});})}function He(){let o=new Command("inbox").description(`Manage inbound emails (inbox)
3097
+ `);let o=spawn("opencode",e,{stdio:"inherit",env:process.env});o.on("error",n=>{l(`Failed to start agent: ${n.message}`),process.exit(1);}),o.on("exit",n=>{process.exit(n??0);});})}function He(){let i=new Command("inbox").description(`Manage inbound emails (inbox)
3098
3098
 
3099
3099
  USAGE
3100
3100
  emailr inbox <subcommand> [options]
@@ -3146,7 +3146,7 @@ EXAMPLES
3146
3146
 
3147
3147
  SEE ALSO
3148
3148
  emailr send Send individual emails
3149
- emailr emails View all emails (sent and received)`);return o.command("list").description(`List received emails
3149
+ emailr emails View all emails (sent and received)`);return i.command("list").description(`List received emails
3150
3150
 
3151
3151
  USAGE
3152
3152
  emailr inbox list [options]
@@ -3174,7 +3174,7 @@ EXAMPLES
3174
3174
 
3175
3175
  OUTPUT FORMATS
3176
3176
  --format json Machine-readable JSON with data array and pagination
3177
- --format table Human-readable table with ID, From, Subject, To, Date (default)`).option("--limit <count>","Number of emails to return","20").option("--page <number>","Page number","1").option("--email <address>","Filter by sender email (partial match)").option("--domain <domain>","Filter by sender domain").option("--inbox-id <inbox_id>","Filter by inbox ID").option("--format <format>","Output format (json|table)","table").action(async a=>{try{let e=d(),t=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),n={status:"received",page:parseInt(a.page),limit:Math.min(parseInt(a.limit),100),email:a.email,domain:a.domain};a.inboxId&&(n.inbox_id=a.inboxId);let i=await t.emails.list(n);if(a.format==="json")m(i,"json");else {if(!i.data||i.data.length===0){u("No emails in inbox");return}let s=i.data.map(c=>({ID:c.id,From:c.from_email,Subject:Ke(c.subject||"(no subject)",40),To:c.to_email,Date:se(c.created_at),Attachments:c.attachments?.length||0}));m(s,"table"),u(`Page ${i.pagination.page} of ${i.pagination.pages} (${i.pagination.total} total)`);}}catch(e){l(e instanceof Error?e.message:"Failed to list inbox"),process.exit(1);}}),o.command("get <id>").description(`View a received email
3177
+ --format table Human-readable table with ID, From, Subject, To, Date (default)`).option("--limit <count>","Number of emails to return","20").option("--page <number>","Page number","1").option("--email <address>","Filter by sender email (partial match)").option("--domain <domain>","Filter by sender domain").option("--inbox-id <inbox_id>","Filter by inbox ID").option("--format <format>","Output format (json|table)","table").action(async a=>{try{let e=d(),o=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),n={status:"received",page:parseInt(a.page),limit:Math.min(parseInt(a.limit),100),email:a.email,domain:a.domain};a.inboxId&&(n.inbox_id=a.inboxId);let t=await o.emails.list(n);if(a.format==="json")m(t,"json");else {if(!t.data||t.data.length===0){u("No emails in inbox");return}let s=t.data.map(c=>({ID:c.id,From:c.from_email,Subject:Ke(c.subject||"(no subject)",40),To:c.to_email,Date:se(c.created_at),Attachments:c.attachments?.length||0}));m(s,"table"),u(`Page ${t.pagination.page} of ${t.pagination.pages} (${t.pagination.total} total)`);}}catch(e){l(e instanceof Error?e.message:"Failed to list inbox"),process.exit(1);}}),i.command("get <id>").description(`View a received email
3178
3178
 
3179
3179
  USAGE
3180
3180
  emailr inbox get <email-id> [options]
@@ -3195,7 +3195,7 @@ EXAMPLES
3195
3195
 
3196
3196
  OUTPUT FORMATS
3197
3197
  --format json Full email object with all fields as JSON
3198
- --format table Key-value table with email metadata and content preview (default)`).option("--content <type>","Content to display: preview | text | html","preview").option("--format <format>","Output format (json|table)","table").action(async(a,e)=>{try{let t=d(),i=await new Emailr({apiKey:t.apiKey,baseUrl:t.baseUrl}).emails.get(a);if(e.format==="json")m(i,"json");else {if(m({ID:i.id,From:i.from_email,To:i.to_email,Subject:i.subject||"(no subject)",Date:se(i.created_at),Status:i.status,"Thread ID":i.thread_id||"-","Parent Email":i.parent_email_id||"-",Attachments:i.attachments?.length||0},"table"),console.log(""),e.content==="html")console.log(i.html_content||"(no HTML content)");else if(e.content==="text")console.log(i.text_content||"(no text content)");else {let s=i.text_content||i.html_content?.replace(/<[^>]*>/g,"")||"(no content)";console.log(s);}if(i.attachments&&i.attachments.length>0){console.log(""),u("Attachments:");let s=i.attachments.map(c=>({Filename:c.filename,Type:c.contentType||c.content_type||"-",Size:Rt(c.size||0)}));m(s,"table");}}}catch(t){l(t instanceof Error?t.message:"Failed to get email"),process.exit(1);}}),o.command("thread <id>").description(`View conversation thread for an email
3198
+ --format table Key-value table with email metadata and content preview (default)`).option("--content <type>","Content to display: preview | text | html","preview").option("--format <format>","Output format (json|table)","table").action(async(a,e)=>{try{let o=d(),t=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).emails.get(a);if(e.format==="json")m(t,"json");else {if(m({ID:t.id,From:t.from_email,To:t.to_email,Subject:t.subject||"(no subject)",Date:se(t.created_at),Status:t.status,"Thread ID":t.thread_id||"-","Parent Email":t.parent_email_id||"-",Attachments:t.attachments?.length||0},"table"),console.log(""),e.content==="html")console.log(t.html_content||"(no HTML content)");else if(e.content==="text")console.log(t.text_content||"(no text content)");else {let s=t.text_content||t.html_content?.replace(/<[^>]*>/g,"")||"(no content)";console.log(s);}if(t.attachments&&t.attachments.length>0){console.log(""),u("Attachments:");let s=t.attachments.map(c=>({Filename:c.filename,Type:c.contentType||c.content_type||"-",Size:Rt(c.size||0)}));m(s,"table");}}}catch(o){l(o instanceof Error?o.message:"Failed to get email"),process.exit(1);}}),i.command("thread <id>").description(`View conversation thread for an email
3199
3199
 
3200
3200
  USAGE
3201
3201
  emailr inbox thread <email-id> [options]
@@ -3214,7 +3214,7 @@ EXAMPLES
3214
3214
 
3215
3215
  OUTPUT FORMATS
3216
3216
  --format json JSON array of all emails in the thread
3217
- --format table Chronological conversation view with direction indicators (default)`).option("--format <format>","Output format (json|table)","table").action(async(a,e)=>{try{let t=d(),n=new Emailr({apiKey:t.apiKey,baseUrl:t.baseUrl}),i=await n.emails.get(a),r=i.thread_id||i.id,s=[],c=new Set;if(s.push(i),c.add(i.id),i.thread_id&&i.thread_id!==i.id)try{let f=await n.emails.get(i.thread_id);c.has(f.id)||(s.push(f),c.add(f.id));}catch{}let b=await n.emails.list({limit:100});if(b.data)for(let f of b.data)c.has(f.id)||(f.thread_id===r||f.parent_email_id===i.id||f.id===i.parent_email_id)&&(s.push(f),c.add(f.id));if(s.sort((f,h)=>new Date(f.created_at).getTime()-new Date(h.created_at).getTime()),e.format==="json")m(s,"json");else {s.length<=1&&u("No other emails in this conversation"),u(`Conversation (${s.length} email${s.length!==1?"s":""}):`),console.log("");for(let f of s){let h=f.status==="received"?"\u2190 IN ":"\u2192 OUT",S=f.id===a?" \u25C0 (selected)":"";console.log(`${h} ${se(f.created_at)}${S}`),console.log(` From: ${f.from_email}`),console.log(` To: ${f.to_email}`),console.log(` Subject: ${f.subject||"(no subject)"}`);let _=f.text_content||f.html_content?.replace(/<[^>]*>/g,"")||"";_&&console.log(` ${Ke(_.trim(),120)}`),console.log("");}}await new Promise(f=>process.stdout.write("",()=>f())),process.exit(0);}catch(t){l(t instanceof Error?t.message:"Failed to load thread"),process.exit(1);}}),o.command("reply <id>").description(`Reply to a received email
3217
+ --format table Chronological conversation view with direction indicators (default)`).option("--format <format>","Output format (json|table)","table").action(async(a,e)=>{try{let o=d(),n=new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}),t=await n.emails.get(a),r=t.thread_id||t.id,s=[],c=new Set;if(s.push(t),c.add(t.id),t.thread_id&&t.thread_id!==t.id)try{let f=await n.emails.get(t.thread_id);c.has(f.id)||(s.push(f),c.add(f.id));}catch{}let b=await n.emails.list({limit:100});if(b.data)for(let f of b.data)c.has(f.id)||(f.thread_id===r||f.parent_email_id===t.id||f.id===t.parent_email_id)&&(s.push(f),c.add(f.id));if(s.sort((f,h)=>new Date(f.created_at).getTime()-new Date(h.created_at).getTime()),e.format==="json")m(s,"json");else {s.length<=1&&u("No other emails in this conversation"),u(`Conversation (${s.length} email${s.length!==1?"s":""}):`),console.log("");for(let f of s){let h=f.status==="received"?"\u2190 IN ":"\u2192 OUT",S=f.id===a?" \u25C0 (selected)":"";console.log(`${h} ${se(f.created_at)}${S}`),console.log(` From: ${f.from_email}`),console.log(` To: ${f.to_email}`),console.log(` Subject: ${f.subject||"(no subject)"}`);let _=f.text_content||f.html_content?.replace(/<[^>]*>/g,"")||"";_&&console.log(` ${Ke(_.trim(),120)}`),console.log("");}}await new Promise(f=>process.stdout.write("",()=>f())),process.exit(0);}catch(o){l(o instanceof Error?o.message:"Failed to load thread"),process.exit(1);}}),i.command("reply <id>").description(`Reply to a received email
3218
3218
 
3219
3219
  USAGE
3220
3220
  emailr inbox reply <email-id> [options]
@@ -3250,7 +3250,7 @@ EXAMPLES
3250
3250
 
3251
3251
  OUTPUT FORMATS
3252
3252
  --format json Machine-readable JSON with message_id and status
3253
- --format table Human-readable summary with Message ID, To, Subject, Status (default)`).option("--html <content>","HTML content for reply").option("--text <content>","Plain text content for reply").option("--html-file <path>","Read HTML content from file").option("--text-file <path>","Read plain text content from file").option("--from <email>","Override sender address").option("--cc <emails>","CC recipients (comma-separated)").option("--bcc <emails>","BCC recipients (comma-separated)").option("--subject <subject>","Override reply subject").option("--format <format>","Output format (json|table)","table").action(async(a,e)=>{try{let t=d(),n=new Emailr({apiKey:t.apiKey,baseUrl:t.baseUrl}),i=await n.emails.get(a),r=e.html,s=e.text;if(e.htmlFile)try{r=readFileSync(e.htmlFile,"utf-8");}catch{l(`Failed to read HTML file: ${e.htmlFile}`),process.exit(1);}if(e.textFile)try{s=readFileSync(e.textFile,"utf-8");}catch{l(`Failed to read text file: ${e.textFile}`),process.exit(1);}!r&&!s&&(l("Reply content is required. Use --html, --text, --html-file, or --text-file"),process.exit(1));let c=e.subject||(i.subject?.startsWith("Re:")?i.subject:`Re: ${i.subject||""}`),b={to:i.from_email,from:e.from||i.to_email,subject:c,html:r||void 0,text:s||r?.replace(/<[^>]*>/g,"")||void 0,replyTo:{in_reply_to:i.message_id||i.ses_message_id,thread_id:i.thread_id||i.id,parent_email_id:i.id}};if(e.cc){let h=e.cc.split(",").map(S=>S.trim());b.cc=h.length===1?h[0]:h;}if(e.bcc){let h=e.bcc.split(",").map(S=>S.trim());b.bcc=h.length===1?h[0]:h;}let g=await n.emails.send(b);e.format==="json"?m(g,"json"):(p("Reply sent successfully!"),m({"Message ID":g.message_id,To:i.from_email,Subject:c,Status:g.status},"table")),await new Promise(h=>process.stdout.write("",()=>h())),process.exit(0);}catch(t){l(t instanceof Error?t.message:"Failed to send reply"),process.exit(1);}}),o.command("forward <id>").description(`Forward a received email
3253
+ --format table Human-readable summary with Message ID, To, Subject, Status (default)`).option("--html <content>","HTML content for reply").option("--text <content>","Plain text content for reply").option("--html-file <path>","Read HTML content from file").option("--text-file <path>","Read plain text content from file").option("--from <email>","Override sender address").option("--cc <emails>","CC recipients (comma-separated)").option("--bcc <emails>","BCC recipients (comma-separated)").option("--subject <subject>","Override reply subject").option("--format <format>","Output format (json|table)","table").action(async(a,e)=>{try{let o=d(),n=new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}),t=await n.emails.get(a),r=e.html,s=e.text;if(e.htmlFile)try{r=readFileSync(e.htmlFile,"utf-8");}catch{l(`Failed to read HTML file: ${e.htmlFile}`),process.exit(1);}if(e.textFile)try{s=readFileSync(e.textFile,"utf-8");}catch{l(`Failed to read text file: ${e.textFile}`),process.exit(1);}!r&&!s&&(l("Reply content is required. Use --html, --text, --html-file, or --text-file"),process.exit(1));let c=e.subject||(t.subject?.startsWith("Re:")?t.subject:`Re: ${t.subject||""}`),b={to:t.from_email,from:e.from||t.to_email,subject:c,html:r||void 0,text:s||r?.replace(/<[^>]*>/g,"")||void 0,replyTo:{in_reply_to:t.message_id||t.ses_message_id,thread_id:t.thread_id||t.id,parent_email_id:t.id}};if(e.cc){let h=e.cc.split(",").map(S=>S.trim());b.cc=h.length===1?h[0]:h;}if(e.bcc){let h=e.bcc.split(",").map(S=>S.trim());b.bcc=h.length===1?h[0]:h;}let g=await n.emails.send(b);e.format==="json"?m(g,"json"):(p("Reply sent successfully!"),m({"Message ID":g.message_id,To:t.from_email,Subject:c,Status:g.status},"table")),await new Promise(h=>process.stdout.write("",()=>h())),process.exit(0);}catch(o){l(o instanceof Error?o.message:"Failed to send reply"),process.exit(1);}}),i.command("forward <id>").description(`Forward a received email
3254
3254
 
3255
3255
  USAGE
3256
3256
  emailr inbox forward <email-id> --to <recipients> [options]
@@ -3276,7 +3276,7 @@ EXAMPLES
3276
3276
 
3277
3277
  OUTPUT FORMATS
3278
3278
  --format json Machine-readable JSON with message_id and status
3279
- --format table Human-readable summary with Message ID, To, Recipients, Status (default)`).requiredOption("--to <emails>","Recipient email addresses (comma-separated)").option("--message <text>","Message to include with forwarded email").option("--format <format>","Output format (json|table)","table").action(async(a,e)=>{try{let t=d(),n=new Emailr({apiKey:t.apiKey,baseUrl:t.baseUrl}),i=e.to.split(",").map(c=>c.trim()).filter(Boolean),r=await n.emails.forward({email_id:a,to:i.length===1?i[0]:i,message:e.message});e.format==="json"?m(r,"json"):(p("Email forwarded successfully!"),m({"Message ID":r.message_id,To:i.join(", "),Recipients:r.recipients,Status:r.status},"table")),await new Promise(c=>process.stdout.write("",()=>c())),process.exit(0);}catch(t){l(t instanceof Error?t.message:"Failed to forward email"),process.exit(1);}}),o}function Ke(o,a){return o.length<=a?o:o.slice(0,a-1)+"\u2026"}function se(o){return new Date(o).toLocaleString()}function Rt(o){return o<1024?o+" B":o<1024*1024?(o/1024).toFixed(1)+" KB":(o/(1024*1024)).toFixed(1)+" MB"}function qe(){let o=new Command("inboxes").description(`Manage inboxes
3279
+ --format table Human-readable summary with Message ID, To, Recipients, Status (default)`).requiredOption("--to <emails>","Recipient email addresses (comma-separated)").option("--message <text>","Message to include with forwarded email").option("--format <format>","Output format (json|table)","table").action(async(a,e)=>{try{let o=d(),n=new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}),t=e.to.split(",").map(c=>c.trim()).filter(Boolean),r=await n.emails.forward({email_id:a,to:t.length===1?t[0]:t,message:e.message});e.format==="json"?m(r,"json"):(p("Email forwarded successfully!"),m({"Message ID":r.message_id,To:t.join(", "),Recipients:r.recipients,Status:r.status},"table")),await new Promise(c=>process.stdout.write("",()=>c())),process.exit(0);}catch(o){l(o instanceof Error?o.message:"Failed to forward email"),process.exit(1);}}),i}function Ke(i,a){return i.length<=a?i:i.slice(0,a-1)+"\u2026"}function se(i){return new Date(i).toLocaleString()}function Rt(i){return i<1024?i+" B":i<1024*1024?(i/1024).toFixed(1)+" KB":(i/(1024*1024)).toFixed(1)+" MB"}function qe(){let i=new Command("inboxes").description(`Manage inboxes
3280
3280
 
3281
3281
  USAGE
3282
3282
  emailr inboxes <subcommand> [options]
@@ -3306,7 +3306,7 @@ EXAMPLES
3306
3306
  emailr inboxes update inb_abc123 --name "Customer Support"
3307
3307
 
3308
3308
  # Delete an inbox
3309
- emailr inboxes delete inb_abc123`);return o.command("create").description(`Create a new inbox
3309
+ emailr inboxes delete inb_abc123`);return i.command("create").description(`Create a new inbox
3310
3310
 
3311
3311
  USAGE
3312
3312
  emailr inboxes create --name <name> --username <username> --domain <domain> [options]
@@ -3325,8 +3325,11 @@ EXAMPLES
3325
3325
  # Create a support inbox
3326
3326
  emailr inboxes create --name "Support" --username support --domain example.com
3327
3327
 
3328
+ # Create with custom reply-to
3329
+ emailr inboxes create --name "Support" --username support --domain example.com --reply-to replies@example.com
3330
+
3328
3331
  # Create and get JSON output
3329
- emailr inboxes create --name "Sales" --username sales --domain example.com --format json`).requiredOption("--name <name>","Inbox display name").requiredOption("--username <username>","Username for the email address").requiredOption("--domain <domain>","Domain for the email address").option("--format <format>","Output format: json | table","table").action(async a=>{try{let e=d(),n=await new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}).inboxes.create({name:a.name,username:a.username,domain:a.domain});a.format==="json"?m(n,"json"):(p(`Inbox created: ${n.id}`),m({ID:n.id,Name:n.name,"From Address":n.from_address,"Inbound Address":n.inbound_address,Created:n.created_at},"table"));}catch(e){l(e instanceof Error?e.message:"Failed to create inbox"),process.exit(1);}}),o.command("list").description(`List all inboxes
3332
+ emailr inboxes create --name "Sales" --username sales --domain example.com --format json`).requiredOption("--name <name>","Inbox display name").requiredOption("--username <username>","Username for the email address").requiredOption("--domain <domain>","Domain for the email address").option("--reply-to <email>","Custom reply-to address (defaults to username@mail.domain)").option("--format <format>","Output format: json | table","table").action(async a=>{try{let e=d(),o=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),n={name:a.name,username:a.username,domain:a.domain};a.replyTo&&(n.reply_to=a.replyTo);let t=await o.inboxes.create(n);a.format==="json"?m(t,"json"):(p(`Inbox created: ${t.id}`),m({ID:t.id,Name:t.name,"From Address":t.from_address,"Reply To":t.reply_to,"Inbound Address":t.inbound_address,Created:t.created_at},"table"));}catch(e){l(e instanceof Error?e.message:"Failed to create inbox"),process.exit(1);}}),i.command("list").description(`List all inboxes
3330
3333
 
3331
3334
  USAGE
3332
3335
  emailr inboxes list [options]
@@ -3342,8 +3345,8 @@ EXAMPLES
3342
3345
  emailr inboxes list
3343
3346
 
3344
3347
  # Get JSON output
3345
- emailr inboxes list --format json`).option("--format <format>","Output format: json | table","table").action(async a=>{try{let e=d(),n=await new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}).inboxes.list();if(a.format==="json")m(n,"json");else {if(n.length===0){console.log("No inboxes found.");return}let i=n.map(r=>({ID:r.id,Name:r.name,"From Address":r.from_address,"Inbound Address":r.inbound_address,Created:new Date(r.created_at).toLocaleDateString()}));m(i,"table"),console.log(`
3346
- Total: ${n.length}`);}}catch(e){l(e instanceof Error?e.message:"Failed to list inboxes"),process.exit(1);}}),o.command("get <inbox_id>").description(`Get an inbox by ID
3348
+ emailr inboxes list --format json`).option("--format <format>","Output format: json | table","table").action(async a=>{try{let e=d(),n=await new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}).inboxes.list();if(a.format==="json")m(n,"json");else {if(n.length===0){console.log("No inboxes found.");return}let t=n.map(r=>({ID:r.id,Name:r.name,"From Address":r.from_address,"Reply To":r.reply_to,"Inbound Address":r.inbound_address,Created:new Date(r.created_at).toLocaleDateString()}));m(t,"table"),console.log(`
3349
+ Total: ${n.length}`);}}catch(e){l(e instanceof Error?e.message:"Failed to list inboxes"),process.exit(1);}}),i.command("get <inbox_id>").description(`Get an inbox by ID
3347
3350
 
3348
3351
  USAGE
3349
3352
  emailr inboxes get <inbox_id> [options]
@@ -3362,7 +3365,7 @@ EXAMPLES
3362
3365
  emailr inboxes get inb_abc123
3363
3366
 
3364
3367
  # Get JSON output
3365
- emailr inboxes get inb_abc123 --format json`).option("--format <format>","Output format: json | table","table").action(async(a,e)=>{try{let t=d(),i=await new Emailr({apiKey:t.apiKey,baseUrl:t.baseUrl}).inboxes.get(a);e.format==="json"?m(i,"json"):m({ID:i.id,Name:i.name,Username:i.username,Domain:i.domain,"From Address":i.from_address,"Inbound Address":i.inbound_address,Created:i.created_at,Updated:i.updated_at},"table");}catch(t){l(t instanceof Error?t.message:"Failed to get inbox"),process.exit(1);}}),o.command("update <inbox_id>").description(`Update an inbox
3368
+ emailr inboxes get inb_abc123 --format json`).option("--format <format>","Output format: json | table","table").action(async(a,e)=>{try{let o=d(),t=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).inboxes.get(a);e.format==="json"?m(t,"json"):m({ID:t.id,Name:t.name,Username:t.username,Domain:t.domain,"From Address":t.from_address,"Reply To":t.reply_to,"Inbound Address":t.inbound_address,Created:t.created_at,Updated:t.updated_at},"table");}catch(o){l(o instanceof Error?o.message:"Failed to get inbox"),process.exit(1);}}),i.command("update <inbox_id>").description(`Update an inbox
3366
3369
 
3367
3370
  USAGE
3368
3371
  emailr inboxes update <inbox_id> --name <name> [options]
@@ -3382,8 +3385,14 @@ EXAMPLES
3382
3385
  # Update inbox name
3383
3386
  emailr inboxes update inb_abc123 --name "Customer Support"
3384
3387
 
3388
+ # Update reply-to address
3389
+ emailr inboxes update inb_abc123 --reply-to replies@example.com
3390
+
3391
+ # Reset reply-to to default
3392
+ emailr inboxes update inb_abc123 --reply-to none
3393
+
3385
3394
  # Get JSON output
3386
- emailr inboxes update inb_abc123 --name "New Name" --format json`).option("--name <name>","New inbox display name").option("--format <format>","Output format: json | table","table").action(async(a,e)=>{try{e.name||(l("No update fields specified. Use --name to update the inbox name."),process.exit(1));let t=d(),n=new Emailr({apiKey:t.apiKey,baseUrl:t.baseUrl}),i={};e.name&&(i.name=e.name);let r=await n.inboxes.update(a,i);e.format==="json"?m(r,"json"):(p(`Inbox updated: ${r.id}`),m({ID:r.id,Name:r.name,"From Address":r.from_address,"Inbound Address":r.inbound_address,Updated:r.updated_at},"table"));}catch(t){l(t instanceof Error?t.message:"Failed to update inbox"),process.exit(1);}}),o.command("delete <inbox_id>").description(`Delete an inbox
3395
+ emailr inboxes update inb_abc123 --name "New Name" --format json`).option("--name <name>","New inbox display name").option("--reply-to <email>",'New reply-to address (use "none" to reset to default)').option("--format <format>","Output format: json | table","table").action(async(a,e)=>{try{!e.name&&!e.replyTo&&(l("No update fields specified. Use --name or --reply-to to update the inbox."),process.exit(1));let o=d(),n=new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}),t={};e.name&&(t.name=e.name),e.replyTo&&(t.reply_to=e.replyTo==="none"?null:e.replyTo);let r=await n.inboxes.update(a,t);e.format==="json"?m(r,"json"):(p(`Inbox updated: ${r.id}`),m({ID:r.id,Name:r.name,"From Address":r.from_address,"Reply To":r.reply_to,"Inbound Address":r.inbound_address,Updated:r.updated_at},"table"));}catch(o){l(o instanceof Error?o.message:"Failed to update inbox"),process.exit(1);}}),i.command("delete <inbox_id>").description(`Delete an inbox
3387
3396
 
3388
3397
  USAGE
3389
3398
  emailr inboxes delete <inbox_id> [options]
@@ -3406,7 +3415,7 @@ EXAMPLES
3406
3415
  emailr inboxes delete inb_abc123 --format json
3407
3416
 
3408
3417
  WARNING
3409
- This action is permanent and cannot be undone.`).option("--format <format>","Output format: json | table","table").action(async(a,e)=>{try{let t=d(),i=await new Emailr({apiKey:t.apiKey,baseUrl:t.baseUrl}).inboxes.delete(a);e.format==="json"?m(i,"json"):p(`Inbox deleted: ${a}`);}catch(t){l(t instanceof Error?t.message:"Failed to delete inbox"),process.exit(1);}}),o}function Je(){let o=new Command("threads").description(`Manage email threads, labels, replies, and drafts
3418
+ This action is permanent and cannot be undone.`).option("--format <format>","Output format: json | table","table").action(async(a,e)=>{try{let o=d(),t=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).inboxes.delete(a);e.format==="json"?m(t,"json"):p(`Inbox deleted: ${a}`);}catch(o){l(o instanceof Error?o.message:"Failed to delete inbox"),process.exit(1);}}),i}function Je(){let i=new Command("threads").description(`Manage email threads, labels, replies, and drafts
3410
3419
 
3411
3420
  USAGE
3412
3421
  emailr threads <subcommand> [options]
@@ -3438,9 +3447,9 @@ EXAMPLES
3438
3447
  emailr threads list
3439
3448
 
3440
3449
  # Star a thread
3441
- emailr threads label <thread-id> --add starred`);o.command("list").description("List threads filtered by label").option("--label <label>","Filter by label (inbox, sent, starred, spam, trash, archived, all)","inbox").option("--limit <count>","Number of threads to return","20").option("--page <number>","Page number","1").option("--search <query>","Search by subject or sender").option("--inbox-id <id>","Filter by inbox ID").option("--format <format>","Output format (json|table)","table").action(async e=>{try{let t=d(),i=await new Emailr({apiKey:t.apiKey,baseUrl:t.baseUrl}).threads.list({label:e.label,page:parseInt(e.page),limit:Math.min(parseInt(e.limit),100),search:e.search,inbox_id:e.inboxId});if(e.format==="json")m(i,"json");else {if(!i.data||i.data.length===0){u(`No threads in ${e.label}`);return}let s=i.data.map(c=>({"Thread ID":c.thread_id.slice(0,8)+"\u2026",Subject:le(c.subject||"(no subject)",40),From:c.from_email,Messages:c.message_count,Labels:(c.labels||[]).join(", "),Updated:$e(c.updated_at)}));m(s,"table"),u(`Page ${i.pagination.page} of ${i.pagination.pages} (${i.pagination.total} total)`);}}catch(t){l(t instanceof Error?t.message:"Failed to list threads"),process.exit(1);}}),o.command("get <id>").description("View a thread with all messages").option("--format <format>","Output format (json|table)","table").action(async(e,t)=>{try{let n=d(),r=await new Emailr({apiKey:n.apiKey,baseUrl:n.baseUrl}).threads.get(e);if(t.format==="json")m(r,"json");else {u(`Thread: ${r.subject||"(no subject)"}`),u(`Labels: ${r.labels.join(", ")||"none"}`),u(`Messages: ${r.messages.length}`),console.log("");for(let c of r.messages){let b=c.status==="received"?"\u2190 IN ":"\u2192 OUT";console.log(`${b} ${$e(c.created_at)}`),console.log(` From: ${c.from_email}`),console.log(` To: ${c.to_email}`),c.cc_emails?.length&&console.log(` Cc: ${c.cc_emails.join(", ")}`),console.log(` Labels: ${c.labels.join(", ")||"none"}`);let g=c.text_content||c.html_content?.replace(/<[^>]*>/g,"")||"";g&&console.log(` ${le(g.trim(),120)}`),console.log("");}}await new Promise(c=>process.stdout.write("",()=>c())),process.exit(0);}catch(n){l(n instanceof Error?n.message:"Failed to get thread"),process.exit(1);}}),o.command("label <id>").description("Add or remove labels from a thread").option("--add <labels>","Labels to add (comma-separated)").option("--remove <labels>","Labels to remove (comma-separated)").option("--format <format>","Output format (json|table)","table").action(async(e,t)=>{try{!t.add&&!t.remove&&(l("Specify --add and/or --remove labels"),process.exit(1));let n=d(),i=new Emailr({apiKey:n.apiKey,baseUrl:n.baseUrl}),r=t.add?t.add.split(",").map(g=>g.trim()):void 0,s=t.remove?t.remove.split(",").map(g=>g.trim()):void 0,c=await i.threads.updateLabels(e,{add:r,remove:s});t.format==="json"?m(c,"json"):(p(`Updated ${c.updated} email(s) in thread`),r&&u(`Added: ${r.join(", ")}`),s&&u(`Removed: ${s.join(", ")}`)),await new Promise(g=>process.stdout.write("",()=>g())),process.exit(0);}catch(n){l(n instanceof Error?n.message:"Failed to update labels"),process.exit(1);}}),o.command("reply <id>").description("Reply to a thread (from/to/subject auto-resolved from inbox)").option("--html <content>","HTML content for the reply").option("--text <content>","Plain text content for the reply").option("--to <email>","Override recipient (auto-resolved if omitted)").option("--cc <emails>","CC recipients (comma-separated)").option("--bcc <emails>","BCC recipients (comma-separated)").option("--from <email>","Override sender (auto-resolved from inbox if omitted)").option("--from-name <name>","Override sender name (auto-resolved from inbox if omitted)").option("--reply-to <email>","Override Reply-To (auto-resolved from inbox if omitted)").option("--format <format>","Output format (json|table)","table").action(async(e,t)=>{try{!t.html&&!t.text&&(l("Provide --html or --text for the reply body"),process.exit(1));let n=d(),i=new Emailr({apiKey:n.apiKey,baseUrl:n.baseUrl}),r={};t.html&&(r.html=t.html),t.text&&(r.text=t.text),t.to&&(r.to=t.to),t.cc&&(r.cc=t.cc.split(",").map(b=>b.trim())),t.bcc&&(r.bcc=t.bcc.split(",").map(b=>b.trim())),t.from&&(r.from=t.from),t.fromName&&(r.from_name=t.fromName),t.replyTo&&(r.reply_to_email=t.replyTo);let s=await i.threads.reply(e,r);t.format==="json"?m(s,"json"):(p(`Reply sent to ${s.recipients} recipient(s)`),u(`Message ID: ${s.message_id}`)),await new Promise(b=>process.stdout.write("",()=>b())),process.exit(0);}catch(n){l(n instanceof Error?n.message:"Failed to send reply"),process.exit(1);}});let a=o.command("draft").description("Manage draft replies for threads");return a.command("save <id>").description("Save a draft reply for a thread").option("--html <content>","HTML content").option("--text <content>","Plain text content").option("--to <email>","Recipient").option("--cc <emails>","CC recipients").option("--bcc <emails>","BCC recipients").option("--from <email>","Sender").option("--reply-to <email>","Reply-To address").option("--format <format>","Output format (json|table)","table").action(async(e,t)=>{try{let n=d(),i=new Emailr({apiKey:n.apiKey,baseUrl:n.baseUrl}),r={};t.html&&(r.html=t.html),t.text&&(r.text=t.text),t.to&&(r.to=t.to),t.cc&&(r.cc=t.cc),t.bcc&&(r.bcc=t.bcc),t.from&&(r.from=t.from),t.replyTo&&(r.reply_to_email=t.replyTo);let s=await i.threads.saveDraft(e,r);t.format==="json"?m(s,"json"):(p(`Draft saved for thread ${e}`),u(`Draft ID: ${s.id}`)),await new Promise(b=>process.stdout.write("",()=>b())),process.exit(0);}catch(n){l(n instanceof Error?n.message:"Failed to save draft"),process.exit(1);}}),a.command("get <id>").description("Get the saved draft for a thread").option("--format <format>","Output format (json|table)","table").action(async(e,t)=>{try{let n=d(),r=await new Emailr({apiKey:n.apiKey,baseUrl:n.baseUrl}).threads.getDraft(e);t.format==="json"?m(r,"json"):(u(`Draft for thread: ${e}`),u(`To: ${r.to_email||"(auto)"}`),u(`From: ${r.from_email||"(auto)"}`),u(`Subject: ${r.subject||"(auto)"}`),r.html_content&&console.log(`
3450
+ emailr threads label <thread-id> --add starred`);i.command("list").description("List threads filtered by label").option("--label <label>","Filter by label (inbox, sent, starred, spam, trash, archived, all)","inbox").option("--limit <count>","Number of threads to return","20").option("--page <number>","Page number","1").option("--search <query>","Search by subject or sender").option("--inbox-id <id>","Filter by inbox ID").option("--format <format>","Output format (json|table)","table").action(async e=>{try{let o=d(),t=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).threads.list({label:e.label,page:parseInt(e.page),limit:Math.min(parseInt(e.limit),100),search:e.search,inbox_id:e.inboxId});if(e.format==="json")m(t,"json");else {if(!t.data||t.data.length===0){u(`No threads in ${e.label}`);return}let s=t.data.map(c=>({"Thread ID":c.thread_id.slice(0,8)+"\u2026",Subject:le(c.subject||"(no subject)",40),From:c.from_email,Messages:c.message_count,Labels:(c.labels||[]).join(", "),Updated:$e(c.updated_at)}));m(s,"table"),u(`Page ${t.pagination.page} of ${t.pagination.pages} (${t.pagination.total} total)`);}}catch(o){l(o instanceof Error?o.message:"Failed to list threads"),process.exit(1);}}),i.command("get <id>").description("View a thread with all messages").option("--format <format>","Output format (json|table)","table").action(async(e,o)=>{try{let n=d(),r=await new Emailr({apiKey:n.apiKey,baseUrl:n.baseUrl}).threads.get(e);if(o.format==="json")m(r,"json");else {u(`Thread: ${r.subject||"(no subject)"}`),u(`Labels: ${r.labels.join(", ")||"none"}`),u(`Messages: ${r.messages.length}`),console.log("");for(let c of r.messages){let b=c.status==="received"?"\u2190 IN ":"\u2192 OUT";console.log(`${b} ${$e(c.created_at)}`),console.log(` From: ${c.from_email}`),console.log(` To: ${c.to_email}`),c.cc_emails?.length&&console.log(` Cc: ${c.cc_emails.join(", ")}`),console.log(` Labels: ${c.labels.join(", ")||"none"}`);let g=c.text_content||c.html_content?.replace(/<[^>]*>/g,"")||"";g&&console.log(` ${le(g.trim(),120)}`),console.log("");}}await new Promise(c=>process.stdout.write("",()=>c())),process.exit(0);}catch(n){l(n instanceof Error?n.message:"Failed to get thread"),process.exit(1);}}),i.command("label <id>").description("Add or remove labels from a thread").option("--add <labels>","Labels to add (comma-separated)").option("--remove <labels>","Labels to remove (comma-separated)").option("--format <format>","Output format (json|table)","table").action(async(e,o)=>{try{!o.add&&!o.remove&&(l("Specify --add and/or --remove labels"),process.exit(1));let n=d(),t=new Emailr({apiKey:n.apiKey,baseUrl:n.baseUrl}),r=o.add?o.add.split(",").map(g=>g.trim()):void 0,s=o.remove?o.remove.split(",").map(g=>g.trim()):void 0,c=await t.threads.updateLabels(e,{add:r,remove:s});o.format==="json"?m(c,"json"):(p(`Updated ${c.updated} email(s) in thread`),r&&u(`Added: ${r.join(", ")}`),s&&u(`Removed: ${s.join(", ")}`)),await new Promise(g=>process.stdout.write("",()=>g())),process.exit(0);}catch(n){l(n instanceof Error?n.message:"Failed to update labels"),process.exit(1);}}),i.command("reply <id>").description("Reply to a thread (from/to/subject auto-resolved from inbox)").option("--html <content>","HTML content for the reply").option("--text <content>","Plain text content for the reply").option("--to <email>","Override recipient (auto-resolved if omitted)").option("--cc <emails>","CC recipients (comma-separated)").option("--bcc <emails>","BCC recipients (comma-separated)").option("--from <email>","Override sender (auto-resolved from inbox if omitted)").option("--from-name <name>","Override sender name (auto-resolved from inbox if omitted)").option("--reply-to <email>","Override Reply-To (auto-resolved from inbox if omitted)").option("--format <format>","Output format (json|table)","table").action(async(e,o)=>{try{!o.html&&!o.text&&(l("Provide --html or --text for the reply body"),process.exit(1));let n=d(),t=new Emailr({apiKey:n.apiKey,baseUrl:n.baseUrl}),r={};o.html&&(r.html=o.html),o.text&&(r.text=o.text),o.to&&(r.to=o.to),o.cc&&(r.cc=o.cc.split(",").map(b=>b.trim())),o.bcc&&(r.bcc=o.bcc.split(",").map(b=>b.trim())),o.from&&(r.from=o.from),o.fromName&&(r.from_name=o.fromName),o.replyTo&&(r.reply_to_email=o.replyTo);let s=await t.threads.reply(e,r);o.format==="json"?m(s,"json"):(p(`Reply sent to ${s.recipients} recipient(s)`),u(`Message ID: ${s.message_id}`)),await new Promise(b=>process.stdout.write("",()=>b())),process.exit(0);}catch(n){l(n instanceof Error?n.message:"Failed to send reply"),process.exit(1);}});let a=i.command("draft").description("Manage draft replies for threads");return a.command("save <id>").description("Save a draft reply for a thread").option("--html <content>","HTML content").option("--text <content>","Plain text content").option("--to <email>","Recipient").option("--cc <emails>","CC recipients").option("--bcc <emails>","BCC recipients").option("--from <email>","Sender").option("--reply-to <email>","Reply-To address").option("--format <format>","Output format (json|table)","table").action(async(e,o)=>{try{let n=d(),t=new Emailr({apiKey:n.apiKey,baseUrl:n.baseUrl}),r={};o.html&&(r.html=o.html),o.text&&(r.text=o.text),o.to&&(r.to=o.to),o.cc&&(r.cc=o.cc),o.bcc&&(r.bcc=o.bcc),o.from&&(r.from=o.from),o.replyTo&&(r.reply_to_email=o.replyTo);let s=await t.threads.saveDraft(e,r);o.format==="json"?m(s,"json"):(p(`Draft saved for thread ${e}`),u(`Draft ID: ${s.id}`)),await new Promise(b=>process.stdout.write("",()=>b())),process.exit(0);}catch(n){l(n instanceof Error?n.message:"Failed to save draft"),process.exit(1);}}),a.command("get <id>").description("Get the saved draft for a thread").option("--format <format>","Output format (json|table)","table").action(async(e,o)=>{try{let n=d(),r=await new Emailr({apiKey:n.apiKey,baseUrl:n.baseUrl}).threads.getDraft(e);o.format==="json"?m(r,"json"):(u(`Draft for thread: ${e}`),u(`To: ${r.to_email||"(auto)"}`),u(`From: ${r.from_email||"(auto)"}`),u(`Subject: ${r.subject||"(auto)"}`),r.html_content&&console.log(`
3442
3451
  Content:
3443
- ${le(r.html_content.replace(/<[^>]*>/g,""),200)}`)),await new Promise(c=>process.stdout.write("",()=>c())),process.exit(0);}catch(n){l(n instanceof Error?n.message:"No draft found"),process.exit(1);}}),a.command("delete <id>").description("Delete the draft for a thread").option("--format <format>","Output format (json|table)","table").action(async(e,t)=>{try{let n=d();await new Emailr({apiKey:n.apiKey,baseUrl:n.baseUrl}).threads.deleteDraft(e),t.format==="json"?m({success:!0},"json"):p(`Draft deleted for thread ${e}`),await new Promise(s=>process.stdout.write("",()=>s())),process.exit(0);}catch(n){l(n instanceof Error?n.message:"Failed to delete draft"),process.exit(1);}}),o}function le(o,a){return o.length<=a?o:o.slice(0,a-1)+"\u2026"}function $e(o){return new Date(o).toLocaleString()}var Ft=`# Emailr CLI \u2014 Agent Skill Guide
3452
+ ${le(r.html_content.replace(/<[^>]*>/g,""),200)}`)),await new Promise(c=>process.stdout.write("",()=>c())),process.exit(0);}catch(n){l(n instanceof Error?n.message:"No draft found"),process.exit(1);}}),a.command("delete <id>").description("Delete the draft for a thread").option("--format <format>","Output format (json|table)","table").action(async(e,o)=>{try{let n=d();await new Emailr({apiKey:n.apiKey,baseUrl:n.baseUrl}).threads.deleteDraft(e),o.format==="json"?m({success:!0},"json"):p(`Draft deleted for thread ${e}`),await new Promise(s=>process.stdout.write("",()=>s())),process.exit(0);}catch(n){l(n instanceof Error?n.message:"Failed to delete draft"),process.exit(1);}}),i}function le(i,a){return i.length<=a?i:i.slice(0,a-1)+"\u2026"}function $e(i){return new Date(i).toLocaleString()}var Ft=`# Emailr CLI \u2014 Agent Skill Guide
3444
3453
 
3445
3454
  ## Setup
3446
3455
 
@@ -3783,4 +3792,4 @@ AGENTIC WORKFLOW
3783
3792
 
3784
3793
  MORE INFORMATION
3785
3794
  Run 'emailr <command> --help' for detailed help on any command.
3786
- Run 'emailr <command> <subcommand> --help' for subcommand details.`).version("1.10.0");y.addCommand(fe());y.addCommand(He());y.addCommand(qe());y.addCommand(Je());y.addCommand(be());y.addCommand(Ie());y.addCommand(Ne());y.addCommand(Ue());y.addCommand(ke());y.addCommand(Pe());y.addCommand(Ce());y.addCommand(De());y.addCommand(Fe());y.addCommand(Be());y.parse();
3795
+ Run 'emailr <command> <subcommand> --help' for subcommand details.`).version("1.11.1");y.addCommand(fe());y.addCommand(He());y.addCommand(qe());y.addCommand(Je());y.addCommand(be());y.addCommand(Ie());y.addCommand(Ne());y.addCommand(Ue());y.addCommand(ke());y.addCommand(Pe());y.addCommand(Ce());y.addCommand(Me());y.addCommand(Fe());y.addCommand(Be());y.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "emailr-cli",
3
- "version": "1.10.0",
3
+ "version": "1.11.1",
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.4.0",
26
+ "emailr": "^1.6.0",
27
27
  "open": "^11.0.0"
28
28
  },
29
29
  "devDependencies": {