@mailmodo/cli 0.0.13 → 0.0.14-beta.pr16.23

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.
@@ -3,6 +3,7 @@ import { input } from '@inquirer/prompts';
3
3
  import chalk from 'chalk';
4
4
  import { BaseCommand } from '../../lib/base-command.js';
5
5
  import { API_ENDPOINTS, DNS_GUIDE_URL } from '../../lib/constants.js';
6
+ import { saveConfig } from '../../lib/config.js';
6
7
  import { saveYaml } from '../../lib/yaml-config.js';
7
8
  export default class Domain extends BaseCommand {
8
9
  static description = 'Set up and verify your sending domain';
@@ -24,22 +25,22 @@ export default class Domain extends BaseCommand {
24
25
  };
25
26
  async run() {
26
27
  const { flags } = await this.parse(Domain);
27
- await this.ensureAuth();
28
+ const config = await this.ensureAuth();
28
29
  if (flags.verify) {
29
- await this.verifyDomain(flags.json);
30
+ await this.verifyDomain(flags.json, config);
30
31
  return;
31
32
  }
32
33
  if (flags.status) {
33
- await this.showDomainStatus(flags.json);
34
+ await this.showDomainStatus(flags.json, config);
34
35
  return;
35
36
  }
36
- await this.setupDomain(flags);
37
+ await this.setupDomain(flags, config);
37
38
  }
38
39
  /**
39
40
  * Interactive domain setup: collects domain, sender email, and business address,
40
41
  * then calls the API to retrieve the required DNS records.
41
42
  */
42
- async setupDomain(flags) {
43
+ async setupDomain(flags, config) {
43
44
  const yamlConfig = await this.ensureYaml();
44
45
  this.log(`\n ${'─'.repeat(53)}`);
45
46
  this.log(` ${chalk.bold('DOMAIN SETUP')}`);
@@ -84,6 +85,7 @@ export default class Domain extends BaseCommand {
84
85
  yamlConfig.project.fromEmail = senderEmail;
85
86
  yamlConfig.project.address = address;
86
87
  await saveYaml(yamlConfig);
88
+ await saveConfig({ ...config, domain });
87
89
  const records = response.data?.dnsRecords || [];
88
90
  if (flags.json) {
89
91
  this.log(JSON.stringify({ dnsRecords: records, domain }, null, 2));
@@ -104,15 +106,21 @@ export default class Domain extends BaseCommand {
104
106
  message: "Press Enter once you've added the records, or 'skip'.",
105
107
  });
106
108
  if (action.toLowerCase() !== 'skip') {
107
- await this.verifyDomain(false);
109
+ await this.verifyDomain(false, { ...config, domain });
108
110
  }
109
111
  }
110
112
  }
111
113
  /**
112
114
  * Calls the domain verification API and displays pass/fail for each DNS record.
113
115
  */
114
- async verifyDomain(jsonOutput) {
115
- const response = await this.withApiSpinner({ json: jsonOutput, text: ' Checking DNS...' }, () => this.apiClient.get(API_ENDPOINTS.DOMAIN_VERIFY));
116
+ async verifyDomain(jsonOutput, config) {
117
+ if (!config.domain) {
118
+ this.error(`No domain configured. Run ${chalk.cyan('mailmodo domain')} to set up your sending domain.`);
119
+ }
120
+ const domain = config.domain;
121
+ const response = await this.withApiSpinner({ json: jsonOutput, text: ' Checking DNS...' }, () => this.apiClient.get(API_ENDPOINTS.DOMAIN_VERIFY, {
122
+ domain,
123
+ }));
116
124
  if (!response.ok) {
117
125
  this.handleApiError(response);
118
126
  }
@@ -121,16 +129,16 @@ export default class Domain extends BaseCommand {
121
129
  this.log(JSON.stringify({ dkim, dmarc, spf }, null, 2));
122
130
  return;
123
131
  }
124
- this.log(` SPF ${spf === 'pass' ? chalk.green('✓') : chalk.red('✗ Not found')}`);
125
- this.log(` DKIM ${dkim === 'pass' ? chalk.green('✓') : chalk.red('✗ Not found')}`);
126
- this.log(` DMARC ${dmarc === 'pass' ? chalk.green('✓') : chalk.red('✗ Not found')}`);
127
- const allPassed = spf === 'pass' && dkim === 'pass' && dmarc === 'pass';
132
+ this.log(` SPF ${spf ? chalk.green('✓') : chalk.red('✗ Not found')}`);
133
+ this.log(` DKIM ${dkim ? chalk.green('✓') : chalk.red('✗ Not found')}`);
134
+ this.log(` DMARC ${dmarc ? chalk.green('✓') : chalk.red('✗ Not found')}`);
135
+ const allPassed = spf && dkim && dmarc;
128
136
  if (allPassed) {
129
137
  this.log(`\n ${chalk.green('✓')} Domain verified.\n`);
130
138
  }
131
139
  else {
132
140
  this.log(`\n ${chalk.yellow('Some records failed.')}`);
133
- if (dkim !== 'pass') {
141
+ if (!dkim) {
134
142
  this.log(`\n DKIM common mistakes:`);
135
143
  this.log(` - Using TXT instead of CNAME record type`);
136
144
  this.log(` - Including the full domain in the Host field`);
@@ -144,8 +152,14 @@ export default class Domain extends BaseCommand {
144
152
  * Displays domain health metrics including verification status,
145
153
  * bounce rate, and spam complaint rate.
146
154
  */
147
- async showDomainStatus(jsonOutput) {
148
- const response = await this.withApiSpinner({ json: jsonOutput, text: ' Loading domain status...' }, () => this.apiClient.get(API_ENDPOINTS.DOMAIN_STATUS));
155
+ async showDomainStatus(jsonOutput, config) {
156
+ if (!config.domain) {
157
+ this.error(`No domain configured. Run ${chalk.cyan('mailmodo domain')} to set up your sending domain.`);
158
+ }
159
+ const domain = config.domain;
160
+ const response = await this.withApiSpinner({ json: jsonOutput, text: ' Loading domain status...' }, () => this.apiClient.get(API_ENDPOINTS.DOMAIN_STATUS, {
161
+ domain,
162
+ }));
149
163
  if (!response.ok) {
150
164
  this.handleApiError(response);
151
165
  }
@@ -2,7 +2,7 @@ import { Flags } from '@oclif/core';
2
2
  import { editor, input, select } from '@inquirer/prompts';
3
3
  import chalk from 'chalk';
4
4
  import { BaseCommand } from '../../lib/base-command.js';
5
- import { API_ENDPOINTS, DEFAULT_BRAND_COLOR, DEFAULT_MONTHLY_CAP } from '../../lib/constants.js';
5
+ import { API_ENDPOINTS, DEFAULT_BRAND_COLOR, DEFAULT_MONTHLY_CAP, } from '../../lib/constants.js';
6
6
  import { saveTemplate, saveYaml, } from '../../lib/yaml-config.js';
7
7
  function isValidUrl(value) {
8
8
  try {
@@ -4,7 +4,7 @@ import open from 'open';
4
4
  import { BaseCommand } from '../../lib/base-command.js';
5
5
  import { ApiClient } from '../../lib/api-client.js';
6
6
  import { loadConfig, saveConfig } from '../../lib/config.js';
7
- import { API_ENDPOINTS, SIGNUP_URL } from '../../lib/constants.js';
7
+ import { API_ENDPOINTS, LOGIN_URL } from '../../lib/constants.js';
8
8
  export default class Login extends BaseCommand {
9
9
  static description = 'Authenticate with Mailmodo using your API key';
10
10
  static examples = [
@@ -44,9 +44,9 @@ export default class Login extends BaseCommand {
44
44
  this.log('Detected MAILMODO_API_KEY from environment.');
45
45
  }
46
46
  else {
47
- this.log(`\n Get your free API key at: ${chalk.cyan(SIGNUP_URL)}\n`);
47
+ this.log(`\n Get your free API key at: ${chalk.cyan(LOGIN_URL)}\n`);
48
48
  try {
49
- await open(SIGNUP_URL);
49
+ await open(LOGIN_URL);
50
50
  this.log(' Opening in browser...\n');
51
51
  }
52
52
  catch {
@@ -199,7 +199,7 @@ export default class Settings extends BaseCommand {
199
199
  const newFromEmail = await input({
200
200
  default: yamlConfig.project.fromEmail || '',
201
201
  message: 'Sender email (from address):',
202
- validate: (v) => v?.includes('@') ? true : 'Please enter a valid email',
202
+ validate: (v) => (v?.includes('@') ? true : 'Please enter a valid email'),
203
203
  });
204
204
  const newAddress = await input({
205
205
  default: yamlConfig.project.address || '',
@@ -1,6 +1,7 @@
1
1
  export interface MailmodoConfig {
2
2
  accountName?: string;
3
3
  apiKey: string;
4
+ domain?: string;
4
5
  email?: string;
5
6
  freeRemaining?: number;
6
7
  }
@@ -1,4 +1,4 @@
1
- export declare const API_BASE_URL: string;
1
+ export declare const API_BASE_URL = "https://app-vertex-debug.azurewebsites.net";
2
2
  export declare const API_ENDPOINTS: Readonly<{
3
3
  ANALYTICS: "/analytics";
4
4
  ANALYZE: "/analyze";
@@ -18,7 +18,7 @@ export declare const API_ENDPOINTS: Readonly<{
18
18
  PREVIEW: "/preview";
19
19
  SEQUENCES: "/sequences";
20
20
  }>;
21
- export declare const SIGNUP_URL = "https://mailmodo.com/cli";
21
+ export declare const LOGIN_URL = "https://app-vertex-debug.azurewebsites.net/login.html";
22
22
  export declare const DOCS_URL = "https://mailmodo.com/docs/cli";
23
23
  export declare const DNS_GUIDE_URL = "https://mailmodo.com/docs/dns";
24
24
  export declare const PREVIEW_PORT = 3421;
@@ -1,6 +1,7 @@
1
1
  /** Set by `bin/dev.js` when running the CLI locally (tsx bootstrap). */
2
2
  const DEV_API_BASE_URL = 'https://app-vertex-debug.azurewebsites.net';
3
- const PRODUCTION_API_BASE_URL = 'https://api.mailmodo.com';
3
+ // const PRODUCTION_API_BASE_URL = 'https://api.mailmodo.com';
4
+ const PRODUCTION_API_BASE_URL = 'https://app-vertex-debug.azurewebsites.net';
4
5
  export const API_BASE_URL = process.env.MAILMODO_DEV_TSX
5
6
  ? DEV_API_BASE_URL
6
7
  : PRODUCTION_API_BASE_URL;
@@ -23,7 +24,12 @@ export const API_ENDPOINTS = Object.freeze({
23
24
  PREVIEW: '/preview',
24
25
  SEQUENCES: '/sequences',
25
26
  });
26
- export const SIGNUP_URL = 'https://mailmodo.com/cli';
27
+ const DEV_LOGIN_URL = 'https://app-vertex-debug.azurewebsites.net/login.html';
28
+ // const PRODUCTION_LOGIN_URL = 'https://mailmodo.com/cli';
29
+ const PRODUCTION_LOGIN_URL = 'https://app-vertex-debug.azurewebsites.net/login.html';
30
+ export const LOGIN_URL = process.env.MAILMODO_DEV_TSX
31
+ ? DEV_LOGIN_URL
32
+ : PRODUCTION_LOGIN_URL;
27
33
  export const DOCS_URL = 'https://mailmodo.com/docs/cli';
28
34
  export const DNS_GUIDE_URL = 'https://mailmodo.com/docs/dns';
29
35
  export const PREVIEW_PORT = 3421;
@@ -114,45 +114,6 @@
114
114
  "index.js"
115
115
  ]
116
116
  },
117
- "deploy": {
118
- "aliases": [],
119
- "args": {},
120
- "description": "Deploy email sequences and verify sending domain",
121
- "examples": [
122
- "<%= config.bin %> deploy",
123
- "<%= config.bin %> deploy --yes"
124
- ],
125
- "flags": {
126
- "json": {
127
- "description": "Output as JSON",
128
- "name": "json",
129
- "allowNo": false,
130
- "type": "boolean"
131
- },
132
- "yes": {
133
- "char": "y",
134
- "description": "Skip confirmation prompts",
135
- "name": "yes",
136
- "allowNo": false,
137
- "type": "boolean"
138
- }
139
- },
140
- "hasDynamicHelp": false,
141
- "hiddenAliases": [],
142
- "id": "deploy",
143
- "pluginAlias": "@mailmodo/cli",
144
- "pluginName": "@mailmodo/cli",
145
- "pluginType": "core",
146
- "strict": true,
147
- "enableJsonFlag": false,
148
- "isESM": true,
149
- "relativePath": [
150
- "dist",
151
- "commands",
152
- "deploy",
153
- "index.js"
154
- ]
155
- },
156
117
  "domain": {
157
118
  "aliases": [],
158
119
  "args": {},
@@ -205,13 +166,13 @@
205
166
  "index.js"
206
167
  ]
207
168
  },
208
- "emails": {
169
+ "deploy": {
209
170
  "aliases": [],
210
171
  "args": {},
211
- "description": "List and view configured email sequences",
172
+ "description": "Deploy email sequences and verify sending domain",
212
173
  "examples": [
213
- "<%= config.bin %> emails",
214
- "<%= config.bin %> emails --json"
174
+ "<%= config.bin %> deploy",
175
+ "<%= config.bin %> deploy --yes"
215
176
  ],
216
177
  "flags": {
217
178
  "json": {
@@ -230,7 +191,7 @@
230
191
  },
231
192
  "hasDynamicHelp": false,
232
193
  "hiddenAliases": [],
233
- "id": "emails",
194
+ "id": "deploy",
234
195
  "pluginAlias": "@mailmodo/cli",
235
196
  "pluginName": "@mailmodo/cli",
236
197
  "pluginType": "core",
@@ -240,7 +201,7 @@
240
201
  "relativePath": [
241
202
  "dist",
242
203
  "commands",
243
- "emails",
204
+ "deploy",
244
205
  "index.js"
245
206
  ]
246
207
  },
@@ -296,6 +257,45 @@
296
257
  "index.js"
297
258
  ]
298
259
  },
260
+ "emails": {
261
+ "aliases": [],
262
+ "args": {},
263
+ "description": "List and view configured email sequences",
264
+ "examples": [
265
+ "<%= config.bin %> emails",
266
+ "<%= config.bin %> emails --json"
267
+ ],
268
+ "flags": {
269
+ "json": {
270
+ "description": "Output as JSON",
271
+ "name": "json",
272
+ "allowNo": false,
273
+ "type": "boolean"
274
+ },
275
+ "yes": {
276
+ "char": "y",
277
+ "description": "Skip confirmation prompts",
278
+ "name": "yes",
279
+ "allowNo": false,
280
+ "type": "boolean"
281
+ }
282
+ },
283
+ "hasDynamicHelp": false,
284
+ "hiddenAliases": [],
285
+ "id": "emails",
286
+ "pluginAlias": "@mailmodo/cli",
287
+ "pluginName": "@mailmodo/cli",
288
+ "pluginType": "core",
289
+ "strict": true,
290
+ "enableJsonFlag": false,
291
+ "isESM": true,
292
+ "relativePath": [
293
+ "dist",
294
+ "commands",
295
+ "emails",
296
+ "index.js"
297
+ ]
298
+ },
299
299
  "init": {
300
300
  "aliases": [],
301
301
  "args": {},
@@ -342,6 +342,45 @@
342
342
  "index.js"
343
343
  ]
344
344
  },
345
+ "login": {
346
+ "aliases": [],
347
+ "args": {},
348
+ "description": "Authenticate with Mailmodo using your API key",
349
+ "examples": [
350
+ "<%= config.bin %> login",
351
+ "MAILMODO_API_KEY=mm_live_xxx <%= config.bin %> login"
352
+ ],
353
+ "flags": {
354
+ "json": {
355
+ "description": "Output as JSON",
356
+ "name": "json",
357
+ "allowNo": false,
358
+ "type": "boolean"
359
+ },
360
+ "yes": {
361
+ "char": "y",
362
+ "description": "Skip confirmation prompts",
363
+ "name": "yes",
364
+ "allowNo": false,
365
+ "type": "boolean"
366
+ }
367
+ },
368
+ "hasDynamicHelp": false,
369
+ "hiddenAliases": [],
370
+ "id": "login",
371
+ "pluginAlias": "@mailmodo/cli",
372
+ "pluginName": "@mailmodo/cli",
373
+ "pluginType": "core",
374
+ "strict": true,
375
+ "enableJsonFlag": false,
376
+ "isESM": true,
377
+ "relativePath": [
378
+ "dist",
379
+ "commands",
380
+ "login",
381
+ "index.js"
382
+ ]
383
+ },
345
384
  "logout": {
346
385
  "aliases": [],
347
386
  "args": {},
@@ -492,45 +531,6 @@
492
531
  "index.js"
493
532
  ]
494
533
  },
495
- "login": {
496
- "aliases": [],
497
- "args": {},
498
- "description": "Authenticate with Mailmodo using your API key",
499
- "examples": [
500
- "<%= config.bin %> login",
501
- "MAILMODO_API_KEY=mm_live_xxx <%= config.bin %> login"
502
- ],
503
- "flags": {
504
- "json": {
505
- "description": "Output as JSON",
506
- "name": "json",
507
- "allowNo": false,
508
- "type": "boolean"
509
- },
510
- "yes": {
511
- "char": "y",
512
- "description": "Skip confirmation prompts",
513
- "name": "yes",
514
- "allowNo": false,
515
- "type": "boolean"
516
- }
517
- },
518
- "hasDynamicHelp": false,
519
- "hiddenAliases": [],
520
- "id": "login",
521
- "pluginAlias": "@mailmodo/cli",
522
- "pluginName": "@mailmodo/cli",
523
- "pluginType": "core",
524
- "strict": true,
525
- "enableJsonFlag": false,
526
- "isESM": true,
527
- "relativePath": [
528
- "dist",
529
- "commands",
530
- "login",
531
- "index.js"
532
- ]
533
- },
534
534
  "settings": {
535
535
  "aliases": [],
536
536
  "args": {},
@@ -618,5 +618,5 @@
618
618
  ]
619
619
  }
620
620
  },
621
- "version": "0.0.13"
621
+ "version": "0.0.14-beta.pr16.23"
622
622
  }
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.13",
4
+ "version": "0.0.14-beta.pr16.23",
5
5
  "author": "provishalk",
6
6
  "bin": {
7
7
  "mailmodo": "bin/run.js"
@@ -24,13 +24,17 @@
24
24
  "@types/chai": "^4",
25
25
  "@types/js-yaml": "^4.0.9",
26
26
  "@types/mocha": "^10",
27
- "@types/node": "^18",
27
+ "@types/node": "^18.19.130",
28
28
  "chai": "^4",
29
29
  "eslint": "^9",
30
30
  "eslint-config-oclif": "^6",
31
31
  "eslint-config-prettier": "^10",
32
+ "eslint-plugin-unused-imports": "^4.4.1",
33
+ "husky": "^9.1.7",
34
+ "lint-staged": "^16.4.0",
32
35
  "mocha": "^11",
33
36
  "oclif": "^4",
37
+ "prettier": "^3.8.2",
34
38
  "shx": "^0.3.3",
35
39
  "ts-node": "^10",
36
40
  "tsx": "^4.21.0",
@@ -69,7 +73,15 @@
69
73
  "posttest": "npm run lint",
70
74
  "prepack": "oclif manifest && oclif readme",
71
75
  "test": "mocha --forbid-only \"test/**/*.test.ts\"",
72
- "version": "oclif readme && git add README.md"
76
+ "version": "oclif readme && git add README.md",
77
+ "prepare": "husky"
73
78
  },
74
- "types": "dist/index.d.ts"
79
+ "types": "dist/index.d.ts",
80
+ "lint-staged": {
81
+ "*.{ts,tsx,js,jsx,mjs,cjs}": [
82
+ "prettier --write",
83
+ "eslint --fix"
84
+ ],
85
+ "*.{json,md,yaml,yml}": "prettier --write"
86
+ }
75
87
  }