@mailmodo/cli 0.0.49-beta.pr51.79 → 0.0.49
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/edit/index.js +0 -1
- package/dist/commands/init/index.d.ts +0 -1
- package/dist/commands/init/index.js +6 -10
- package/dist/lib/base-command.d.ts +3 -30
- package/dist/lib/base-command.js +6 -38
- package/dist/lib/constants.d.ts +0 -6
- package/dist/lib/constants.js +0 -6
- package/dist/lib/messages.d.ts +0 -27
- package/dist/lib/messages.js +0 -57
- package/oclif.manifest.json +104 -104
- package/package.json +1 -1
|
@@ -49,7 +49,6 @@ export default class Edit extends BaseCommand {
|
|
|
49
49
|
async runEditStep(ctx, changeDescription, flags) {
|
|
50
50
|
const response = await this.withApiSpinner({ json: flags.json, text: ' Applying AI edits...' }, () => this.callEditApi(changeDescription, ctx.email, ctx.templateHtml));
|
|
51
51
|
if (!response.ok) {
|
|
52
|
-
this.handleAiQuotaError(response, 'edit');
|
|
53
52
|
this.handleApiError(response);
|
|
54
53
|
}
|
|
55
54
|
const updated = response.data;
|
|
@@ -64,7 +64,6 @@ export default class Init extends BaseCommand {
|
|
|
64
64
|
url: productUrl,
|
|
65
65
|
}));
|
|
66
66
|
if (!analysisResponse.ok) {
|
|
67
|
-
this.handleAiQuotaError(analysisResponse, 'init');
|
|
68
67
|
this.handleApiError(analysisResponse);
|
|
69
68
|
}
|
|
70
69
|
const analysis = analysisResponse.data;
|
|
@@ -155,7 +154,12 @@ export default class Init extends BaseCommand {
|
|
|
155
154
|
},
|
|
156
155
|
};
|
|
157
156
|
await saveYaml(yamlConfig);
|
|
158
|
-
await this.
|
|
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
|
+
}
|
|
159
163
|
const templateSaves = analysisPayload.recommendedEmails.flatMap((rec, index) => {
|
|
160
164
|
const generated = generatedEmails[index];
|
|
161
165
|
const saves = [];
|
|
@@ -180,14 +184,6 @@ export default class Init extends BaseCommand {
|
|
|
180
184
|
this.log(` Created ${chalk.green('mailmodo.yaml')} + ${chalk.green(String(emailConfigs.length))} email templates in ${chalk.green('/mailmodo')}\n`);
|
|
181
185
|
this.log(` Run ${chalk.cyan("'mailmodo emails'")} to review.\n`);
|
|
182
186
|
}
|
|
183
|
-
async persistMonthlyCap(yamlConfig) {
|
|
184
|
-
const billingStatus = await this.fetchBillingStatus();
|
|
185
|
-
const monthlyCap = billingStatus?.cap?.inBlocks;
|
|
186
|
-
if (monthlyCap !== null && monthlyCap !== undefined) {
|
|
187
|
-
yamlConfig.project.monthlyCap = monthlyCap;
|
|
188
|
-
await saveYaml(yamlConfig);
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
187
|
async confirmOverwriteIfNeeded(flags) {
|
|
192
188
|
const existing = await loadYaml();
|
|
193
189
|
if (!existing)
|
|
@@ -2,11 +2,6 @@ import { Command } from '@oclif/core';
|
|
|
2
2
|
import { ApiClient, type ApiRequestDebugInfo } from './api-client.js';
|
|
3
3
|
import { type MailmodoConfig } from './config.js';
|
|
4
4
|
import { type MailmodoYaml } from './yaml-config.js';
|
|
5
|
-
/**
|
|
6
|
-
* Kind of AI quota that was exhausted. Drives both the headline default
|
|
7
|
-
* message and the follow-up tip pointing the user at the next-best action.
|
|
8
|
-
*/
|
|
9
|
-
export type AiQuotaFeature = 'edit' | 'init';
|
|
10
5
|
export interface BillingCapUpdateResult {
|
|
11
6
|
autoChargeBlockCount?: number;
|
|
12
7
|
capBlocks: number;
|
|
@@ -81,25 +76,6 @@ export declare abstract class BaseCommand extends Command {
|
|
|
81
76
|
error?: string;
|
|
82
77
|
status: number;
|
|
83
78
|
}): never;
|
|
84
|
-
/**
|
|
85
|
-
* Intercepts a 429 "Monthly quota exhausted" response from an AI rate-limited
|
|
86
|
-
* endpoint (analyze for `init`, email edit for `edit`) and exits with a
|
|
87
|
-
* feature-specific message that includes the server's error text, the reset
|
|
88
|
-
* date, optional retry hint, and the next-best action. Returns without
|
|
89
|
-
* exiting when the response is not a 429 so callers can fall through to
|
|
90
|
-
* `handleApiError` for non-quota failures.
|
|
91
|
-
*
|
|
92
|
-
* @param {{ status: number; error?: string; data?: unknown; debug?: ApiRequestDebugInfo }} response - The failed API response.
|
|
93
|
-
* Must carry the parsed JSON body (`data`) so reset/retry fields can be surfaced.
|
|
94
|
-
* @param {AiQuotaFeature} feature - Which AI quota was hit. Drives the default headline + tip
|
|
95
|
-
* shown when the server omits an explicit `error` string.
|
|
96
|
-
*/
|
|
97
|
-
protected handleAiQuotaError(response: {
|
|
98
|
-
data?: unknown;
|
|
99
|
-
debug?: ApiRequestDebugInfo;
|
|
100
|
-
error?: string;
|
|
101
|
-
status: number;
|
|
102
|
-
}, feature: AiQuotaFeature): void;
|
|
103
79
|
protected collectDomainSetupInputs(yamlConfig: MailmodoYaml, skipPrompts: boolean): Promise<{
|
|
104
80
|
address: string;
|
|
105
81
|
domain: string;
|
|
@@ -168,15 +144,12 @@ export declare abstract class BaseCommand extends Command {
|
|
|
168
144
|
value: string;
|
|
169
145
|
}>, guideUrl: string | undefined, json: boolean): void;
|
|
170
146
|
/**
|
|
171
|
-
* Builds the terminal error string for a failed API call
|
|
172
|
-
*
|
|
173
|
-
* status, response body, error code) are appended only when [[IS_DEV_MODE]]
|
|
174
|
-
* is true so end users never see internal request metadata.
|
|
147
|
+
* Builds the terminal error string for a failed API call, appending request
|
|
148
|
+
* metadata when {@link ApiRequestDebugInfo} is available.
|
|
175
149
|
*
|
|
176
150
|
* @param {string} message - Primary error text (HTTP message or generic).
|
|
177
151
|
* @param {{ status: number; debug?: ApiRequestDebugInfo }} response - Failed API response.
|
|
178
|
-
* @returns {string} Message
|
|
179
|
-
* Request details when running in dev/debug mode.
|
|
152
|
+
* @returns {string} Message plus indented Request details for troubleshooting.
|
|
180
153
|
*/
|
|
181
154
|
private formatApiFailure;
|
|
182
155
|
}
|
package/dist/lib/base-command.js
CHANGED
|
@@ -4,8 +4,8 @@ import chalk from 'chalk';
|
|
|
4
4
|
import ora from 'ora';
|
|
5
5
|
import { ApiClient } from './api-client.js';
|
|
6
6
|
import { loadConfig } from './config.js';
|
|
7
|
-
import { API_ENDPOINTS
|
|
8
|
-
import { ERRORS, INFO, PROMPTS,
|
|
7
|
+
import { API_ENDPOINTS } from './constants.js';
|
|
8
|
+
import { ERRORS, INFO, PROMPTS, recordLabel, VALIDATION } from './messages.js';
|
|
9
9
|
import { loadYaml, saveYaml } from './yaml-config.js';
|
|
10
10
|
export const FREE_TIER = 'free';
|
|
11
11
|
/**
|
|
@@ -107,35 +107,6 @@ export class BaseCommand extends Command {
|
|
|
107
107
|
}
|
|
108
108
|
this.error(this.formatApiFailure(response.error || ERRORS.UNEXPECTED_API, response));
|
|
109
109
|
}
|
|
110
|
-
/**
|
|
111
|
-
* Intercepts a 429 "Monthly quota exhausted" response from an AI rate-limited
|
|
112
|
-
* endpoint (analyze for `init`, email edit for `edit`) and exits with a
|
|
113
|
-
* feature-specific message that includes the server's error text, the reset
|
|
114
|
-
* date, optional retry hint, and the next-best action. Returns without
|
|
115
|
-
* exiting when the response is not a 429 so callers can fall through to
|
|
116
|
-
* `handleApiError` for non-quota failures.
|
|
117
|
-
*
|
|
118
|
-
* @param {{ status: number; error?: string; data?: unknown; debug?: ApiRequestDebugInfo }} response - The failed API response.
|
|
119
|
-
* Must carry the parsed JSON body (`data`) so reset/retry fields can be surfaced.
|
|
120
|
-
* @param {AiQuotaFeature} feature - Which AI quota was hit. Drives the default headline + tip
|
|
121
|
-
* shown when the server omits an explicit `error` string.
|
|
122
|
-
*/
|
|
123
|
-
handleAiQuotaError(response, feature) {
|
|
124
|
-
if (response.status !== 429)
|
|
125
|
-
return;
|
|
126
|
-
const body = (response.data ?? {});
|
|
127
|
-
const isInit = feature === 'init';
|
|
128
|
-
const message = quotaExhaustedMessage({
|
|
129
|
-
defaultMessage: isInit
|
|
130
|
-
? ERRORS.QUOTA_INIT_DEFAULT
|
|
131
|
-
: ERRORS.QUOTA_EDIT_DEFAULT,
|
|
132
|
-
limitReset: body.limitReset,
|
|
133
|
-
retryAfter: body.retryAfter,
|
|
134
|
-
serverError: typeof body.error === 'string' ? body.error : undefined,
|
|
135
|
-
tip: isInit ? ERRORS.QUOTA_INIT_TIP : ERRORS.QUOTA_EDIT_TIP,
|
|
136
|
-
});
|
|
137
|
-
this.error(this.formatApiFailure(message, response));
|
|
138
|
-
}
|
|
139
110
|
async collectDomainSetupInputs(yamlConfig, skipPrompts) {
|
|
140
111
|
if (skipPrompts) {
|
|
141
112
|
const domain = yamlConfig.project?.domain || '';
|
|
@@ -296,19 +267,16 @@ export class BaseCommand extends Command {
|
|
|
296
267
|
this.log(` Full guide: ${chalk.cyan(guideUrl)}\n`);
|
|
297
268
|
}
|
|
298
269
|
/**
|
|
299
|
-
* Builds the terminal error string for a failed API call
|
|
300
|
-
*
|
|
301
|
-
* status, response body, error code) are appended only when [[IS_DEV_MODE]]
|
|
302
|
-
* is true so end users never see internal request metadata.
|
|
270
|
+
* Builds the terminal error string for a failed API call, appending request
|
|
271
|
+
* metadata when {@link ApiRequestDebugInfo} is available.
|
|
303
272
|
*
|
|
304
273
|
* @param {string} message - Primary error text (HTTP message or generic).
|
|
305
274
|
* @param {{ status: number; debug?: ApiRequestDebugInfo }} response - Failed API response.
|
|
306
|
-
* @returns {string} Message
|
|
307
|
-
* Request details when running in dev/debug mode.
|
|
275
|
+
* @returns {string} Message plus indented Request details for troubleshooting.
|
|
308
276
|
*/
|
|
309
277
|
formatApiFailure(message, response) {
|
|
310
278
|
const { debug, status } = response;
|
|
311
|
-
if (!
|
|
279
|
+
if (!debug) {
|
|
312
280
|
return message;
|
|
313
281
|
}
|
|
314
282
|
return [
|
package/dist/lib/constants.d.ts
CHANGED
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* True when the CLI is running in a dev/debug context. Verbose request
|
|
3
|
-
* diagnostics (URL, status, response body, error code) are only surfaced
|
|
4
|
-
* when this is true so end users never see internal request metadata.
|
|
5
|
-
*/
|
|
6
|
-
export declare const IS_DEV_MODE: boolean;
|
|
7
1
|
export declare const API_BASE_URL = "https://app-vertex-debug.azurewebsites.net";
|
|
8
2
|
export declare const API_ENDPOINTS: Readonly<{
|
|
9
3
|
ANALYTICS: "/analytics";
|
package/dist/lib/constants.js
CHANGED
|
@@ -1,11 +1,5 @@
|
|
|
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
|
-
/**
|
|
4
|
-
* True when the CLI is running in a dev/debug context. Verbose request
|
|
5
|
-
* diagnostics (URL, status, response body, error code) are only surfaced
|
|
6
|
-
* when this is true so end users never see internal request metadata.
|
|
7
|
-
*/
|
|
8
|
-
export const IS_DEV_MODE = Boolean(process.env.MAILMODO_DEV_TSX || process.env.MAILMODO_DEBUG);
|
|
9
3
|
// const PRODUCTION_API_BASE_URL = 'https://api.mailmodo.com';
|
|
10
4
|
const PRODUCTION_API_BASE_URL = 'https://app-vertex-debug.azurewebsites.net';
|
|
11
5
|
export const API_BASE_URL = process.env.MAILMODO_DEV_TSX
|
package/dist/lib/messages.d.ts
CHANGED
|
@@ -19,10 +19,6 @@ export declare const ERRORS: {
|
|
|
19
19
|
readonly INVALID_API_KEY: `Invalid API key. Run ${string} to re-authenticate.`;
|
|
20
20
|
readonly NOT_LOGGED_IN: `Not logged in. Run ${string} to authenticate.`;
|
|
21
21
|
readonly NO_YAML: `No mailmodo.yaml found. Run ${string} first.`;
|
|
22
|
-
readonly QUOTA_EDIT_DEFAULT: "Edit limit reached for this month.";
|
|
23
|
-
readonly QUOTA_EDIT_TIP: "AI edits are limited to 50 per account per month. Manually edit the template file under ./mailmodo to make further changes.";
|
|
24
|
-
readonly QUOTA_INIT_DEFAULT: "Regeneration limit reached.";
|
|
25
|
-
readonly QUOTA_INIT_TIP: `Regenerations are limited to 5 per account per month. Run ${string} to modify individual emails instead.`;
|
|
26
22
|
readonly RATE_LIMIT: "Rate limit exceeded. Please try again later.";
|
|
27
23
|
readonly UNEXPECTED_API: "An unexpected API error occurred.";
|
|
28
24
|
};
|
|
@@ -41,26 +37,3 @@ export declare const INFO: {
|
|
|
41
37
|
};
|
|
42
38
|
export declare function yamlParseError(detail: string): string;
|
|
43
39
|
export declare function recordLabel(index: number): string;
|
|
44
|
-
/**
|
|
45
|
-
* Parses an ISO-8601 timestamp into a `YYYY-MM-DD` date string.
|
|
46
|
-
* Returns the raw input if parsing fails so the original value is preserved.
|
|
47
|
-
*/
|
|
48
|
-
export declare function formatQuotaResetDate(value?: string): string | undefined;
|
|
49
|
-
/**
|
|
50
|
-
* Formats a `retry-after` value (seconds) into a short, human-readable hint
|
|
51
|
-
* suitable for appending to a 429 error message.
|
|
52
|
-
*/
|
|
53
|
-
export declare function formatRetryAfter(seconds?: number): string | undefined;
|
|
54
|
-
/**
|
|
55
|
-
* Builds the multi-line message printed when an AI quota (init regeneration or
|
|
56
|
-
* edit) is exhausted. `serverError` is the message returned by the API; the
|
|
57
|
-
* default text is used when the server omits it. The tip lists the next action
|
|
58
|
-
* the user can take (e.g. switch from init to edit).
|
|
59
|
-
*/
|
|
60
|
-
export declare function quotaExhaustedMessage(input: {
|
|
61
|
-
defaultMessage: string;
|
|
62
|
-
limitReset?: string;
|
|
63
|
-
retryAfter?: number;
|
|
64
|
-
serverError?: string;
|
|
65
|
-
tip: string;
|
|
66
|
-
}): string;
|
package/dist/lib/messages.js
CHANGED
|
@@ -20,10 +20,6 @@ export const ERRORS = {
|
|
|
20
20
|
INVALID_API_KEY: `Invalid API key. Run ${chalk.cyan('mailmodo login')} to re-authenticate.`,
|
|
21
21
|
NOT_LOGGED_IN: `Not logged in. Run ${chalk.cyan('mailmodo login')} to authenticate.`,
|
|
22
22
|
NO_YAML: `No mailmodo.yaml found. Run ${chalk.cyan('mailmodo init')} first.`,
|
|
23
|
-
QUOTA_EDIT_DEFAULT: 'Edit limit reached for this month.',
|
|
24
|
-
QUOTA_EDIT_TIP: 'AI edits are limited to 50 per account per month. Manually edit the template file under ./mailmodo to make further changes.',
|
|
25
|
-
QUOTA_INIT_DEFAULT: 'Regeneration limit reached.',
|
|
26
|
-
QUOTA_INIT_TIP: `Regenerations are limited to 5 per account per month. Run ${chalk.cyan('mailmodo edit <id>')} to modify individual emails instead.`,
|
|
27
23
|
RATE_LIMIT: 'Rate limit exceeded. Please try again later.',
|
|
28
24
|
UNEXPECTED_API: 'An unexpected API error occurred.',
|
|
29
25
|
};
|
|
@@ -46,56 +42,3 @@ export function recordLabel(index) {
|
|
|
46
42
|
const labels = ['DKIM', 'DMARC', 'Return Path'];
|
|
47
43
|
return labels[index] || `Record ${index + 1}`;
|
|
48
44
|
}
|
|
49
|
-
/**
|
|
50
|
-
* Parses an ISO-8601 timestamp into a `YYYY-MM-DD` date string.
|
|
51
|
-
* Returns the raw input if parsing fails so the original value is preserved.
|
|
52
|
-
*/
|
|
53
|
-
export function formatQuotaResetDate(value) {
|
|
54
|
-
if (!value)
|
|
55
|
-
return undefined;
|
|
56
|
-
const parsed = new Date(value);
|
|
57
|
-
if (Number.isNaN(parsed.getTime()))
|
|
58
|
-
return value;
|
|
59
|
-
const year = parsed.getUTCFullYear();
|
|
60
|
-
const month = String(parsed.getUTCMonth() + 1).padStart(2, '0');
|
|
61
|
-
const day = String(parsed.getUTCDate()).padStart(2, '0');
|
|
62
|
-
return `${year}-${month}-${day}`;
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* Formats a `retry-after` value (seconds) into a short, human-readable hint
|
|
66
|
-
* suitable for appending to a 429 error message.
|
|
67
|
-
*/
|
|
68
|
-
export function formatRetryAfter(seconds) {
|
|
69
|
-
if (typeof seconds !== 'number' || !Number.isFinite(seconds) || seconds <= 0)
|
|
70
|
-
return undefined;
|
|
71
|
-
if (seconds < 60)
|
|
72
|
-
return `${Math.round(seconds)} seconds`;
|
|
73
|
-
const minutes = Math.round(seconds / 60);
|
|
74
|
-
if (minutes < 60)
|
|
75
|
-
return `${minutes} minutes`;
|
|
76
|
-
const hours = Math.round(seconds / 3600);
|
|
77
|
-
if (hours < 24)
|
|
78
|
-
return `${hours} hours`;
|
|
79
|
-
const days = Math.round(seconds / 86_400);
|
|
80
|
-
return `${days} days`;
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* Builds the multi-line message printed when an AI quota (init regeneration or
|
|
84
|
-
* edit) is exhausted. `serverError` is the message returned by the API; the
|
|
85
|
-
* default text is used when the server omits it. The tip lists the next action
|
|
86
|
-
* the user can take (e.g. switch from init to edit).
|
|
87
|
-
*/
|
|
88
|
-
export function quotaExhaustedMessage(input) {
|
|
89
|
-
const headline = input.serverError || input.defaultMessage;
|
|
90
|
-
const lines = [headline];
|
|
91
|
-
const resetDate = formatQuotaResetDate(input.limitReset);
|
|
92
|
-
if (resetDate && !headline.includes(resetDate)) {
|
|
93
|
-
lines.push(`Resets on ${resetDate}.`);
|
|
94
|
-
}
|
|
95
|
-
const retryHint = formatRetryAfter(input.retryAfter);
|
|
96
|
-
if (retryHint) {
|
|
97
|
-
lines.push(`Try again in ${retryHint}.`);
|
|
98
|
-
}
|
|
99
|
-
lines.push('', input.tip);
|
|
100
|
-
return lines.join('\n');
|
|
101
|
-
}
|
package/oclif.manifest.json
CHANGED
|
@@ -76,14 +76,15 @@
|
|
|
76
76
|
"index.js"
|
|
77
77
|
]
|
|
78
78
|
},
|
|
79
|
-
"
|
|
79
|
+
"contacts": {
|
|
80
80
|
"aliases": [],
|
|
81
81
|
"args": {},
|
|
82
|
-
"description": "
|
|
82
|
+
"description": "Manage contacts — search, export, or delete",
|
|
83
83
|
"examples": [
|
|
84
|
-
"<%= config.bin %>
|
|
85
|
-
"<%= config.bin %>
|
|
86
|
-
"<%= config.bin %>
|
|
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"
|
|
87
88
|
],
|
|
88
89
|
"flags": {
|
|
89
90
|
"json": {
|
|
@@ -99,22 +100,30 @@
|
|
|
99
100
|
"allowNo": false,
|
|
100
101
|
"type": "boolean"
|
|
101
102
|
},
|
|
102
|
-
"
|
|
103
|
-
"description": "
|
|
104
|
-
"name": "
|
|
105
|
-
"
|
|
106
|
-
"
|
|
103
|
+
"delete": {
|
|
104
|
+
"description": "GDPR hard delete a contact by email",
|
|
105
|
+
"name": "delete",
|
|
106
|
+
"hasDynamicHelp": false,
|
|
107
|
+
"multiple": false,
|
|
108
|
+
"type": "option"
|
|
107
109
|
},
|
|
108
|
-
"
|
|
109
|
-
"description": "
|
|
110
|
-
"name": "
|
|
110
|
+
"export": {
|
|
111
|
+
"description": "Export all contacts as GDPR-compliant CSV (writes contacts.csv in the current directory)",
|
|
112
|
+
"name": "export",
|
|
111
113
|
"allowNo": false,
|
|
112
114
|
"type": "boolean"
|
|
115
|
+
},
|
|
116
|
+
"search": {
|
|
117
|
+
"description": "Search for a contact by email",
|
|
118
|
+
"name": "search",
|
|
119
|
+
"hasDynamicHelp": false,
|
|
120
|
+
"multiple": false,
|
|
121
|
+
"type": "option"
|
|
113
122
|
}
|
|
114
123
|
},
|
|
115
124
|
"hasDynamicHelp": false,
|
|
116
125
|
"hiddenAliases": [],
|
|
117
|
-
"id": "
|
|
126
|
+
"id": "contacts",
|
|
118
127
|
"pluginAlias": "@mailmodo/cli",
|
|
119
128
|
"pluginName": "@mailmodo/cli",
|
|
120
129
|
"pluginType": "core",
|
|
@@ -124,7 +133,7 @@
|
|
|
124
133
|
"relativePath": [
|
|
125
134
|
"dist",
|
|
126
135
|
"commands",
|
|
127
|
-
"
|
|
136
|
+
"contacts",
|
|
128
137
|
"index.js"
|
|
129
138
|
]
|
|
130
139
|
},
|
|
@@ -167,15 +176,14 @@
|
|
|
167
176
|
"index.js"
|
|
168
177
|
]
|
|
169
178
|
},
|
|
170
|
-
"
|
|
179
|
+
"domain": {
|
|
171
180
|
"aliases": [],
|
|
172
181
|
"args": {},
|
|
173
|
-
"description": "
|
|
182
|
+
"description": "Set up and verify your sending domain",
|
|
174
183
|
"examples": [
|
|
175
|
-
"<%= config.bin %>
|
|
176
|
-
"<%= config.bin %>
|
|
177
|
-
"<%= config.bin %>
|
|
178
|
-
"<%= config.bin %> contacts --delete sarah@example.com"
|
|
184
|
+
"<%= config.bin %> domain",
|
|
185
|
+
"<%= config.bin %> domain --verify",
|
|
186
|
+
"<%= config.bin %> domain --status"
|
|
179
187
|
],
|
|
180
188
|
"flags": {
|
|
181
189
|
"json": {
|
|
@@ -191,30 +199,22 @@
|
|
|
191
199
|
"allowNo": false,
|
|
192
200
|
"type": "boolean"
|
|
193
201
|
},
|
|
194
|
-
"
|
|
195
|
-
"description": "
|
|
196
|
-
"name": "
|
|
197
|
-
"hasDynamicHelp": false,
|
|
198
|
-
"multiple": false,
|
|
199
|
-
"type": "option"
|
|
200
|
-
},
|
|
201
|
-
"export": {
|
|
202
|
-
"description": "Export all contacts as GDPR-compliant CSV (writes contacts.csv in the current directory)",
|
|
203
|
-
"name": "export",
|
|
202
|
+
"status": {
|
|
203
|
+
"description": "Show domain health status",
|
|
204
|
+
"name": "status",
|
|
204
205
|
"allowNo": false,
|
|
205
206
|
"type": "boolean"
|
|
206
207
|
},
|
|
207
|
-
"
|
|
208
|
-
"description": "
|
|
209
|
-
"name": "
|
|
210
|
-
"
|
|
211
|
-
"
|
|
212
|
-
"type": "option"
|
|
208
|
+
"verify": {
|
|
209
|
+
"description": "Verify DNS records",
|
|
210
|
+
"name": "verify",
|
|
211
|
+
"allowNo": false,
|
|
212
|
+
"type": "boolean"
|
|
213
213
|
}
|
|
214
214
|
},
|
|
215
215
|
"hasDynamicHelp": false,
|
|
216
216
|
"hiddenAliases": [],
|
|
217
|
-
"id": "
|
|
217
|
+
"id": "domain",
|
|
218
218
|
"pluginAlias": "@mailmodo/cli",
|
|
219
219
|
"pluginName": "@mailmodo/cli",
|
|
220
220
|
"pluginType": "core",
|
|
@@ -224,7 +224,7 @@
|
|
|
224
224
|
"relativePath": [
|
|
225
225
|
"dist",
|
|
226
226
|
"commands",
|
|
227
|
-
"
|
|
227
|
+
"domain",
|
|
228
228
|
"index.js"
|
|
229
229
|
]
|
|
230
230
|
},
|
|
@@ -365,6 +365,44 @@
|
|
|
365
365
|
"index.js"
|
|
366
366
|
]
|
|
367
367
|
},
|
|
368
|
+
"logout": {
|
|
369
|
+
"aliases": [],
|
|
370
|
+
"args": {},
|
|
371
|
+
"description": "Sign out by removing saved credentials from this machine",
|
|
372
|
+
"examples": [
|
|
373
|
+
"<%= config.bin %> logout"
|
|
374
|
+
],
|
|
375
|
+
"flags": {
|
|
376
|
+
"json": {
|
|
377
|
+
"description": "Output as JSON",
|
|
378
|
+
"name": "json",
|
|
379
|
+
"allowNo": false,
|
|
380
|
+
"type": "boolean"
|
|
381
|
+
},
|
|
382
|
+
"yes": {
|
|
383
|
+
"char": "y",
|
|
384
|
+
"description": "Skip confirmation prompts",
|
|
385
|
+
"name": "yes",
|
|
386
|
+
"allowNo": false,
|
|
387
|
+
"type": "boolean"
|
|
388
|
+
}
|
|
389
|
+
},
|
|
390
|
+
"hasDynamicHelp": false,
|
|
391
|
+
"hiddenAliases": [],
|
|
392
|
+
"id": "logout",
|
|
393
|
+
"pluginAlias": "@mailmodo/cli",
|
|
394
|
+
"pluginName": "@mailmodo/cli",
|
|
395
|
+
"pluginType": "core",
|
|
396
|
+
"strict": true,
|
|
397
|
+
"enableJsonFlag": false,
|
|
398
|
+
"isESM": true,
|
|
399
|
+
"relativePath": [
|
|
400
|
+
"dist",
|
|
401
|
+
"commands",
|
|
402
|
+
"logout",
|
|
403
|
+
"index.js"
|
|
404
|
+
]
|
|
405
|
+
},
|
|
368
406
|
"login": {
|
|
369
407
|
"aliases": [],
|
|
370
408
|
"args": {},
|
|
@@ -404,12 +442,19 @@
|
|
|
404
442
|
"index.js"
|
|
405
443
|
]
|
|
406
444
|
},
|
|
407
|
-
"
|
|
445
|
+
"preview": {
|
|
408
446
|
"aliases": [],
|
|
409
|
-
"args": {
|
|
410
|
-
|
|
447
|
+
"args": {
|
|
448
|
+
"id": {
|
|
449
|
+
"description": "Email template ID to preview",
|
|
450
|
+
"name": "id"
|
|
451
|
+
}
|
|
452
|
+
},
|
|
453
|
+
"description": "Preview an email in browser, as text, or send a test",
|
|
411
454
|
"examples": [
|
|
412
|
-
"<%= config.bin %>
|
|
455
|
+
"<%= config.bin %> preview welcome",
|
|
456
|
+
"<%= config.bin %> preview welcome --text",
|
|
457
|
+
"<%= config.bin %> preview welcome --send me@example.com"
|
|
413
458
|
],
|
|
414
459
|
"flags": {
|
|
415
460
|
"json": {
|
|
@@ -424,11 +469,24 @@
|
|
|
424
469
|
"name": "yes",
|
|
425
470
|
"allowNo": false,
|
|
426
471
|
"type": "boolean"
|
|
472
|
+
},
|
|
473
|
+
"send": {
|
|
474
|
+
"description": "Send test email to this address",
|
|
475
|
+
"name": "send",
|
|
476
|
+
"hasDynamicHelp": false,
|
|
477
|
+
"multiple": false,
|
|
478
|
+
"type": "option"
|
|
479
|
+
},
|
|
480
|
+
"text": {
|
|
481
|
+
"description": "Output plain text version (for AI agents)",
|
|
482
|
+
"name": "text",
|
|
483
|
+
"allowNo": false,
|
|
484
|
+
"type": "boolean"
|
|
427
485
|
}
|
|
428
486
|
},
|
|
429
487
|
"hasDynamicHelp": false,
|
|
430
488
|
"hiddenAliases": [],
|
|
431
|
-
"id": "
|
|
489
|
+
"id": "preview",
|
|
432
490
|
"pluginAlias": "@mailmodo/cli",
|
|
433
491
|
"pluginName": "@mailmodo/cli",
|
|
434
492
|
"pluginType": "core",
|
|
@@ -438,7 +496,7 @@
|
|
|
438
496
|
"relativePath": [
|
|
439
497
|
"dist",
|
|
440
498
|
"commands",
|
|
441
|
-
"
|
|
499
|
+
"preview",
|
|
442
500
|
"index.js"
|
|
443
501
|
]
|
|
444
502
|
},
|
|
@@ -597,65 +655,7 @@
|
|
|
597
655
|
"status",
|
|
598
656
|
"index.js"
|
|
599
657
|
]
|
|
600
|
-
},
|
|
601
|
-
"preview": {
|
|
602
|
-
"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",
|
|
610
|
-
"examples": [
|
|
611
|
-
"<%= config.bin %> preview welcome",
|
|
612
|
-
"<%= config.bin %> preview welcome --text",
|
|
613
|
-
"<%= config.bin %> preview welcome --send me@example.com"
|
|
614
|
-
],
|
|
615
|
-
"flags": {
|
|
616
|
-
"json": {
|
|
617
|
-
"description": "Output as JSON",
|
|
618
|
-
"name": "json",
|
|
619
|
-
"allowNo": false,
|
|
620
|
-
"type": "boolean"
|
|
621
|
-
},
|
|
622
|
-
"yes": {
|
|
623
|
-
"char": "y",
|
|
624
|
-
"description": "Skip confirmation prompts",
|
|
625
|
-
"name": "yes",
|
|
626
|
-
"allowNo": false,
|
|
627
|
-
"type": "boolean"
|
|
628
|
-
},
|
|
629
|
-
"send": {
|
|
630
|
-
"description": "Send test email to this address",
|
|
631
|
-
"name": "send",
|
|
632
|
-
"hasDynamicHelp": false,
|
|
633
|
-
"multiple": false,
|
|
634
|
-
"type": "option"
|
|
635
|
-
},
|
|
636
|
-
"text": {
|
|
637
|
-
"description": "Output plain text version (for AI agents)",
|
|
638
|
-
"name": "text",
|
|
639
|
-
"allowNo": false,
|
|
640
|
-
"type": "boolean"
|
|
641
|
-
}
|
|
642
|
-
},
|
|
643
|
-
"hasDynamicHelp": false,
|
|
644
|
-
"hiddenAliases": [],
|
|
645
|
-
"id": "preview",
|
|
646
|
-
"pluginAlias": "@mailmodo/cli",
|
|
647
|
-
"pluginName": "@mailmodo/cli",
|
|
648
|
-
"pluginType": "core",
|
|
649
|
-
"strict": true,
|
|
650
|
-
"enableJsonFlag": false,
|
|
651
|
-
"isESM": true,
|
|
652
|
-
"relativePath": [
|
|
653
|
-
"dist",
|
|
654
|
-
"commands",
|
|
655
|
-
"preview",
|
|
656
|
-
"index.js"
|
|
657
|
-
]
|
|
658
658
|
}
|
|
659
659
|
},
|
|
660
|
-
"version": "0.0.49
|
|
660
|
+
"version": "0.0.49"
|
|
661
661
|
}
|