@mailmodo/cli 0.0.47 → 0.0.48
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/deploy/index.d.ts +1 -0
- package/dist/commands/deploy/index.js +18 -9
- package/dist/commands/init/index.js +7 -2
- package/dist/commands/settings/index.js +12 -4
- package/dist/lib/base-command.d.ts +14 -0
- package/dist/lib/base-command.js +14 -5
- package/dist/lib/constants.d.ts +0 -3
- package/dist/lib/constants.js +0 -3
- package/oclif.manifest.json +48 -48
- package/package.json +1 -1
|
@@ -10,6 +10,7 @@ export default class Deploy extends BaseCommand {
|
|
|
10
10
|
run(): Promise<void>;
|
|
11
11
|
private validateSequence;
|
|
12
12
|
private buildDeployPayload;
|
|
13
|
+
private resolveMonthlyCapForDeploy;
|
|
13
14
|
private mapEmailToPayload;
|
|
14
15
|
private buildBrandSection;
|
|
15
16
|
private buildProductSection;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { confirm, input } from '@inquirer/prompts';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
3
|
import { BaseCommand } from '../../lib/base-command.js';
|
|
4
|
-
import { API_ENDPOINTS, DEFAULT_BRAND_COLOR
|
|
4
|
+
import { API_ENDPOINTS, DEFAULT_BRAND_COLOR } from '../../lib/constants.js';
|
|
5
5
|
import { ERRORS, INFO, PROMPTS, SEPARATOR } from '../../lib/messages.js';
|
|
6
6
|
import { loadTemplate, } from '../../lib/yaml-config.js';
|
|
7
7
|
export default class Deploy extends BaseCommand {
|
|
@@ -61,16 +61,25 @@ export default class Deploy extends BaseCommand {
|
|
|
61
61
|
return response.data;
|
|
62
62
|
}
|
|
63
63
|
async buildDeployPayload(yamlConfig) {
|
|
64
|
-
const emailsWithHtml = await Promise.all(
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
64
|
+
const [emailsWithHtml, monthlyCap] = await Promise.all([
|
|
65
|
+
Promise.all(yamlConfig.emails.map(async (email) => {
|
|
66
|
+
const html = (await loadTemplate(`${email.id}.html`)) || '';
|
|
67
|
+
const plainHtml = (await loadTemplate(`${email.id}_plain.html`)) || html;
|
|
68
|
+
return { ...this.mapEmailToPayload(email), html, plainHtml };
|
|
69
|
+
})),
|
|
70
|
+
this.resolveMonthlyCapForDeploy(yamlConfig.project.monthlyCap),
|
|
71
|
+
]);
|
|
69
72
|
return {
|
|
70
|
-
...this.buildProjectPayload(yamlConfig.project),
|
|
73
|
+
...this.buildProjectPayload(yamlConfig.project, monthlyCap),
|
|
71
74
|
emails: emailsWithHtml,
|
|
72
75
|
};
|
|
73
76
|
}
|
|
77
|
+
async resolveMonthlyCapForDeploy(yamlMonthlyCap) {
|
|
78
|
+
if (yamlMonthlyCap !== undefined)
|
|
79
|
+
return yamlMonthlyCap;
|
|
80
|
+
const billingStatus = await this.fetchBillingStatus();
|
|
81
|
+
return billingStatus?.cap?.inBlocks ?? undefined;
|
|
82
|
+
}
|
|
74
83
|
mapEmailToPayload(email) {
|
|
75
84
|
return {
|
|
76
85
|
condition: email.condition || null,
|
|
@@ -111,11 +120,11 @@ export default class Deploy extends BaseCommand {
|
|
|
111
120
|
replyTo: project?.replyTo || project?.fromEmail || '',
|
|
112
121
|
};
|
|
113
122
|
}
|
|
114
|
-
buildProjectPayload(project) {
|
|
123
|
+
buildProjectPayload(project, monthlyCap) {
|
|
115
124
|
return {
|
|
116
125
|
brand: this.buildBrandSection(project),
|
|
117
126
|
emailStyle: project?.emailStyle || 'branded',
|
|
118
|
-
monthlyCap:
|
|
127
|
+
...(monthlyCap === undefined ? {} : { monthlyCap }),
|
|
119
128
|
product: this.buildProductSection(project),
|
|
120
129
|
senderDetails: this.buildSenderSection(project),
|
|
121
130
|
...(project?.webhookUrl ? { webhookUrl: project.webhookUrl } : {}),
|
|
@@ -2,7 +2,7 @@ import { Flags } from '@oclif/core';
|
|
|
2
2
|
import { confirm, 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
|
|
5
|
+
import { API_ENDPOINTS, DEFAULT_BRAND_COLOR } from '../../lib/constants.js';
|
|
6
6
|
import { loadYaml, saveTemplate, saveYaml, } from '../../lib/yaml-config.js';
|
|
7
7
|
function isValidUrl(value) {
|
|
8
8
|
try {
|
|
@@ -143,7 +143,6 @@ export default class Init extends BaseCommand {
|
|
|
143
143
|
fromEmail: '',
|
|
144
144
|
fromName: `Team ${analysisPayload.productName}`,
|
|
145
145
|
logoUrl: analysisPayload.brand?.logoUrl || '',
|
|
146
|
-
monthlyCap: DEFAULT_MONTHLY_CAP,
|
|
147
146
|
name: analysisPayload.productName,
|
|
148
147
|
pricingModel: analysisPayload.pricingModel,
|
|
149
148
|
replyTo: '',
|
|
@@ -155,6 +154,12 @@ export default class Init extends BaseCommand {
|
|
|
155
154
|
},
|
|
156
155
|
};
|
|
157
156
|
await saveYaml(yamlConfig);
|
|
157
|
+
const billingStatus = await this.fetchBillingStatus();
|
|
158
|
+
const monthlyCap = billingStatus?.cap?.inBlocks;
|
|
159
|
+
if (monthlyCap !== null && monthlyCap !== undefined) {
|
|
160
|
+
yamlConfig.project.monthlyCap = monthlyCap;
|
|
161
|
+
await saveYaml(yamlConfig);
|
|
162
|
+
}
|
|
158
163
|
const templateSaves = analysisPayload.recommendedEmails.flatMap((rec, index) => {
|
|
159
164
|
const generated = generatedEmails[index];
|
|
160
165
|
const saves = [];
|
|
@@ -48,14 +48,22 @@ export default class Settings extends BaseCommand {
|
|
|
48
48
|
await this.applySetFlag(flags.set, yamlConfig, flags.json ?? false);
|
|
49
49
|
return;
|
|
50
50
|
}
|
|
51
|
+
const [domainVerified, billingStatus] = await Promise.all([
|
|
52
|
+
flags.json
|
|
53
|
+
? Promise.resolve(null)
|
|
54
|
+
: this.fetchDomainVerified(yamlConfig.project.domain),
|
|
55
|
+
this.fetchBillingStatus(),
|
|
56
|
+
]);
|
|
57
|
+
const tier = billingStatus?.tier ?? null;
|
|
58
|
+
const capFromApi = billingStatus?.cap?.inBlocks ?? null;
|
|
59
|
+
if (capFromApi !== null) {
|
|
60
|
+
yamlConfig.project.monthlyCap = capFromApi;
|
|
61
|
+
await saveYaml(yamlConfig);
|
|
62
|
+
}
|
|
51
63
|
if (flags.json) {
|
|
52
64
|
this.log(JSON.stringify({ settings: yamlConfig.project }, null, 2));
|
|
53
65
|
return;
|
|
54
66
|
}
|
|
55
|
-
const [domainVerified, tier] = await Promise.all([
|
|
56
|
-
this.fetchDomainVerified(yamlConfig.project.domain),
|
|
57
|
-
this.fetchBillingTier(),
|
|
58
|
-
]);
|
|
59
67
|
this.log(`\n Current settings for ${chalk.bold(yamlConfig.project.name || 'project')}:\n`);
|
|
60
68
|
for (const [group, keys] of Object.entries(SETTINGS_GROUPS)) {
|
|
61
69
|
if (group === 'billing' && tier === FREE_TIER)
|
|
@@ -8,6 +8,14 @@ export interface BillingCapUpdateResult {
|
|
|
8
8
|
capEmails: number;
|
|
9
9
|
message: string;
|
|
10
10
|
}
|
|
11
|
+
export interface BillingStatusResult {
|
|
12
|
+
cap?: {
|
|
13
|
+
capUpdatedAt: null | string;
|
|
14
|
+
inBlocks: null | number;
|
|
15
|
+
inEmails: null | number;
|
|
16
|
+
};
|
|
17
|
+
tier?: string;
|
|
18
|
+
}
|
|
11
19
|
export declare const FREE_TIER = "free";
|
|
12
20
|
/**
|
|
13
21
|
* Abstract base command providing shared functionality for all Mailmodo CLI commands.
|
|
@@ -102,6 +110,12 @@ export declare abstract class BaseCommand extends Command {
|
|
|
102
110
|
* distinguish from a successful update.
|
|
103
111
|
*/
|
|
104
112
|
protected warnFreeTierCapBlocked(jsonOutput: boolean): void;
|
|
113
|
+
/**
|
|
114
|
+
* Fetches the full billing status from `/billing/status`. Returns `null`
|
|
115
|
+
* when the request cannot be completed (no credentials, network failure,
|
|
116
|
+
* non-OK response) so callers can degrade gracefully without halting.
|
|
117
|
+
*/
|
|
118
|
+
protected fetchBillingStatus(): Promise<BillingStatusResult | null>;
|
|
105
119
|
/**
|
|
106
120
|
* Fetches the account's billing tier from `/billing/status`. Returns `null`
|
|
107
121
|
* when the request cannot be completed (no credentials, network failure,
|
package/dist/lib/base-command.js
CHANGED
|
@@ -198,24 +198,33 @@ export class BaseCommand extends Command {
|
|
|
198
198
|
this.warn(chalk.yellow(INFO.FREE_TIER_CAP_BLOCKED));
|
|
199
199
|
}
|
|
200
200
|
/**
|
|
201
|
-
* Fetches the
|
|
201
|
+
* Fetches the full billing status from `/billing/status`. Returns `null`
|
|
202
202
|
* when the request cannot be completed (no credentials, network failure,
|
|
203
203
|
* non-OK response) so callers can degrade gracefully without halting.
|
|
204
|
-
* Callers that need a hard "free vs paid" decision should treat `null` as
|
|
205
|
-
* unknown and fall through to their default behavior.
|
|
206
204
|
*/
|
|
207
|
-
async
|
|
205
|
+
async fetchBillingStatus() {
|
|
208
206
|
try {
|
|
209
207
|
await this.ensureAuth();
|
|
210
208
|
const response = await this.apiClient.get(API_ENDPOINTS.BILLING_STATUS);
|
|
211
209
|
if (!response.ok)
|
|
212
210
|
return null;
|
|
213
|
-
return response.data
|
|
211
|
+
return response.data ?? null;
|
|
214
212
|
}
|
|
215
213
|
catch {
|
|
216
214
|
return null;
|
|
217
215
|
}
|
|
218
216
|
}
|
|
217
|
+
/**
|
|
218
|
+
* Fetches the account's billing tier from `/billing/status`. Returns `null`
|
|
219
|
+
* when the request cannot be completed (no credentials, network failure,
|
|
220
|
+
* non-OK response) so callers can degrade gracefully without halting.
|
|
221
|
+
* Callers that need a hard "free vs paid" decision should treat `null` as
|
|
222
|
+
* unknown and fall through to their default behavior.
|
|
223
|
+
*/
|
|
224
|
+
async fetchBillingTier() {
|
|
225
|
+
const status = await this.fetchBillingStatus();
|
|
226
|
+
return status?.tier ?? null;
|
|
227
|
+
}
|
|
219
228
|
async registerDomain(yamlConfig, inputs, json) {
|
|
220
229
|
const apiPayload = {
|
|
221
230
|
address: inputs.address,
|
package/dist/lib/constants.d.ts
CHANGED
|
@@ -23,10 +23,7 @@ export declare const API_ENDPOINTS: Readonly<{
|
|
|
23
23
|
SEQUENCES_VALIDATE: "/sequences/validate";
|
|
24
24
|
}>;
|
|
25
25
|
export declare const LOGIN_URL = "https://app-vertex-debug.azurewebsites.net/signup.html";
|
|
26
|
-
export declare const DOCS_URL = "https://mailmodo.com/docs/cli";
|
|
27
|
-
export declare const DNS_GUIDE_URL = "https://mailmodo.com/docs/dns";
|
|
28
26
|
export declare const PREVIEW_PORT = 3421;
|
|
29
27
|
export declare const DEFAULT_BRAND_COLOR = "#1A56DB";
|
|
30
|
-
export declare const DEFAULT_MONTHLY_CAP = 5;
|
|
31
28
|
export declare const TEMPLATES_DIR = "mailmodo";
|
|
32
29
|
export declare const YAML_FILE = "mailmodo.yaml";
|
package/dist/lib/constants.js
CHANGED
|
@@ -34,10 +34,7 @@ const PRODUCTION_LOGIN_URL = 'https://app-vertex-debug.azurewebsites.net/signup.
|
|
|
34
34
|
export const LOGIN_URL = process.env.MAILMODO_DEV_TSX
|
|
35
35
|
? DEV_LOGIN_URL
|
|
36
36
|
: PRODUCTION_LOGIN_URL;
|
|
37
|
-
export const DOCS_URL = 'https://mailmodo.com/docs/cli';
|
|
38
|
-
export const DNS_GUIDE_URL = 'https://mailmodo.com/docs/dns';
|
|
39
37
|
export const PREVIEW_PORT = 3421;
|
|
40
38
|
export const DEFAULT_BRAND_COLOR = '#1A56DB';
|
|
41
|
-
export const DEFAULT_MONTHLY_CAP = 5;
|
|
42
39
|
export const TEMPLATES_DIR = 'mailmodo';
|
|
43
40
|
export const YAML_FILE = 'mailmodo.yaml';
|
package/oclif.manifest.json
CHANGED
|
@@ -228,13 +228,19 @@
|
|
|
228
228
|
"index.js"
|
|
229
229
|
]
|
|
230
230
|
},
|
|
231
|
-
"
|
|
231
|
+
"edit": {
|
|
232
232
|
"aliases": [],
|
|
233
|
-
"args": {
|
|
234
|
-
|
|
233
|
+
"args": {
|
|
234
|
+
"id": {
|
|
235
|
+
"description": "Email template ID to edit",
|
|
236
|
+
"name": "id",
|
|
237
|
+
"required": true
|
|
238
|
+
}
|
|
239
|
+
},
|
|
240
|
+
"description": "Edit an email using AI-assisted natural language changes",
|
|
235
241
|
"examples": [
|
|
236
|
-
"<%= config.bin %>
|
|
237
|
-
"<%= config.bin %>
|
|
242
|
+
"<%= config.bin %> edit welcome",
|
|
243
|
+
"<%= config.bin %> edit welcome --change \"make subject more urgent\" --yes"
|
|
238
244
|
],
|
|
239
245
|
"flags": {
|
|
240
246
|
"json": {
|
|
@@ -249,11 +255,18 @@
|
|
|
249
255
|
"name": "yes",
|
|
250
256
|
"allowNo": false,
|
|
251
257
|
"type": "boolean"
|
|
258
|
+
},
|
|
259
|
+
"change": {
|
|
260
|
+
"description": "Natural language description of the change",
|
|
261
|
+
"name": "change",
|
|
262
|
+
"hasDynamicHelp": false,
|
|
263
|
+
"multiple": false,
|
|
264
|
+
"type": "option"
|
|
252
265
|
}
|
|
253
266
|
},
|
|
254
267
|
"hasDynamicHelp": false,
|
|
255
268
|
"hiddenAliases": [],
|
|
256
|
-
"id": "
|
|
269
|
+
"id": "edit",
|
|
257
270
|
"pluginAlias": "@mailmodo/cli",
|
|
258
271
|
"pluginName": "@mailmodo/cli",
|
|
259
272
|
"pluginType": "core",
|
|
@@ -263,23 +276,17 @@
|
|
|
263
276
|
"relativePath": [
|
|
264
277
|
"dist",
|
|
265
278
|
"commands",
|
|
266
|
-
"
|
|
279
|
+
"edit",
|
|
267
280
|
"index.js"
|
|
268
281
|
]
|
|
269
282
|
},
|
|
270
|
-
"
|
|
283
|
+
"emails": {
|
|
271
284
|
"aliases": [],
|
|
272
|
-
"args": {
|
|
273
|
-
|
|
274
|
-
"description": "Email template ID to edit",
|
|
275
|
-
"name": "id",
|
|
276
|
-
"required": true
|
|
277
|
-
}
|
|
278
|
-
},
|
|
279
|
-
"description": "Edit an email using AI-assisted natural language changes",
|
|
285
|
+
"args": {},
|
|
286
|
+
"description": "List and view configured email sequences",
|
|
280
287
|
"examples": [
|
|
281
|
-
"<%= config.bin %>
|
|
282
|
-
"<%= config.bin %>
|
|
288
|
+
"<%= config.bin %> emails",
|
|
289
|
+
"<%= config.bin %> emails --json"
|
|
283
290
|
],
|
|
284
291
|
"flags": {
|
|
285
292
|
"json": {
|
|
@@ -294,18 +301,11 @@
|
|
|
294
301
|
"name": "yes",
|
|
295
302
|
"allowNo": false,
|
|
296
303
|
"type": "boolean"
|
|
297
|
-
},
|
|
298
|
-
"change": {
|
|
299
|
-
"description": "Natural language description of the change",
|
|
300
|
-
"name": "change",
|
|
301
|
-
"hasDynamicHelp": false,
|
|
302
|
-
"multiple": false,
|
|
303
|
-
"type": "option"
|
|
304
304
|
}
|
|
305
305
|
},
|
|
306
306
|
"hasDynamicHelp": false,
|
|
307
307
|
"hiddenAliases": [],
|
|
308
|
-
"id": "
|
|
308
|
+
"id": "emails",
|
|
309
309
|
"pluginAlias": "@mailmodo/cli",
|
|
310
310
|
"pluginName": "@mailmodo/cli",
|
|
311
311
|
"pluginType": "core",
|
|
@@ -315,7 +315,7 @@
|
|
|
315
315
|
"relativePath": [
|
|
316
316
|
"dist",
|
|
317
317
|
"commands",
|
|
318
|
-
"
|
|
318
|
+
"emails",
|
|
319
319
|
"index.js"
|
|
320
320
|
]
|
|
321
321
|
},
|
|
@@ -570,14 +570,13 @@
|
|
|
570
570
|
"index.js"
|
|
571
571
|
]
|
|
572
572
|
},
|
|
573
|
-
"
|
|
573
|
+
"status": {
|
|
574
574
|
"aliases": [],
|
|
575
575
|
"args": {},
|
|
576
|
-
"description": "View and
|
|
576
|
+
"description": "View email performance metrics and quota usage",
|
|
577
577
|
"examples": [
|
|
578
|
-
"<%= config.bin %>
|
|
579
|
-
"<%= config.bin %>
|
|
580
|
-
"<%= config.bin %> settings --json"
|
|
578
|
+
"<%= config.bin %> status",
|
|
579
|
+
"<%= config.bin %> status --json"
|
|
581
580
|
],
|
|
582
581
|
"flags": {
|
|
583
582
|
"json": {
|
|
@@ -592,18 +591,11 @@
|
|
|
592
591
|
"name": "yes",
|
|
593
592
|
"allowNo": false,
|
|
594
593
|
"type": "boolean"
|
|
595
|
-
},
|
|
596
|
-
"set": {
|
|
597
|
-
"description": "Set a setting (format: key=value)",
|
|
598
|
-
"name": "set",
|
|
599
|
-
"hasDynamicHelp": false,
|
|
600
|
-
"multiple": false,
|
|
601
|
-
"type": "option"
|
|
602
594
|
}
|
|
603
595
|
},
|
|
604
596
|
"hasDynamicHelp": false,
|
|
605
597
|
"hiddenAliases": [],
|
|
606
|
-
"id": "
|
|
598
|
+
"id": "status",
|
|
607
599
|
"pluginAlias": "@mailmodo/cli",
|
|
608
600
|
"pluginName": "@mailmodo/cli",
|
|
609
601
|
"pluginType": "core",
|
|
@@ -613,17 +605,18 @@
|
|
|
613
605
|
"relativePath": [
|
|
614
606
|
"dist",
|
|
615
607
|
"commands",
|
|
616
|
-
"
|
|
608
|
+
"status",
|
|
617
609
|
"index.js"
|
|
618
610
|
]
|
|
619
611
|
},
|
|
620
|
-
"
|
|
612
|
+
"settings": {
|
|
621
613
|
"aliases": [],
|
|
622
614
|
"args": {},
|
|
623
|
-
"description": "View
|
|
615
|
+
"description": "View and update project settings",
|
|
624
616
|
"examples": [
|
|
625
|
-
"<%= config.bin %>
|
|
626
|
-
"<%= config.bin %>
|
|
617
|
+
"<%= config.bin %> settings",
|
|
618
|
+
"<%= config.bin %> settings --set brand_color=#0F3460",
|
|
619
|
+
"<%= config.bin %> settings --json"
|
|
627
620
|
],
|
|
628
621
|
"flags": {
|
|
629
622
|
"json": {
|
|
@@ -638,11 +631,18 @@
|
|
|
638
631
|
"name": "yes",
|
|
639
632
|
"allowNo": false,
|
|
640
633
|
"type": "boolean"
|
|
634
|
+
},
|
|
635
|
+
"set": {
|
|
636
|
+
"description": "Set a setting (format: key=value)",
|
|
637
|
+
"name": "set",
|
|
638
|
+
"hasDynamicHelp": false,
|
|
639
|
+
"multiple": false,
|
|
640
|
+
"type": "option"
|
|
641
641
|
}
|
|
642
642
|
},
|
|
643
643
|
"hasDynamicHelp": false,
|
|
644
644
|
"hiddenAliases": [],
|
|
645
|
-
"id": "
|
|
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
|
-
"
|
|
655
|
+
"settings",
|
|
656
656
|
"index.js"
|
|
657
657
|
]
|
|
658
658
|
}
|
|
659
659
|
},
|
|
660
|
-
"version": "0.0.
|
|
660
|
+
"version": "0.0.48"
|
|
661
661
|
}
|