@mailmodo/cli 0.0.54-beta.pr56.91 → 0.0.54
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 +6 -9
- package/dist/commands/deploy/index.d.ts +32 -1
- package/dist/commands/deploy/index.js +303 -52
- package/dist/commands/edit/index.js +0 -19
- package/dist/commands/init/index.d.ts +0 -1
- package/dist/commands/init/index.js +3 -25
- package/dist/commands/login/index.js +3 -18
- package/dist/commands/preview/index.js +12 -24
- package/dist/commands/settings/index.js +0 -6
- package/dist/lib/api-client.d.ts +0 -5
- package/dist/lib/api-client.js +0 -45
- package/dist/lib/base-command.d.ts +1 -25
- package/dist/lib/base-command.js +5 -91
- package/dist/lib/constants.d.ts +0 -1
- package/dist/lib/constants.js +0 -1
- package/dist/lib/messages.d.ts +0 -22
- package/dist/lib/messages.js +0 -22
- package/oclif.manifest.json +60 -60
- package/package.json +1 -1
- package/dist/lib/deploy/domain-setup.d.ts +0 -8
- package/dist/lib/deploy/domain-setup.js +0 -82
- package/dist/lib/deploy/output.d.ts +0 -5
- package/dist/lib/deploy/output.js +0 -61
- package/dist/lib/deploy/payload.d.ts +0 -41
- package/dist/lib/deploy/payload.js +0 -95
- package/dist/lib/deploy/sequence-status.d.ts +0 -3
- package/dist/lib/deploy/sequence-status.js +0 -56
- package/dist/lib/deploy/types.d.ts +0 -88
- package/dist/lib/deploy/types.js +0 -1
- package/dist/lib/templates/missing-templates.d.ts +0 -5
- package/dist/lib/templates/missing-templates.js +0 -61
- package/dist/lib/templates/types.d.ts +0 -13
- package/dist/lib/templates/types.js +0 -1
|
@@ -6,7 +6,6 @@ import { BaseCommand } from '../../lib/base-command.js';
|
|
|
6
6
|
import { API_ENDPOINTS, PREVIEW_PORT } from '../../lib/constants.js';
|
|
7
7
|
import { INFO } from '../../lib/messages.js';
|
|
8
8
|
import { loadTemplate, getEmailStyle, getTemplateFilename, } from '../../lib/yaml-config.js';
|
|
9
|
-
import { handleMissingTemplates } from '../../lib/templates/missing-templates.js';
|
|
10
9
|
/* eslint-disable camelcase */
|
|
11
10
|
const SAMPLE_DATA = Object.freeze({
|
|
12
11
|
app_url: 'https://yourapp.com',
|
|
@@ -87,28 +86,12 @@ export default class Preview extends BaseCommand {
|
|
|
87
86
|
product_name: yamlConfig.project?.name || 'YourApp', // eslint-disable-line camelcase
|
|
88
87
|
};
|
|
89
88
|
const effectiveStyle = getEmailStyle(email.style, yamlConfig.project?.emailStyle);
|
|
90
|
-
const
|
|
91
|
-
let templateHtml = await loadTemplate(templateFilename);
|
|
92
|
-
if (!templateHtml) {
|
|
93
|
-
await this.ensureAuth();
|
|
94
|
-
const regenCtx = {
|
|
95
|
-
error: (msg) => this.error(msg),
|
|
96
|
-
exit: (code) => this.exit(code),
|
|
97
|
-
log: (msg) => this.log(msg),
|
|
98
|
-
onApiError: (r) => this.handleApiError(r),
|
|
99
|
-
post: (path, body) => this.apiClient.post(path, body),
|
|
100
|
-
spinner: (text, json, work) => this.withApiSpinner({ json, text }, work),
|
|
101
|
-
syncYaml: () => this.syncYamlToServer(),
|
|
102
|
-
};
|
|
103
|
-
const regenerated = await handleMissingTemplates(regenCtx, yamlConfig, [email.id], { json: flags.json, yes: flags.yes });
|
|
104
|
-
if (!regenerated)
|
|
105
|
-
return;
|
|
106
|
-
templateHtml = await loadTemplate(templateFilename);
|
|
107
|
-
if (!templateHtml)
|
|
108
|
-
this.error('Template regeneration failed.');
|
|
109
|
-
}
|
|
89
|
+
const templateHtml = await loadTemplate(getTemplateFilename(email.id, email.style, yamlConfig.project?.emailStyle));
|
|
110
90
|
if (flags.send) {
|
|
111
|
-
|
|
91
|
+
const rendered = templateHtml
|
|
92
|
+
? renderTemplate(templateHtml, sampleData)
|
|
93
|
+
: '';
|
|
94
|
+
await this.sendTestEmail(email, rendered, {
|
|
112
95
|
domain: yamlConfig.project?.domain,
|
|
113
96
|
jsonOutput: flags.json,
|
|
114
97
|
toAddress: flags.send,
|
|
@@ -129,7 +112,10 @@ export default class Preview extends BaseCommand {
|
|
|
129
112
|
* and CI pipelines that cannot open a browser.
|
|
130
113
|
*/
|
|
131
114
|
async renderText(email, templateHtml, sampleData, jsonOutput) {
|
|
132
|
-
const
|
|
115
|
+
const rendered = templateHtml
|
|
116
|
+
? renderTemplate(templateHtml, sampleData)
|
|
117
|
+
: '';
|
|
118
|
+
const plainText = htmlToText(rendered);
|
|
133
119
|
if (jsonOutput) {
|
|
134
120
|
this.log(JSON.stringify({
|
|
135
121
|
body: plainText,
|
|
@@ -195,7 +181,9 @@ export default class Preview extends BaseCommand {
|
|
|
195
181
|
*/
|
|
196
182
|
async startPreviewServer(email, templateHtml, sampleData, opts) {
|
|
197
183
|
const { effectiveStyle, jsonOutput } = opts;
|
|
198
|
-
const rendered =
|
|
184
|
+
const rendered = templateHtml
|
|
185
|
+
? renderTemplate(templateHtml, sampleData)
|
|
186
|
+
: '<p>No template found.</p>';
|
|
199
187
|
const wrapperHtml = `<!DOCTYPE html>
|
|
200
188
|
<html>
|
|
201
189
|
<head>
|
|
@@ -50,7 +50,6 @@ export default class Settings extends BaseCommand {
|
|
|
50
50
|
if (capFromApi !== null) {
|
|
51
51
|
yamlConfig.project.monthlyCap = capFromApi;
|
|
52
52
|
await saveYaml(yamlConfig);
|
|
53
|
-
await this.syncYamlToServer();
|
|
54
53
|
}
|
|
55
54
|
if (flags.json) {
|
|
56
55
|
this.log(JSON.stringify({ settings: yamlConfig.project }, null, 2));
|
|
@@ -84,7 +83,6 @@ export default class Settings extends BaseCommand {
|
|
|
84
83
|
}
|
|
85
84
|
project[propKey] = value;
|
|
86
85
|
await saveYaml(yamlConfig);
|
|
87
|
-
await this.syncYamlToServer();
|
|
88
86
|
if (isJson) {
|
|
89
87
|
this.log(JSON.stringify({ [propKey]: value, status: 'updated' }, null, 2));
|
|
90
88
|
return;
|
|
@@ -106,7 +104,6 @@ export default class Settings extends BaseCommand {
|
|
|
106
104
|
const data = await this.applyBillingCap({ cap: parsed, json: isJson });
|
|
107
105
|
yamlConfig.project.monthlyCap = data.capBlocks;
|
|
108
106
|
await saveYaml(yamlConfig);
|
|
109
|
-
await this.syncYamlToServer();
|
|
110
107
|
if (isJson) {
|
|
111
108
|
this.log(JSON.stringify({ monthlyCap: data.capBlocks, status: 'updated' }, null, 2));
|
|
112
109
|
return;
|
|
@@ -210,7 +207,6 @@ export default class Settings extends BaseCommand {
|
|
|
210
207
|
});
|
|
211
208
|
project.emailStyle = style;
|
|
212
209
|
await saveYaml(yamlConfig);
|
|
213
|
-
await this.syncYamlToServer();
|
|
214
210
|
this.log(`\n ${chalk.green('✓')} email_style updated to ${chalk.cyan(style)}`);
|
|
215
211
|
this.log(` ${INFO.DEPLOY_TO_APPLY}\n`);
|
|
216
212
|
return;
|
|
@@ -220,7 +216,6 @@ export default class Settings extends BaseCommand {
|
|
|
220
216
|
});
|
|
221
217
|
project[editPropKey] = newValue;
|
|
222
218
|
await saveYaml(yamlConfig);
|
|
223
|
-
await this.syncYamlToServer();
|
|
224
219
|
this.log(`\n ${chalk.green('✓')} Updated. ${INFO.DEPLOY_TO_APPLY}\n`);
|
|
225
220
|
}
|
|
226
221
|
/**
|
|
@@ -286,7 +281,6 @@ export default class Settings extends BaseCommand {
|
|
|
286
281
|
yamlConfig.project.logoUrl = response.data?.url || '';
|
|
287
282
|
yamlConfig.project.logoFile = logoPath;
|
|
288
283
|
await saveYaml(yamlConfig);
|
|
289
|
-
await this.syncYamlToServer();
|
|
290
284
|
this.log(`\n Logo uploaded and hosted at:`);
|
|
291
285
|
this.log(` ${chalk.cyan(String(response.data?.url))}`);
|
|
292
286
|
this.log(` Run ${chalk.cyan("'mailmodo deploy'")} to apply to all branded emails.\n`);
|
package/dist/lib/api-client.d.ts
CHANGED
|
@@ -46,11 +46,6 @@ export declare class ApiClient {
|
|
|
46
46
|
* Bearer auth as other requests; does not parse JSON.
|
|
47
47
|
*/
|
|
48
48
|
getFile(url: string): Promise<FileFetchResult>;
|
|
49
|
-
/**
|
|
50
|
-
* GET an endpoint and return the raw response body as a string (e.g. YAML files).
|
|
51
|
-
* Uses Bearer auth; does not parse JSON.
|
|
52
|
-
*/
|
|
53
|
-
getRawText(path: string): Promise<ApiResponse<string>>;
|
|
54
49
|
/**
|
|
55
50
|
* GET an external URL (e.g. blob storage) without auth headers.
|
|
56
51
|
*/
|
package/dist/lib/api-client.js
CHANGED
|
@@ -135,51 +135,6 @@ export class ApiClient {
|
|
|
135
135
|
async getFile(url) {
|
|
136
136
|
return fetchFileWithBearerAuth(url, this.apiKey);
|
|
137
137
|
}
|
|
138
|
-
/**
|
|
139
|
-
* GET an endpoint and return the raw response body as a string (e.g. YAML files).
|
|
140
|
-
* Uses Bearer auth; does not parse JSON.
|
|
141
|
-
*/
|
|
142
|
-
async getRawText(path) {
|
|
143
|
-
const url = this.resolveUrl(path);
|
|
144
|
-
const debug = this.requestDebug(url);
|
|
145
|
-
try {
|
|
146
|
-
const response = await fetch(url.toString(), {
|
|
147
|
-
headers: {
|
|
148
|
-
Authorization: `Bearer ${this.apiKey}`,
|
|
149
|
-
'User-Agent': '@mailmodo/cli',
|
|
150
|
-
},
|
|
151
|
-
method: 'GET',
|
|
152
|
-
});
|
|
153
|
-
const text = await response.text().catch(() => '');
|
|
154
|
-
if (!response.ok) {
|
|
155
|
-
return {
|
|
156
|
-
data: '',
|
|
157
|
-
debug: {
|
|
158
|
-
...debug,
|
|
159
|
-
...(text ? { responseSummary: text.slice(0, 200) } : {}),
|
|
160
|
-
},
|
|
161
|
-
error: text || `Request failed with status ${response.status}`,
|
|
162
|
-
ok: false,
|
|
163
|
-
status: response.status,
|
|
164
|
-
};
|
|
165
|
-
}
|
|
166
|
-
return { data: text, ok: true, status: response.status };
|
|
167
|
-
}
|
|
168
|
-
catch (error) {
|
|
169
|
-
const err = error;
|
|
170
|
-
const isConnectionError = err?.cause?.code === 'ECONNREFUSED' || err?.cause?.code === 'ENOTFOUND';
|
|
171
|
-
const causeCode = err?.cause?.code;
|
|
172
|
-
return {
|
|
173
|
-
data: '',
|
|
174
|
-
debug: { ...debug, ...(causeCode ? { causeCode } : {}) },
|
|
175
|
-
error: isConnectionError
|
|
176
|
-
? 'Cannot connect to Mailmodo API. The API service may not be available yet.'
|
|
177
|
-
: err?.message || 'An unexpected network error occurred.',
|
|
178
|
-
ok: false,
|
|
179
|
-
status: 0,
|
|
180
|
-
};
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
138
|
/**
|
|
184
139
|
* GET an external URL (e.g. blob storage) without auth headers.
|
|
185
140
|
*/
|
|
@@ -60,36 +60,12 @@ export declare abstract class BaseCommand extends Command {
|
|
|
60
60
|
}, work: () => Promise<T>): Promise<T>;
|
|
61
61
|
/**
|
|
62
62
|
* Loads and returns the mailmodo.yaml configuration from the current directory.
|
|
63
|
-
*
|
|
64
|
-
* restore it from the server. Exits with an error if the file cannot be found
|
|
65
|
-
* or restored, directing the user to run init.
|
|
63
|
+
* Exits with an error if the file is not found, directing the user to run init.
|
|
66
64
|
*
|
|
67
65
|
* @returns {Promise<MailmodoYaml>} The parsed mailmodo.yaml containing project
|
|
68
66
|
* settings and all email sequence definitions.
|
|
69
67
|
*/
|
|
70
68
|
protected ensureYaml(): Promise<MailmodoYaml>;
|
|
71
|
-
private fetchAndWriteYaml;
|
|
72
|
-
/**
|
|
73
|
-
* Attempts to fetch mailmodo.yaml from the server and save it locally.
|
|
74
|
-
* Returns null silently on any failure so callers can fall through to an error.
|
|
75
|
-
*/
|
|
76
|
-
private restoreYamlFromServer;
|
|
77
|
-
/**
|
|
78
|
-
* If `mailmodo.yaml` is absent from the current directory, attempts to restore
|
|
79
|
-
* it from the server using the given client. Returns `true` if the file was
|
|
80
|
-
* successfully written, `false` otherwise (file already present, server 404,
|
|
81
|
-
* or any network error). Silent — never throws.
|
|
82
|
-
*
|
|
83
|
-
* Used by `mailmodo login` right after the API key is validated so a returning
|
|
84
|
-
* user automatically gets their config back without having to run `init` again.
|
|
85
|
-
*/
|
|
86
|
-
protected recoverYamlAfterLogin(client: ApiClient): Promise<boolean>;
|
|
87
|
-
/**
|
|
88
|
-
* Uploads the current local mailmodo.yaml to the server as a backup.
|
|
89
|
-
* Best-effort: silently ignores all errors so the originating command
|
|
90
|
-
* always succeeds regardless of sync failures.
|
|
91
|
-
*/
|
|
92
|
-
protected syncYamlToServer(): Promise<void>;
|
|
93
69
|
/**
|
|
94
70
|
* Handles a failed API response by mapping HTTP status codes to
|
|
95
71
|
* user-friendly error messages and exiting the process.
|
package/dist/lib/base-command.js
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
import { existsSync } from 'node:fs';
|
|
2
|
-
import { readFile, writeFile } from 'node:fs/promises';
|
|
3
|
-
import { join } from 'node:path';
|
|
4
1
|
import { input } from '@inquirer/prompts';
|
|
5
2
|
import { Command, Flags } from '@oclif/core';
|
|
6
3
|
import chalk from 'chalk';
|
|
7
4
|
import ora from 'ora';
|
|
8
5
|
import { ApiClient } from './api-client.js';
|
|
9
6
|
import { loadConfig } from './config.js';
|
|
10
|
-
import { API_ENDPOINTS, IS_DEV_MODE
|
|
7
|
+
import { API_ENDPOINTS, IS_DEV_MODE } from './constants.js';
|
|
11
8
|
import { ERRORS, INFO, PROMPTS, quotaExhaustedMessage, recordLabel, VALIDATION, } from './messages.js';
|
|
12
9
|
import { loadYaml, saveYaml } from './yaml-config.js';
|
|
13
10
|
export const FREE_TIER = 'free';
|
|
@@ -79,99 +76,17 @@ export class BaseCommand extends Command {
|
|
|
79
76
|
}
|
|
80
77
|
/**
|
|
81
78
|
* Loads and returns the mailmodo.yaml configuration from the current directory.
|
|
82
|
-
*
|
|
83
|
-
* restore it from the server. Exits with an error if the file cannot be found
|
|
84
|
-
* or restored, directing the user to run init.
|
|
79
|
+
* Exits with an error if the file is not found, directing the user to run init.
|
|
85
80
|
*
|
|
86
81
|
* @returns {Promise<MailmodoYaml>} The parsed mailmodo.yaml containing project
|
|
87
82
|
* settings and all email sequence definitions.
|
|
88
83
|
*/
|
|
89
84
|
async ensureYaml() {
|
|
90
85
|
const config = await loadYaml();
|
|
91
|
-
if (config)
|
|
92
|
-
|
|
93
|
-
const restored = await this.restoreYamlFromServer();
|
|
94
|
-
if (restored)
|
|
95
|
-
return restored;
|
|
96
|
-
this.error(ERRORS.NO_YAML);
|
|
97
|
-
}
|
|
98
|
-
async fetchAndWriteYaml(client) {
|
|
99
|
-
try {
|
|
100
|
-
const response = await client.getRawText(API_ENDPOINTS.ASSETS_YAML);
|
|
101
|
-
if (!response.ok || !response.data)
|
|
102
|
-
return false;
|
|
103
|
-
await writeFile(join(process.cwd(), YAML_FILE), response.data);
|
|
104
|
-
return true;
|
|
105
|
-
}
|
|
106
|
-
catch {
|
|
107
|
-
return false;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
/**
|
|
111
|
-
* Attempts to fetch mailmodo.yaml from the server and save it locally.
|
|
112
|
-
* Returns null silently on any failure so callers can fall through to an error.
|
|
113
|
-
*/
|
|
114
|
-
async restoreYamlFromServer() {
|
|
115
|
-
try {
|
|
116
|
-
let client = this.apiClient;
|
|
117
|
-
if (!client) {
|
|
118
|
-
const envKey = process.env.MAILMODO_API_KEY;
|
|
119
|
-
const apiKey = envKey ?? (await loadConfig())?.apiKey;
|
|
120
|
-
if (!apiKey)
|
|
121
|
-
return null;
|
|
122
|
-
client = new ApiClient(apiKey);
|
|
123
|
-
}
|
|
124
|
-
const written = await this.fetchAndWriteYaml(client);
|
|
125
|
-
if (!written)
|
|
126
|
-
return null;
|
|
127
|
-
this.logToStderr(INFO.YAML_RESTORED_FROM_SERVER);
|
|
128
|
-
return loadYaml();
|
|
129
|
-
}
|
|
130
|
-
catch {
|
|
131
|
-
return null;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
/**
|
|
135
|
-
* If `mailmodo.yaml` is absent from the current directory, attempts to restore
|
|
136
|
-
* it from the server using the given client. Returns `true` if the file was
|
|
137
|
-
* successfully written, `false` otherwise (file already present, server 404,
|
|
138
|
-
* or any network error). Silent — never throws.
|
|
139
|
-
*
|
|
140
|
-
* Used by `mailmodo login` right after the API key is validated so a returning
|
|
141
|
-
* user automatically gets their config back without having to run `init` again.
|
|
142
|
-
*/
|
|
143
|
-
async recoverYamlAfterLogin(client) {
|
|
144
|
-
if (existsSync(join(process.cwd(), YAML_FILE)))
|
|
145
|
-
return false;
|
|
146
|
-
return this.fetchAndWriteYaml(client);
|
|
147
|
-
}
|
|
148
|
-
/**
|
|
149
|
-
* Uploads the current local mailmodo.yaml to the server as a backup.
|
|
150
|
-
* Best-effort: silently ignores all errors so the originating command
|
|
151
|
-
* always succeeds regardless of sync failures.
|
|
152
|
-
*/
|
|
153
|
-
async syncYamlToServer() {
|
|
154
|
-
try {
|
|
155
|
-
let client = this.apiClient;
|
|
156
|
-
if (!client) {
|
|
157
|
-
const envKey = process.env.MAILMODO_API_KEY;
|
|
158
|
-
const apiKey = envKey ?? (await loadConfig())?.apiKey;
|
|
159
|
-
if (!apiKey)
|
|
160
|
-
return;
|
|
161
|
-
client = new ApiClient(apiKey);
|
|
162
|
-
}
|
|
163
|
-
const filePath = join(process.cwd(), YAML_FILE);
|
|
164
|
-
if (!existsSync(filePath))
|
|
165
|
-
return;
|
|
166
|
-
const content = await readFile(filePath, 'utf8');
|
|
167
|
-
const blob = new Blob([content], { type: 'application/yaml' });
|
|
168
|
-
const formData = new FormData();
|
|
169
|
-
formData.append('yaml', blob, YAML_FILE);
|
|
170
|
-
await client.postFormData(API_ENDPOINTS.ASSETS_YAML, formData);
|
|
171
|
-
}
|
|
172
|
-
catch {
|
|
173
|
-
// Silently ignore — local file remains authoritative
|
|
86
|
+
if (!config) {
|
|
87
|
+
this.error(ERRORS.NO_YAML);
|
|
174
88
|
}
|
|
89
|
+
return config;
|
|
175
90
|
}
|
|
176
91
|
/**
|
|
177
92
|
* Handles a failed API response by mapping HTTP status codes to
|
|
@@ -361,7 +276,6 @@ export class BaseCommand extends Command {
|
|
|
361
276
|
if (inputs.replyTo)
|
|
362
277
|
yamlConfig.project.replyTo = inputs.replyTo;
|
|
363
278
|
await saveYaml(yamlConfig);
|
|
364
|
-
await this.syncYamlToServer();
|
|
365
279
|
return {
|
|
366
280
|
dnsGuideUrl: response.data?.dnsGuideUrl,
|
|
367
281
|
dnsRecords: response.data?.dnsRecords || [],
|
package/dist/lib/constants.d.ts
CHANGED
|
@@ -9,7 +9,6 @@ export declare const API_ENDPOINTS: Readonly<{
|
|
|
9
9
|
ANALYTICS: "/analytics";
|
|
10
10
|
ANALYZE: "/analyze";
|
|
11
11
|
ASSETS_LOGO: "/assets/logo";
|
|
12
|
-
ASSETS_YAML: "/assets/yaml";
|
|
13
12
|
AUTH_VALIDATE: "/auth/validate";
|
|
14
13
|
BILLING_CAP: "/billing/cap";
|
|
15
14
|
BILLING_CHECKOUT: "/billing/checkout";
|
package/dist/lib/constants.js
CHANGED
|
@@ -15,7 +15,6 @@ export const API_ENDPOINTS = Object.freeze({
|
|
|
15
15
|
ANALYTICS: '/analytics',
|
|
16
16
|
ANALYZE: '/analyze',
|
|
17
17
|
ASSETS_LOGO: '/assets/logo',
|
|
18
|
-
ASSETS_YAML: '/assets/yaml',
|
|
19
18
|
AUTH_VALIDATE: '/auth/validate',
|
|
20
19
|
BILLING_CAP: '/billing/cap',
|
|
21
20
|
BILLING_CHECKOUT: '/billing/checkout',
|
package/dist/lib/messages.d.ts
CHANGED
|
@@ -13,17 +13,6 @@ export declare const PROMPTS: {
|
|
|
13
13
|
readonly REPLY_TO: "Reply-to address (optional, press Enter to use sender email):";
|
|
14
14
|
readonly SENDER_EMAIL: "Sender email address:";
|
|
15
15
|
};
|
|
16
|
-
export declare const MISSING_TEMPLATES: {
|
|
17
|
-
readonly ABORT_HINT: `Restore the missing files from version control, then run ${string} again.`;
|
|
18
|
-
readonly CHOICE_ABORT: "Abort (restore from version control)";
|
|
19
|
-
readonly CHOICE_REGENERATE: "Re-generate via AI";
|
|
20
|
-
readonly HEADER: `Some email templates are missing from ${string}:`;
|
|
21
|
-
readonly PROMPT_ACTION: "What would you like to do?";
|
|
22
|
-
readonly REGENERATE_NOTE: string;
|
|
23
|
-
readonly REGENERATE_SPINNER: "Regenerating email templates...";
|
|
24
|
-
readonly REVIEW_HINT: `Templates regenerated. Review them with ${string}, then run ${string} again.`;
|
|
25
|
-
readonly YES_ERROR: `Missing templates cannot be resolved with ${string}. Run ${string} without ${string} to regenerate via AI or restore from version control.`;
|
|
26
|
-
};
|
|
27
16
|
export declare const ERRORS: {
|
|
28
17
|
readonly DOMAIN_NOT_CONFIGURED: `No domain configured. Run ${string} to set up your sending domain.`;
|
|
29
18
|
readonly DOMAIN_NOT_REGISTERED: `Sending domain not registered. Run: ${string}`;
|
|
@@ -51,17 +40,6 @@ export declare const INFO: {
|
|
|
51
40
|
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.`;
|
|
52
41
|
readonly PAUSE_CANCELLED: "Pause cancelled. Sequence is still live.";
|
|
53
42
|
readonly SEQUENCES_NOT_DEPLOYED: `Sequences saved but ${string}.`;
|
|
54
|
-
readonly YAML_RESTORED_FROM_SERVER: string;
|
|
55
|
-
readonly YAML_RESTORED_ON_LOGIN: ` mailmodo.yaml restored from server. Run ${string} to re-deploy your sequences.`;
|
|
56
|
-
};
|
|
57
|
-
export declare const DEPLOY: {
|
|
58
|
-
readonly CHANGES_HEADER: "Changes vs. last deployment:";
|
|
59
|
-
readonly DEPLOYING_HEADER: "Deploying:";
|
|
60
|
-
readonly NO_CHANGES: "No changes from last deployment.";
|
|
61
|
-
readonly SDK_DOCS_HINT: `Full SDK docs: ${string}`;
|
|
62
|
-
readonly SDK_EXAMPLE_COMMENT: string;
|
|
63
|
-
readonly SDK_ONBOARDING_HEADER: string;
|
|
64
|
-
readonly SUCCESS: `${string} Emails are live.`;
|
|
65
43
|
};
|
|
66
44
|
export declare function pauseSuccess(sequenceId: string): string;
|
|
67
45
|
export declare function pauseAlready(sequenceId: string): string;
|
package/dist/lib/messages.js
CHANGED
|
@@ -14,17 +14,6 @@ export const PROMPTS = {
|
|
|
14
14
|
REPLY_TO: 'Reply-to address (optional, press Enter to use sender email):',
|
|
15
15
|
SENDER_EMAIL: 'Sender email address:',
|
|
16
16
|
};
|
|
17
|
-
export const MISSING_TEMPLATES = {
|
|
18
|
-
ABORT_HINT: `Restore the missing files from version control, then run ${chalk.cyan('mailmodo deploy')} again.`,
|
|
19
|
-
CHOICE_ABORT: 'Abort (restore from version control)',
|
|
20
|
-
CHOICE_REGENERATE: 'Re-generate via AI',
|
|
21
|
-
HEADER: `Some email templates are missing from ${chalk.cyan('./mailmodo/')}:`,
|
|
22
|
-
PROMPT_ACTION: 'What would you like to do?',
|
|
23
|
-
REGENERATE_NOTE: chalk.yellow(' Note: any previous manual edits to these files will be replaced with a new AI draft.'),
|
|
24
|
-
REGENERATE_SPINNER: 'Regenerating email templates...',
|
|
25
|
-
REVIEW_HINT: `Templates regenerated. Review them with ${chalk.cyan('mailmodo preview')}, then run ${chalk.cyan('mailmodo deploy')} again.`,
|
|
26
|
-
YES_ERROR: `Missing templates cannot be resolved with ${chalk.cyan('--yes')}. Run ${chalk.cyan('mailmodo deploy')} without ${chalk.cyan('--yes')} to regenerate via AI or restore from version control.`,
|
|
27
|
-
};
|
|
28
17
|
export const ERRORS = {
|
|
29
18
|
DOMAIN_NOT_CONFIGURED: `No domain configured. Run ${chalk.cyan('mailmodo domain')} to set up your sending domain.`,
|
|
30
19
|
DOMAIN_NOT_REGISTERED: `Sending domain not registered. Run: ${chalk.cyan('mailmodo domain')}`,
|
|
@@ -51,17 +40,6 @@ export const INFO = {
|
|
|
51
40
|
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.`,
|
|
52
41
|
PAUSE_CANCELLED: 'Pause cancelled. Sequence is still live.',
|
|
53
42
|
SEQUENCES_NOT_DEPLOYED: `Sequences saved but ${chalk.yellow('NOT deployed')}.`,
|
|
54
|
-
YAML_RESTORED_FROM_SERVER: chalk.dim(' mailmodo.yaml not found locally — restored from server.'),
|
|
55
|
-
YAML_RESTORED_ON_LOGIN: ` mailmodo.yaml restored from server. Run ${chalk.cyan("'mailmodo deploy'")} to re-deploy your sequences.`,
|
|
56
|
-
};
|
|
57
|
-
export const DEPLOY = {
|
|
58
|
-
CHANGES_HEADER: 'Changes vs. last deployment:',
|
|
59
|
-
DEPLOYING_HEADER: 'Deploying:',
|
|
60
|
-
NO_CHANGES: 'No changes from last deployment.',
|
|
61
|
-
SDK_DOCS_HINT: `Full SDK docs: ${chalk.cyan('mailmodo.com/docs/sdk')}`,
|
|
62
|
-
SDK_EXAMPLE_COMMENT: chalk.dim('// Example usage:'),
|
|
63
|
-
SDK_ONBOARDING_HEADER: chalk.bold('ADD THIS TO YOUR APP (one-time only):'),
|
|
64
|
-
SUCCESS: `${chalk.green('Deployed.')} Emails are live.`,
|
|
65
43
|
};
|
|
66
44
|
export function pauseSuccess(sequenceId) {
|
|
67
45
|
return `Sequence ${chalk.cyan(sequenceId)} paused. Run ${chalk.cyan(`mailmodo deploy --resume ${sequenceId}`)} to resume.`;
|
package/oclif.manifest.json
CHANGED
|
@@ -198,45 +198,6 @@
|
|
|
198
198
|
"index.js"
|
|
199
199
|
]
|
|
200
200
|
},
|
|
201
|
-
"deployments": {
|
|
202
|
-
"aliases": [],
|
|
203
|
-
"args": {},
|
|
204
|
-
"description": "List every deployed sequence on this account, with the IDs needed for deploy --pause / --resume",
|
|
205
|
-
"examples": [
|
|
206
|
-
"<%= config.bin %> deployments",
|
|
207
|
-
"<%= config.bin %> deployments --json"
|
|
208
|
-
],
|
|
209
|
-
"flags": {
|
|
210
|
-
"json": {
|
|
211
|
-
"description": "Output as JSON",
|
|
212
|
-
"name": "json",
|
|
213
|
-
"allowNo": false,
|
|
214
|
-
"type": "boolean"
|
|
215
|
-
},
|
|
216
|
-
"yes": {
|
|
217
|
-
"char": "y",
|
|
218
|
-
"description": "Skip confirmation prompts",
|
|
219
|
-
"name": "yes",
|
|
220
|
-
"allowNo": false,
|
|
221
|
-
"type": "boolean"
|
|
222
|
-
}
|
|
223
|
-
},
|
|
224
|
-
"hasDynamicHelp": false,
|
|
225
|
-
"hiddenAliases": [],
|
|
226
|
-
"id": "deployments",
|
|
227
|
-
"pluginAlias": "@mailmodo/cli",
|
|
228
|
-
"pluginName": "@mailmodo/cli",
|
|
229
|
-
"pluginType": "core",
|
|
230
|
-
"strict": true,
|
|
231
|
-
"enableJsonFlag": false,
|
|
232
|
-
"isESM": true,
|
|
233
|
-
"relativePath": [
|
|
234
|
-
"dist",
|
|
235
|
-
"commands",
|
|
236
|
-
"deployments",
|
|
237
|
-
"index.js"
|
|
238
|
-
]
|
|
239
|
-
},
|
|
240
201
|
"domain": {
|
|
241
202
|
"aliases": [],
|
|
242
203
|
"args": {},
|
|
@@ -503,6 +464,45 @@
|
|
|
503
464
|
"index.js"
|
|
504
465
|
]
|
|
505
466
|
},
|
|
467
|
+
"deployments": {
|
|
468
|
+
"aliases": [],
|
|
469
|
+
"args": {},
|
|
470
|
+
"description": "List every deployed sequence on this account, with the IDs needed for deploy --pause / --resume",
|
|
471
|
+
"examples": [
|
|
472
|
+
"<%= config.bin %> deployments",
|
|
473
|
+
"<%= config.bin %> deployments --json"
|
|
474
|
+
],
|
|
475
|
+
"flags": {
|
|
476
|
+
"json": {
|
|
477
|
+
"description": "Output as JSON",
|
|
478
|
+
"name": "json",
|
|
479
|
+
"allowNo": false,
|
|
480
|
+
"type": "boolean"
|
|
481
|
+
},
|
|
482
|
+
"yes": {
|
|
483
|
+
"char": "y",
|
|
484
|
+
"description": "Skip confirmation prompts",
|
|
485
|
+
"name": "yes",
|
|
486
|
+
"allowNo": false,
|
|
487
|
+
"type": "boolean"
|
|
488
|
+
}
|
|
489
|
+
},
|
|
490
|
+
"hasDynamicHelp": false,
|
|
491
|
+
"hiddenAliases": [],
|
|
492
|
+
"id": "deployments",
|
|
493
|
+
"pluginAlias": "@mailmodo/cli",
|
|
494
|
+
"pluginName": "@mailmodo/cli",
|
|
495
|
+
"pluginType": "core",
|
|
496
|
+
"strict": true,
|
|
497
|
+
"enableJsonFlag": false,
|
|
498
|
+
"isESM": true,
|
|
499
|
+
"relativePath": [
|
|
500
|
+
"dist",
|
|
501
|
+
"commands",
|
|
502
|
+
"deployments",
|
|
503
|
+
"index.js"
|
|
504
|
+
]
|
|
505
|
+
},
|
|
506
506
|
"logs": {
|
|
507
507
|
"aliases": [],
|
|
508
508
|
"args": {},
|
|
@@ -631,13 +631,14 @@
|
|
|
631
631
|
"index.js"
|
|
632
632
|
]
|
|
633
633
|
},
|
|
634
|
-
"
|
|
634
|
+
"sdk": {
|
|
635
635
|
"aliases": [],
|
|
636
636
|
"args": {},
|
|
637
|
-
"description": "
|
|
637
|
+
"description": "Show the SDK track() / identify() reference for deployed sequences",
|
|
638
638
|
"examples": [
|
|
639
|
-
"<%= config.bin %>
|
|
640
|
-
"<%= config.bin %>
|
|
639
|
+
"<%= config.bin %> sdk",
|
|
640
|
+
"<%= config.bin %> sdk --sequence-id a1b2c3d4",
|
|
641
|
+
"<%= config.bin %> sdk --json"
|
|
641
642
|
],
|
|
642
643
|
"flags": {
|
|
643
644
|
"json": {
|
|
@@ -652,11 +653,18 @@
|
|
|
652
653
|
"name": "yes",
|
|
653
654
|
"allowNo": false,
|
|
654
655
|
"type": "boolean"
|
|
656
|
+
},
|
|
657
|
+
"sequence-id": {
|
|
658
|
+
"description": "Limit output to a single active sequence by ID (default: all active sequences)",
|
|
659
|
+
"name": "sequence-id",
|
|
660
|
+
"hasDynamicHelp": false,
|
|
661
|
+
"multiple": false,
|
|
662
|
+
"type": "option"
|
|
655
663
|
}
|
|
656
664
|
},
|
|
657
665
|
"hasDynamicHelp": false,
|
|
658
666
|
"hiddenAliases": [],
|
|
659
|
-
"id": "
|
|
667
|
+
"id": "sdk",
|
|
660
668
|
"pluginAlias": "@mailmodo/cli",
|
|
661
669
|
"pluginName": "@mailmodo/cli",
|
|
662
670
|
"pluginType": "core",
|
|
@@ -666,7 +674,7 @@
|
|
|
666
674
|
"relativePath": [
|
|
667
675
|
"dist",
|
|
668
676
|
"commands",
|
|
669
|
-
"
|
|
677
|
+
"sdk",
|
|
670
678
|
"index.js"
|
|
671
679
|
]
|
|
672
680
|
},
|
|
@@ -717,14 +725,13 @@
|
|
|
717
725
|
"index.js"
|
|
718
726
|
]
|
|
719
727
|
},
|
|
720
|
-
"
|
|
728
|
+
"status": {
|
|
721
729
|
"aliases": [],
|
|
722
730
|
"args": {},
|
|
723
|
-
"description": "
|
|
731
|
+
"description": "View email performance metrics and quota usage",
|
|
724
732
|
"examples": [
|
|
725
|
-
"<%= config.bin %>
|
|
726
|
-
"<%= config.bin %>
|
|
727
|
-
"<%= config.bin %> sdk --json"
|
|
733
|
+
"<%= config.bin %> status",
|
|
734
|
+
"<%= config.bin %> status --json"
|
|
728
735
|
],
|
|
729
736
|
"flags": {
|
|
730
737
|
"json": {
|
|
@@ -739,18 +746,11 @@
|
|
|
739
746
|
"name": "yes",
|
|
740
747
|
"allowNo": false,
|
|
741
748
|
"type": "boolean"
|
|
742
|
-
},
|
|
743
|
-
"sequence-id": {
|
|
744
|
-
"description": "Limit output to a single active sequence by ID (default: all active sequences)",
|
|
745
|
-
"name": "sequence-id",
|
|
746
|
-
"hasDynamicHelp": false,
|
|
747
|
-
"multiple": false,
|
|
748
|
-
"type": "option"
|
|
749
749
|
}
|
|
750
750
|
},
|
|
751
751
|
"hasDynamicHelp": false,
|
|
752
752
|
"hiddenAliases": [],
|
|
753
|
-
"id": "
|
|
753
|
+
"id": "status",
|
|
754
754
|
"pluginAlias": "@mailmodo/cli",
|
|
755
755
|
"pluginName": "@mailmodo/cli",
|
|
756
756
|
"pluginType": "core",
|
|
@@ -760,10 +760,10 @@
|
|
|
760
760
|
"relativePath": [
|
|
761
761
|
"dist",
|
|
762
762
|
"commands",
|
|
763
|
-
"
|
|
763
|
+
"status",
|
|
764
764
|
"index.js"
|
|
765
765
|
]
|
|
766
766
|
}
|
|
767
767
|
},
|
|
768
|
-
"version": "0.0.54
|
|
768
|
+
"version": "0.0.54"
|
|
769
769
|
}
|
package/package.json
CHANGED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import type { MailmodoYaml } from '../yaml-config.js';
|
|
2
|
-
import type { DeployCtx, DeployFlags, ValidateResponse } from './types.js';
|
|
3
|
-
export declare function validateDeploySequence(ctx: DeployCtx, payload: object, flags: {
|
|
4
|
-
json: boolean;
|
|
5
|
-
}): Promise<ValidateResponse>;
|
|
6
|
-
export declare function verifyDomain(ctx: DeployCtx, jsonOutput: boolean, domain: string): Promise<boolean>;
|
|
7
|
-
export declare function runDomainSetup(ctx: DeployCtx, yamlConfig: MailmodoYaml, flags: DeployFlags): Promise<boolean>;
|
|
8
|
-
export declare function ensureDomainReady(ctx: DeployCtx, yamlConfig: MailmodoYaml, flags: DeployFlags): Promise<boolean>;
|