@mailmodo/cli 0.0.46-beta.pr48.74 → 0.0.46
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/billing/index.js +1 -7
- package/dist/commands/settings/index.js +7 -21
- package/dist/lib/base-command.d.ts +0 -25
- package/dist/lib/base-command.js +5 -50
- package/dist/lib/messages.d.ts +0 -1
- package/dist/lib/messages.js +0 -1
- package/oclif.manifest.json +28 -28
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Flags } from '@oclif/core';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
3
|
import open from 'open';
|
|
4
|
-
import { BaseCommand
|
|
4
|
+
import { BaseCommand } from '../../lib/base-command.js';
|
|
5
5
|
import { API_ENDPOINTS } from '../../lib/constants.js';
|
|
6
6
|
import { INFO } from '../../lib/messages.js';
|
|
7
7
|
import { loadYaml, saveYaml } from '../../lib/yaml-config.js';
|
|
@@ -200,12 +200,6 @@ export default class Billing extends BaseCommand {
|
|
|
200
200
|
this.log('');
|
|
201
201
|
}
|
|
202
202
|
async setCap(cap, autoChargeBlockCount, jsonOutput) {
|
|
203
|
-
this.validateBillingCapInputs({ autoChargeBlockCount, cap });
|
|
204
|
-
const tier = await this.fetchBillingTier();
|
|
205
|
-
if (tier === FREE_TIER) {
|
|
206
|
-
this.warnFreeTierCapBlocked(jsonOutput);
|
|
207
|
-
return;
|
|
208
|
-
}
|
|
209
203
|
const data = await this.applyBillingCap({
|
|
210
204
|
autoChargeBlockCount,
|
|
211
205
|
cap,
|
|
@@ -4,7 +4,7 @@ import chalk from 'chalk';
|
|
|
4
4
|
import { existsSync } from 'node:fs';
|
|
5
5
|
import { readFile } from 'node:fs/promises';
|
|
6
6
|
import { resolve } from 'node:path';
|
|
7
|
-
import { BaseCommand
|
|
7
|
+
import { BaseCommand } from '../../lib/base-command.js';
|
|
8
8
|
import { API_ENDPOINTS } from '../../lib/constants.js';
|
|
9
9
|
import { INFO } from '../../lib/messages.js';
|
|
10
10
|
import { saveYaml } from '../../lib/yaml-config.js';
|
|
@@ -52,18 +52,13 @@ export default class Settings extends BaseCommand {
|
|
|
52
52
|
this.log(JSON.stringify({ settings: yamlConfig.project }, null, 2));
|
|
53
53
|
return;
|
|
54
54
|
}
|
|
55
|
-
const
|
|
56
|
-
this.fetchDomainVerified(yamlConfig.project.domain),
|
|
57
|
-
this.fetchBillingTier(),
|
|
58
|
-
]);
|
|
55
|
+
const domainVerified = await this.fetchDomainVerified(yamlConfig.project.domain);
|
|
59
56
|
this.log(`\n Current settings for ${chalk.bold(yamlConfig.project.name || 'project')}:\n`);
|
|
60
57
|
for (const [group, keys] of Object.entries(SETTINGS_GROUPS)) {
|
|
61
|
-
if (group === 'billing' && tier === FREE_TIER)
|
|
62
|
-
continue;
|
|
63
58
|
this.displaySettingsGroup(group, keys, yamlConfig.project, domainVerified);
|
|
64
59
|
}
|
|
65
60
|
if (!flags.yes) {
|
|
66
|
-
await this.promptEditSetting(yamlConfig
|
|
61
|
+
await this.promptEditSetting(yamlConfig);
|
|
67
62
|
}
|
|
68
63
|
}
|
|
69
64
|
async applySetFlag(setFlag, yamlConfig, isJson) {
|
|
@@ -79,7 +74,7 @@ export default class Settings extends BaseCommand {
|
|
|
79
74
|
this.error(`Unknown setting: ${key}`);
|
|
80
75
|
}
|
|
81
76
|
if (propKey === 'monthlyCap') {
|
|
82
|
-
await this.applyMonthlyCapChange(yamlConfig, value, isJson
|
|
77
|
+
await this.applyMonthlyCapChange(yamlConfig, value, isJson);
|
|
83
78
|
return;
|
|
84
79
|
}
|
|
85
80
|
project[propKey] = value;
|
|
@@ -91,17 +86,12 @@ export default class Settings extends BaseCommand {
|
|
|
91
86
|
this.log(`\n ${chalk.green('✓')} ${key} updated to ${chalk.cyan(value)}`);
|
|
92
87
|
this.log(` ${INFO.DEPLOY_TO_APPLY}\n`);
|
|
93
88
|
}
|
|
94
|
-
async applyMonthlyCapChange(yamlConfig, rawValue, isJson
|
|
89
|
+
async applyMonthlyCapChange(yamlConfig, rawValue, isJson) {
|
|
95
90
|
const parsed = Number(rawValue);
|
|
96
91
|
if (!Number.isInteger(parsed) || parsed < 1) {
|
|
97
92
|
this.error('monthly_cap must be a positive integer (blocks).');
|
|
98
93
|
}
|
|
99
94
|
await this.ensureAuth();
|
|
100
|
-
const tier = knownTier ?? (await this.fetchBillingTier());
|
|
101
|
-
if (tier === FREE_TIER) {
|
|
102
|
-
this.warnFreeTierCapBlocked(isJson);
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
95
|
const data = await this.applyBillingCap({ cap: parsed, json: isJson });
|
|
106
96
|
yamlConfig.project.monthlyCap = data.capBlocks;
|
|
107
97
|
await saveYaml(yamlConfig);
|
|
@@ -156,7 +146,7 @@ export default class Settings extends BaseCommand {
|
|
|
156
146
|
* Prompts the user to pick a setting key to edit and dispatches
|
|
157
147
|
* to the appropriate handler for that key.
|
|
158
148
|
*/
|
|
159
|
-
async promptEditSetting(yamlConfig
|
|
149
|
+
async promptEditSetting(yamlConfig) {
|
|
160
150
|
const { project } = yamlConfig;
|
|
161
151
|
const editKey = await input({
|
|
162
152
|
default: 'n',
|
|
@@ -164,10 +154,6 @@ export default class Settings extends BaseCommand {
|
|
|
164
154
|
});
|
|
165
155
|
if (editKey === 'n')
|
|
166
156
|
return;
|
|
167
|
-
if (editKey === 'monthly_cap' && tier === FREE_TIER) {
|
|
168
|
-
this.warnFreeTierCapBlocked(false);
|
|
169
|
-
return;
|
|
170
|
-
}
|
|
171
157
|
const editPropKey = settingKeyToProp(editKey);
|
|
172
158
|
if (!(editPropKey in project)) {
|
|
173
159
|
if (editKey === 'logo_file') {
|
|
@@ -195,7 +181,7 @@ export default class Settings extends BaseCommand {
|
|
|
195
181
|
const newValue = await input({
|
|
196
182
|
message: 'New monthly cap (blocks):',
|
|
197
183
|
});
|
|
198
|
-
await this.applyMonthlyCapChange(yamlConfig, newValue, false
|
|
184
|
+
await this.applyMonthlyCapChange(yamlConfig, newValue, false);
|
|
199
185
|
return;
|
|
200
186
|
}
|
|
201
187
|
if (editKey === 'email_style') {
|
|
@@ -8,7 +8,6 @@ export interface BillingCapUpdateResult {
|
|
|
8
8
|
capEmails: number;
|
|
9
9
|
message: string;
|
|
10
10
|
}
|
|
11
|
-
export declare const FREE_TIER = "free";
|
|
12
11
|
/**
|
|
13
12
|
* Abstract base command providing shared functionality for all Mailmodo CLI commands.
|
|
14
13
|
* Subclasses inherit --json and --yes base flags, authentication enforcement,
|
|
@@ -75,15 +74,6 @@ export declare abstract class BaseCommand extends Command {
|
|
|
75
74
|
fromName: string;
|
|
76
75
|
replyTo: string;
|
|
77
76
|
}>;
|
|
78
|
-
/**
|
|
79
|
-
* Validates the inputs that would be sent to `POST /billing/cap`. Extracted
|
|
80
|
-
* so callers can run cheap, no-API local checks (positive integers) before
|
|
81
|
-
* the tier lookup or any other network round trip.
|
|
82
|
-
*/
|
|
83
|
-
protected validateBillingCapInputs(options: {
|
|
84
|
-
autoChargeBlockCount?: number;
|
|
85
|
-
cap: number;
|
|
86
|
-
}): void;
|
|
87
77
|
/**
|
|
88
78
|
* Updates the account's monthly sending cap on the server.
|
|
89
79
|
* Validates inputs, wraps the POST /billing/cap call in a spinner, and
|
|
@@ -95,21 +85,6 @@ export declare abstract class BaseCommand extends Command {
|
|
|
95
85
|
cap: number;
|
|
96
86
|
json: boolean;
|
|
97
87
|
}): Promise<BillingCapUpdateResult>;
|
|
98
|
-
/**
|
|
99
|
-
* Shared "free-tier users can't set a monthly cap" notice for both the
|
|
100
|
-
* billing and settings commands. Prints a yellow warning in text mode and a
|
|
101
|
-
* `status: 'blocked'` payload in JSON mode so machine-readable callers can
|
|
102
|
-
* distinguish from a successful update.
|
|
103
|
-
*/
|
|
104
|
-
protected warnFreeTierCapBlocked(jsonOutput: boolean): void;
|
|
105
|
-
/**
|
|
106
|
-
* Fetches the account's billing tier from `/billing/status`. Returns `null`
|
|
107
|
-
* when the request cannot be completed (no credentials, network failure,
|
|
108
|
-
* non-OK response) so callers can degrade gracefully without halting.
|
|
109
|
-
* Callers that need a hard "free vs paid" decision should treat `null` as
|
|
110
|
-
* unknown and fall through to their default behavior.
|
|
111
|
-
*/
|
|
112
|
-
protected fetchBillingTier(): Promise<null | string>;
|
|
113
88
|
protected registerDomain(yamlConfig: MailmodoYaml, inputs: {
|
|
114
89
|
address: string;
|
|
115
90
|
domain: string;
|
package/dist/lib/base-command.js
CHANGED
|
@@ -7,7 +7,6 @@ import { loadConfig } from './config.js';
|
|
|
7
7
|
import { API_ENDPOINTS } from './constants.js';
|
|
8
8
|
import { ERRORS, INFO, PROMPTS, recordLabel, VALIDATION } from './messages.js';
|
|
9
9
|
import { loadYaml, saveYaml } from './yaml-config.js';
|
|
10
|
-
export const FREE_TIER = 'free';
|
|
11
10
|
/**
|
|
12
11
|
* Abstract base command providing shared functionality for all Mailmodo CLI commands.
|
|
13
12
|
* Subclasses inherit --json and --yes base flags, authentication enforcement,
|
|
@@ -147,11 +146,12 @@ export class BaseCommand extends Command {
|
|
|
147
146
|
return { address, domain, fromEmail, fromName, replyTo };
|
|
148
147
|
}
|
|
149
148
|
/**
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
*
|
|
149
|
+
* Updates the account's monthly sending cap on the server.
|
|
150
|
+
* Validates inputs, wraps the POST /billing/cap call in a spinner, and
|
|
151
|
+
* surfaces errors via handleApiError. The caller is responsible for any
|
|
152
|
+
* local persistence (e.g. writing `monthlyCap` to mailmodo.yaml).
|
|
153
153
|
*/
|
|
154
|
-
|
|
154
|
+
async applyBillingCap(options) {
|
|
155
155
|
if (options.cap < 1) {
|
|
156
156
|
this.error('Cap must be at least 1 block.');
|
|
157
157
|
}
|
|
@@ -159,15 +159,6 @@ export class BaseCommand extends Command {
|
|
|
159
159
|
options.autoChargeBlockCount < 1) {
|
|
160
160
|
this.error('Auto-charge block count must be at least 1 block.');
|
|
161
161
|
}
|
|
162
|
-
}
|
|
163
|
-
/**
|
|
164
|
-
* Updates the account's monthly sending cap on the server.
|
|
165
|
-
* Validates inputs, wraps the POST /billing/cap call in a spinner, and
|
|
166
|
-
* surfaces errors via handleApiError. The caller is responsible for any
|
|
167
|
-
* local persistence (e.g. writing `monthlyCap` to mailmodo.yaml).
|
|
168
|
-
*/
|
|
169
|
-
async applyBillingCap(options) {
|
|
170
|
-
this.validateBillingCapInputs(options);
|
|
171
162
|
const payload = options.autoChargeBlockCount === undefined
|
|
172
163
|
? { cap: options.cap }
|
|
173
164
|
: {
|
|
@@ -180,42 +171,6 @@ export class BaseCommand extends Command {
|
|
|
180
171
|
}
|
|
181
172
|
return response.data;
|
|
182
173
|
}
|
|
183
|
-
/**
|
|
184
|
-
* Shared "free-tier users can't set a monthly cap" notice for both the
|
|
185
|
-
* billing and settings commands. Prints a yellow warning in text mode and a
|
|
186
|
-
* `status: 'blocked'` payload in JSON mode so machine-readable callers can
|
|
187
|
-
* distinguish from a successful update.
|
|
188
|
-
*/
|
|
189
|
-
warnFreeTierCapBlocked(jsonOutput) {
|
|
190
|
-
if (jsonOutput) {
|
|
191
|
-
this.log(JSON.stringify({
|
|
192
|
-
message: INFO.FREE_TIER_CAP_BLOCKED,
|
|
193
|
-
status: 'blocked',
|
|
194
|
-
tier: FREE_TIER,
|
|
195
|
-
}, null, 2));
|
|
196
|
-
return;
|
|
197
|
-
}
|
|
198
|
-
this.warn(chalk.yellow(INFO.FREE_TIER_CAP_BLOCKED));
|
|
199
|
-
}
|
|
200
|
-
/**
|
|
201
|
-
* Fetches the account's billing tier from `/billing/status`. Returns `null`
|
|
202
|
-
* when the request cannot be completed (no credentials, network failure,
|
|
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
|
-
*/
|
|
207
|
-
async fetchBillingTier() {
|
|
208
|
-
try {
|
|
209
|
-
await this.ensureAuth();
|
|
210
|
-
const response = await this.apiClient.get(API_ENDPOINTS.BILLING_STATUS);
|
|
211
|
-
if (!response.ok)
|
|
212
|
-
return null;
|
|
213
|
-
return response.data?.tier ?? null;
|
|
214
|
-
}
|
|
215
|
-
catch {
|
|
216
|
-
return null;
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
174
|
async registerDomain(yamlConfig, inputs, json) {
|
|
220
175
|
const apiPayload = {
|
|
221
176
|
address: inputs.address,
|
package/dist/lib/messages.d.ts
CHANGED
|
@@ -32,7 +32,6 @@ export declare const INFO: {
|
|
|
32
32
|
readonly DOMAIN_NOT_DEPLOYED_HINT: `When ready, run: ${string}
|
|
33
33
|
Then: ${string}`;
|
|
34
34
|
readonly DOMAIN_PENDING_VERIFICATION: `Your domain is not verified yet. Please verify it first. Run ${string} to check the status.`;
|
|
35
|
-
readonly FREE_TIER_CAP_BLOCKED: `Monthly cap is a paid-tier setting and is not available on the free tier. Run ${string} to add a payment method, then set a cap.`;
|
|
36
35
|
readonly SEQUENCES_NOT_DEPLOYED: `Sequences saved but ${string}.`;
|
|
37
36
|
};
|
|
38
37
|
export declare function yamlParseError(detail: string): string;
|
package/dist/lib/messages.js
CHANGED
|
@@ -32,7 +32,6 @@ export const INFO = {
|
|
|
32
32
|
DNS_RECORDS_FAILED: chalk.yellow('Some records failed.'),
|
|
33
33
|
DOMAIN_NOT_DEPLOYED_HINT: `When ready, run: ${chalk.cyan('mailmodo domain')}\n Then: ${chalk.cyan('mailmodo deploy')}`,
|
|
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
|
-
FREE_TIER_CAP_BLOCKED: `Monthly cap is a paid-tier setting and is not available on the free tier. Run ${chalk.cyan("'mailmodo billing --checkout'")} to add a payment method, then set a cap.`,
|
|
36
35
|
SEQUENCES_NOT_DEPLOYED: `Sequences saved but ${chalk.yellow('NOT deployed')}.`,
|
|
37
36
|
};
|
|
38
37
|
export function yamlParseError(detail) {
|
package/oclif.manifest.json
CHANGED
|
@@ -228,19 +228,13 @@
|
|
|
228
228
|
"index.js"
|
|
229
229
|
]
|
|
230
230
|
},
|
|
231
|
-
"
|
|
231
|
+
"emails": {
|
|
232
232
|
"aliases": [],
|
|
233
|
-
"args": {
|
|
234
|
-
|
|
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",
|
|
233
|
+
"args": {},
|
|
234
|
+
"description": "List and view configured email sequences",
|
|
241
235
|
"examples": [
|
|
242
|
-
"<%= config.bin %>
|
|
243
|
-
"<%= config.bin %>
|
|
236
|
+
"<%= config.bin %> emails",
|
|
237
|
+
"<%= config.bin %> emails --json"
|
|
244
238
|
],
|
|
245
239
|
"flags": {
|
|
246
240
|
"json": {
|
|
@@ -255,18 +249,11 @@
|
|
|
255
249
|
"name": "yes",
|
|
256
250
|
"allowNo": false,
|
|
257
251
|
"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"
|
|
265
252
|
}
|
|
266
253
|
},
|
|
267
254
|
"hasDynamicHelp": false,
|
|
268
255
|
"hiddenAliases": [],
|
|
269
|
-
"id": "
|
|
256
|
+
"id": "emails",
|
|
270
257
|
"pluginAlias": "@mailmodo/cli",
|
|
271
258
|
"pluginName": "@mailmodo/cli",
|
|
272
259
|
"pluginType": "core",
|
|
@@ -276,17 +263,23 @@
|
|
|
276
263
|
"relativePath": [
|
|
277
264
|
"dist",
|
|
278
265
|
"commands",
|
|
279
|
-
"
|
|
266
|
+
"emails",
|
|
280
267
|
"index.js"
|
|
281
268
|
]
|
|
282
269
|
},
|
|
283
|
-
"
|
|
270
|
+
"edit": {
|
|
284
271
|
"aliases": [],
|
|
285
|
-
"args": {
|
|
286
|
-
|
|
272
|
+
"args": {
|
|
273
|
+
"id": {
|
|
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",
|
|
287
280
|
"examples": [
|
|
288
|
-
"<%= config.bin %>
|
|
289
|
-
"<%= config.bin %>
|
|
281
|
+
"<%= config.bin %> edit welcome",
|
|
282
|
+
"<%= config.bin %> edit welcome --change \"make subject more urgent\" --yes"
|
|
290
283
|
],
|
|
291
284
|
"flags": {
|
|
292
285
|
"json": {
|
|
@@ -301,11 +294,18 @@
|
|
|
301
294
|
"name": "yes",
|
|
302
295
|
"allowNo": false,
|
|
303
296
|
"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": "edit",
|
|
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
|
+
"edit",
|
|
319
319
|
"index.js"
|
|
320
320
|
]
|
|
321
321
|
},
|
|
@@ -657,5 +657,5 @@
|
|
|
657
657
|
]
|
|
658
658
|
}
|
|
659
659
|
},
|
|
660
|
-
"version": "0.0.46
|
|
660
|
+
"version": "0.0.46"
|
|
661
661
|
}
|