@mailmodo/cli 0.0.42 → 0.0.44-beta.pr46.72

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.
@@ -113,7 +113,7 @@ export default class Contacts extends BaseCommand {
113
113
  this.log(`\n Export status: ${status ?? 'unknown'}. No download URL yet.\n`);
114
114
  return;
115
115
  }
116
- const fileResult = await this.apiClient.getPublicFile(downloadUrl.trim());
116
+ const fileResult = await this.withApiSpinner({ json: jsonOutput, text: ' Downloading CSV file...' }, () => this.apiClient.getPublicFile(downloadUrl.trim()));
117
117
  if (!fileResult.ok) {
118
118
  this.error(`Download failed: ${fileResult.status} ${fileResult.error ?? ''}\n` +
119
119
  ` URL: ${fileResult.debug.fullUrl}`);
@@ -97,7 +97,7 @@ export default class Domain extends BaseCommand {
97
97
  this.log(`\n ${INFO.DNS_RECORDS_FAILED}`);
98
98
  if (!dkim) {
99
99
  this.log(`\n DKIM common mistakes:`);
100
- this.log(` - Using TXT instead of CNAME record type`);
100
+ this.log(` - Using CNAME instead of TXT record type`);
101
101
  this.log(` - Including the full domain in the Host field`);
102
102
  this.log(` - Cloudflare: proxy must be OFF (grey cloud, not orange)`);
103
103
  }
@@ -261,7 +261,7 @@ export default class Settings extends BaseCommand {
261
261
  const mimeType = mimeTypes[ext ?? ''] ?? 'application/octet-stream';
262
262
  const formData = new FormData();
263
263
  formData.append('logo', new Blob([new Uint8Array(fileBuffer)], { type: mimeType }), logoPath.split(/[/\\]/).pop() || 'logo.png');
264
- const response = await this.apiClient.postFormData(API_ENDPOINTS.ASSETS_LOGO, formData);
264
+ const response = await this.withApiSpinner({ json: false, text: ' Uploading logo file...' }, () => this.apiClient.postFormData(API_ENDPOINTS.ASSETS_LOGO, formData));
265
265
  if (!response.ok) {
266
266
  this.handleApiError(response);
267
267
  }
@@ -34,4 +34,5 @@ export declare const INFO: {
34
34
  readonly DOMAIN_PENDING_VERIFICATION: `Your domain is not verified yet. Please verify it first. Run ${string} to check the status.`;
35
35
  readonly SEQUENCES_NOT_DEPLOYED: `Sequences saved but ${string}.`;
36
36
  };
37
+ export declare function yamlParseError(detail: string): string;
37
38
  export declare function recordLabel(index: number): string;
@@ -34,6 +34,9 @@ export const INFO = {
34
34
  DOMAIN_PENDING_VERIFICATION: `Your domain is not verified yet. Please verify it first. Run ${chalk.cyan('mailmodo domain --verify')} to check the status.`,
35
35
  SEQUENCES_NOT_DEPLOYED: `Sequences saved but ${chalk.yellow('NOT deployed')}.`,
36
36
  };
37
+ export function yamlParseError(detail) {
38
+ return `mailmodo.yaml has invalid YAML syntax:\n${detail}`;
39
+ }
37
40
  export function recordLabel(index) {
38
41
  const labels = ['DKIM', 'DMARC', 'Return Path'];
39
42
  return labels[index] || `Record ${index + 1}`;
@@ -40,7 +40,8 @@ export interface MailmodoYaml {
40
40
  *
41
41
  * @param {string} [cwd] - Directory containing mailmodo.yaml. Defaults to process.cwd().
42
42
  * @returns {Promise<MailmodoYaml | null>} The parsed configuration with project
43
- * settings and email array, or null if the file doesn't exist or can't be parsed.
43
+ * settings and email array, or null if the file doesn't exist. Throws a
44
+ * formatted Error with the line number if the file contains invalid YAML syntax.
44
45
  */
45
46
  export declare function loadYaml(cwd?: string): Promise<MailmodoYaml | null>;
46
47
  /**
@@ -3,24 +3,26 @@ import { mkdir, readFile, writeFile } from 'node:fs/promises';
3
3
  import { join } from 'node:path';
4
4
  import { dump, load } from 'js-yaml';
5
5
  import { TEMPLATES_DIR, YAML_FILE } from './constants.js';
6
+ import { yamlParseError } from './messages.js';
6
7
  /**
7
8
  * Loads and parses the mailmodo.yaml configuration file from the specified
8
9
  * directory (or current working directory).
9
10
  *
10
11
  * @param {string} [cwd] - Directory containing mailmodo.yaml. Defaults to process.cwd().
11
12
  * @returns {Promise<MailmodoYaml | null>} The parsed configuration with project
12
- * settings and email array, or null if the file doesn't exist or can't be parsed.
13
+ * settings and email array, or null if the file doesn't exist. Throws a
14
+ * formatted Error with the line number if the file contains invalid YAML syntax.
13
15
  */
14
16
  export async function loadYaml(cwd) {
15
17
  const filePath = join(cwd || process.cwd(), YAML_FILE);
16
18
  if (!existsSync(filePath))
17
19
  return null;
20
+ const content = await readFile(filePath, 'utf8');
18
21
  try {
19
- const content = await readFile(filePath, 'utf8');
20
22
  return load(content);
21
23
  }
22
- catch {
23
- return null;
24
+ catch (error) {
25
+ throw new Error(yamlParseError(error.message));
24
26
  }
25
27
  }
26
28
  /**
@@ -1,16 +1,14 @@
1
1
  {
2
2
  "commands": {
3
- "billing": {
3
+ "contacts": {
4
4
  "aliases": [],
5
5
  "args": {},
6
- "description": "View billing status, purchase blocks, set cap, or add a payment method",
6
+ "description": "Manage contacts search, export, or delete",
7
7
  "examples": [
8
- "<%= config.bin %> billing",
9
- "<%= config.bin %> billing --status",
10
- "<%= config.bin %> billing --cap 5",
11
- "<%= config.bin %> billing --cap 5 --auto-charge-block-count 2",
12
- "<%= config.bin %> billing --purchase 3",
13
- "<%= config.bin %> billing --checkout"
8
+ "<%= config.bin %> contacts",
9
+ "<%= config.bin %> contacts --search sarah@example.com",
10
+ "<%= config.bin %> contacts --export # GDPR CSV → contacts.csv",
11
+ "<%= config.bin %> contacts --delete sarah@example.com"
14
12
  ],
15
13
  "flags": {
16
14
  "json": {
@@ -26,43 +24,30 @@
26
24
  "allowNo": false,
27
25
  "type": "boolean"
28
26
  },
29
- "auto-charge-block-count": {
30
- "description": "Blocks to auto-purchase when the quota runs low (use with --cap)",
31
- "name": "auto-charge-block-count",
32
- "hasDynamicHelp": false,
33
- "multiple": false,
34
- "type": "option"
35
- },
36
- "cap": {
37
- "description": "Set monthly sending cap in blocks",
38
- "name": "cap",
27
+ "delete": {
28
+ "description": "GDPR hard delete a contact by email",
29
+ "name": "delete",
39
30
  "hasDynamicHelp": false,
40
31
  "multiple": false,
41
32
  "type": "option"
42
33
  },
43
- "checkout": {
44
- "description": "Open Stripe checkout to add or update a payment method",
45
- "name": "checkout",
34
+ "export": {
35
+ "description": "Export all contacts as GDPR-compliant CSV (writes contacts.csv in the current directory)",
36
+ "name": "export",
46
37
  "allowNo": false,
47
38
  "type": "boolean"
48
39
  },
49
- "purchase": {
50
- "description": "Manually purchase this many 10,000-email blocks",
51
- "name": "purchase",
40
+ "search": {
41
+ "description": "Search for a contact by email",
42
+ "name": "search",
52
43
  "hasDynamicHelp": false,
53
44
  "multiple": false,
54
45
  "type": "option"
55
- },
56
- "status": {
57
- "description": "Show billing status only",
58
- "name": "status",
59
- "allowNo": false,
60
- "type": "boolean"
61
46
  }
62
47
  },
63
48
  "hasDynamicHelp": false,
64
49
  "hiddenAliases": [],
65
- "id": "billing",
50
+ "id": "contacts",
66
51
  "pluginAlias": "@mailmodo/cli",
67
52
  "pluginName": "@mailmodo/cli",
68
53
  "pluginType": "core",
@@ -72,19 +57,21 @@
72
57
  "relativePath": [
73
58
  "dist",
74
59
  "commands",
75
- "billing",
60
+ "contacts",
76
61
  "index.js"
77
62
  ]
78
63
  },
79
- "contacts": {
64
+ "billing": {
80
65
  "aliases": [],
81
66
  "args": {},
82
- "description": "Manage contacts search, export, or delete",
67
+ "description": "View billing status, purchase blocks, set cap, or add a payment method",
83
68
  "examples": [
84
- "<%= config.bin %> contacts",
85
- "<%= config.bin %> contacts --search sarah@example.com",
86
- "<%= config.bin %> contacts --export # GDPR CSV → contacts.csv",
87
- "<%= config.bin %> contacts --delete sarah@example.com"
69
+ "<%= config.bin %> billing",
70
+ "<%= config.bin %> billing --status",
71
+ "<%= config.bin %> billing --cap 5",
72
+ "<%= config.bin %> billing --cap 5 --auto-charge-block-count 2",
73
+ "<%= config.bin %> billing --purchase 3",
74
+ "<%= config.bin %> billing --checkout"
88
75
  ],
89
76
  "flags": {
90
77
  "json": {
@@ -100,30 +87,43 @@
100
87
  "allowNo": false,
101
88
  "type": "boolean"
102
89
  },
103
- "delete": {
104
- "description": "GDPR hard delete a contact by email",
105
- "name": "delete",
90
+ "auto-charge-block-count": {
91
+ "description": "Blocks to auto-purchase when the quota runs low (use with --cap)",
92
+ "name": "auto-charge-block-count",
106
93
  "hasDynamicHelp": false,
107
94
  "multiple": false,
108
95
  "type": "option"
109
96
  },
110
- "export": {
111
- "description": "Export all contacts as GDPR-compliant CSV (writes contacts.csv in the current directory)",
112
- "name": "export",
97
+ "cap": {
98
+ "description": "Set monthly sending cap in blocks",
99
+ "name": "cap",
100
+ "hasDynamicHelp": false,
101
+ "multiple": false,
102
+ "type": "option"
103
+ },
104
+ "checkout": {
105
+ "description": "Open Stripe checkout to add or update a payment method",
106
+ "name": "checkout",
113
107
  "allowNo": false,
114
108
  "type": "boolean"
115
109
  },
116
- "search": {
117
- "description": "Search for a contact by email",
118
- "name": "search",
110
+ "purchase": {
111
+ "description": "Manually purchase this many 10,000-email blocks",
112
+ "name": "purchase",
119
113
  "hasDynamicHelp": false,
120
114
  "multiple": false,
121
115
  "type": "option"
116
+ },
117
+ "status": {
118
+ "description": "Show billing status only",
119
+ "name": "status",
120
+ "allowNo": false,
121
+ "type": "boolean"
122
122
  }
123
123
  },
124
124
  "hasDynamicHelp": false,
125
125
  "hiddenAliases": [],
126
- "id": "contacts",
126
+ "id": "billing",
127
127
  "pluginAlias": "@mailmodo/cli",
128
128
  "pluginName": "@mailmodo/cli",
129
129
  "pluginType": "core",
@@ -133,7 +133,7 @@
133
133
  "relativePath": [
134
134
  "dist",
135
135
  "commands",
136
- "contacts",
136
+ "billing",
137
137
  "index.js"
138
138
  ]
139
139
  },
@@ -512,14 +512,19 @@
512
512
  "index.js"
513
513
  ]
514
514
  },
515
- "settings": {
515
+ "preview": {
516
516
  "aliases": [],
517
- "args": {},
518
- "description": "View and update project settings",
517
+ "args": {
518
+ "id": {
519
+ "description": "Email template ID to preview",
520
+ "name": "id"
521
+ }
522
+ },
523
+ "description": "Preview an email in browser, as text, or send a test",
519
524
  "examples": [
520
- "<%= config.bin %> settings",
521
- "<%= config.bin %> settings --set brand_color=#0F3460",
522
- "<%= config.bin %> settings --json"
525
+ "<%= config.bin %> preview welcome",
526
+ "<%= config.bin %> preview welcome --text",
527
+ "<%= config.bin %> preview welcome --send me@example.com"
523
528
  ],
524
529
  "flags": {
525
530
  "json": {
@@ -535,17 +540,23 @@
535
540
  "allowNo": false,
536
541
  "type": "boolean"
537
542
  },
538
- "set": {
539
- "description": "Set a setting (format: key=value)",
540
- "name": "set",
543
+ "send": {
544
+ "description": "Send test email to this address",
545
+ "name": "send",
541
546
  "hasDynamicHelp": false,
542
547
  "multiple": false,
543
548
  "type": "option"
549
+ },
550
+ "text": {
551
+ "description": "Output plain text version (for AI agents)",
552
+ "name": "text",
553
+ "allowNo": false,
554
+ "type": "boolean"
544
555
  }
545
556
  },
546
557
  "hasDynamicHelp": false,
547
558
  "hiddenAliases": [],
548
- "id": "settings",
559
+ "id": "preview",
549
560
  "pluginAlias": "@mailmodo/cli",
550
561
  "pluginName": "@mailmodo/cli",
551
562
  "pluginType": "core",
@@ -555,7 +566,7 @@
555
566
  "relativePath": [
556
567
  "dist",
557
568
  "commands",
558
- "settings",
569
+ "preview",
559
570
  "index.js"
560
571
  ]
561
572
  },
@@ -598,19 +609,14 @@
598
609
  "index.js"
599
610
  ]
600
611
  },
601
- "preview": {
612
+ "settings": {
602
613
  "aliases": [],
603
- "args": {
604
- "id": {
605
- "description": "Email template ID to preview",
606
- "name": "id"
607
- }
608
- },
609
- "description": "Preview an email in browser, as text, or send a test",
614
+ "args": {},
615
+ "description": "View and update project settings",
610
616
  "examples": [
611
- "<%= config.bin %> preview welcome",
612
- "<%= config.bin %> preview welcome --text",
613
- "<%= config.bin %> preview welcome --send me@example.com"
617
+ "<%= config.bin %> settings",
618
+ "<%= config.bin %> settings --set brand_color=#0F3460",
619
+ "<%= config.bin %> settings --json"
614
620
  ],
615
621
  "flags": {
616
622
  "json": {
@@ -626,23 +632,17 @@
626
632
  "allowNo": false,
627
633
  "type": "boolean"
628
634
  },
629
- "send": {
630
- "description": "Send test email to this address",
631
- "name": "send",
635
+ "set": {
636
+ "description": "Set a setting (format: key=value)",
637
+ "name": "set",
632
638
  "hasDynamicHelp": false,
633
639
  "multiple": false,
634
640
  "type": "option"
635
- },
636
- "text": {
637
- "description": "Output plain text version (for AI agents)",
638
- "name": "text",
639
- "allowNo": false,
640
- "type": "boolean"
641
641
  }
642
642
  },
643
643
  "hasDynamicHelp": false,
644
644
  "hiddenAliases": [],
645
- "id": "preview",
645
+ "id": "settings",
646
646
  "pluginAlias": "@mailmodo/cli",
647
647
  "pluginName": "@mailmodo/cli",
648
648
  "pluginType": "core",
@@ -652,10 +652,10 @@
652
652
  "relativePath": [
653
653
  "dist",
654
654
  "commands",
655
- "preview",
655
+ "settings",
656
656
  "index.js"
657
657
  ]
658
658
  }
659
659
  },
660
- "version": "0.0.42"
660
+ "version": "0.0.44-beta.pr46.72"
661
661
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mailmodo/cli",
3
3
  "description": "Email lifecycle automation for the AI-native builder generation.",
4
- "version": "0.0.42",
4
+ "version": "0.0.44-beta.pr46.72",
5
5
  "author": "provishalk",
6
6
  "bin": {
7
7
  "mailmodo": "bin/run.js"