@myapihq/cli 1.0.82 → 1.1.0-wip.0
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/auth.d.ts +8 -3
- package/dist/commands/auth.js +11 -29
- package/dist/commands/billing.d.ts +8 -4
- package/dist/commands/billing.js +43 -22
- package/dist/commands/config.d.ts +8 -5
- package/dist/commands/config.js +63 -28
- package/dist/commands/domain.d.ts +12 -9
- package/dist/commands/domain.js +117 -86
- package/dist/commands/email.d.ts +4 -12
- package/dist/commands/email.js +490 -128
- package/dist/commands/funnel.d.ts +10 -7
- package/dist/commands/funnel.js +78 -55
- package/dist/commands/image.js +25 -15
- package/dist/commands/keys.d.ts +8 -3
- package/dist/commands/keys.js +67 -28
- package/dist/commands/org.d.ts +9 -5
- package/dist/commands/org.js +121 -53
- package/dist/commands/pixel.js +23 -11
- package/dist/commands/setup.d.ts +3 -2
- package/dist/commands/setup.js +44 -77
- package/dist/commands/storage.js +25 -15
- package/dist/commands/update.d.ts +2 -1
- package/dist/commands/url.js +19 -7
- package/dist/commands/webhook.d.ts +8 -5
- package/dist/commands/webhook.js +52 -36
- package/dist/commands/workflow.d.ts +13 -7
- package/dist/commands/workflow.js +158 -56
- package/dist/flags.d.ts +8 -0
- package/dist/flags.js +88 -0
- package/dist/flags.test.d.ts +1 -0
- package/dist/flags.test.js +73 -0
- package/dist/helpers.d.ts +6 -0
- package/dist/helpers.js +29 -0
- package/dist/index.js +97 -107
- package/dist/output.d.ts +10 -1
- package/dist/output.js +4 -6
- package/dist/skills/my-email-api/README.md +45 -0
- package/dist/skills/my-email-api/SKILL.md +106 -0
- package/dist/skills/my-email-api/claude/.claude-plugin/plugin.json +6 -0
- package/dist/skills/my-email-api/make/.gitkeep +0 -0
- package/dist/skills/my-email-api/n8n/.gitkeep +0 -0
- package/dist/skills/my-email-api/openapi/.gitkeep +0 -0
- package/dist/skills/my-webhook-api/README.md +40 -0
- package/dist/skills/my-webhook-api/SKILL.md +65 -0
- package/dist/skills/my-webhook-api/claude/.claude-plugin/plugin.json +6 -0
- package/dist/skills/my-webhook-api/make/.gitkeep +0 -0
- package/dist/skills/my-webhook-api/n8n/.gitkeep +0 -0
- package/dist/skills/my-webhook-api/openapi/.gitkeep +0 -0
- package/dist/skills/my-workflow-api/README.md +37 -0
- package/dist/skills/my-workflow-api/SKILL.md +98 -0
- package/dist/skills/my-workflow-api/claude/.claude-plugin/plugin.json +6 -0
- package/dist/skills/my-workflow-api/make/.gitkeep +0 -0
- package/dist/skills/my-workflow-api/n8n/.gitkeep +0 -0
- package/dist/skills/my-workflow-api/openapi/.gitkeep +0 -0
- package/dist/utils.d.ts +0 -4
- package/dist/utils.js +0 -33
- package/dist/utils.test.d.ts +1 -0
- package/dist/utils.test.js +48 -0
- package/package.json +9 -4
- package/dist/commands/account.d.ts +0 -4
- package/dist/commands/account.js +0 -80
package/dist/commands/email.js
CHANGED
|
@@ -2,114 +2,258 @@ import { email as sdkEmail } from '@myapihq/sdk';
|
|
|
2
2
|
import { requireConfig } from '../config.js';
|
|
3
3
|
import { success, error, printTable, printJson, info } from '../output.js';
|
|
4
4
|
import { sleep } from '../utils.js';
|
|
5
|
-
|
|
5
|
+
import { requireOrg } from '../helpers.js';
|
|
6
|
+
export const SCHEMA = {
|
|
7
|
+
org: 'string',
|
|
8
|
+
domain: 'string',
|
|
9
|
+
username: 'string',
|
|
10
|
+
'display-name': 'string',
|
|
11
|
+
filter: 'string',
|
|
12
|
+
address: 'string',
|
|
13
|
+
from: 'string',
|
|
14
|
+
to: 'string',
|
|
15
|
+
subject: 'string',
|
|
16
|
+
body: 'string',
|
|
17
|
+
html: 'string',
|
|
18
|
+
'template-id': 'string',
|
|
19
|
+
'template-vars': 'string',
|
|
20
|
+
limit: 'number',
|
|
21
|
+
offset: 'number',
|
|
22
|
+
prompt: 'string',
|
|
23
|
+
name: 'string',
|
|
24
|
+
emails: 'string',
|
|
25
|
+
'per-day': 'number',
|
|
26
|
+
};
|
|
27
|
+
// ─── Mailbox ─────────────────────────────────────────────────────────────────
|
|
28
|
+
async function mailboxCreate(flags) {
|
|
6
29
|
const config = requireConfig();
|
|
7
|
-
const orgId = flags.org || config.default_org;
|
|
8
30
|
const domain = flags.domain || config.default_domain;
|
|
9
|
-
|
|
10
|
-
|
|
31
|
+
const username = flags.username;
|
|
32
|
+
if (!domain || !username) {
|
|
33
|
+
error('Missing required arguments.\nUsage: myapi email mailbox create --domain <domain> --username <user> [--display-name <name>]\n(Or set default: myapi config set-domain <domain>)');
|
|
11
34
|
}
|
|
12
|
-
const
|
|
13
|
-
|
|
35
|
+
const res = await sdkEmail.createMailbox(config.api_key, domain, username, flags['display-name']);
|
|
36
|
+
// Backend response sometimes omits address; we know it from the inputs.
|
|
37
|
+
success(`Mailbox created: ${res.address || `${username}@${domain}`}`);
|
|
14
38
|
}
|
|
15
|
-
|
|
39
|
+
async function mailboxList(flags) {
|
|
16
40
|
const config = requireConfig();
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
error("Must provide either --domain <domain> or --filter unassigned");
|
|
22
|
-
const mailboxes = await sdkEmail.listMailboxes(config.api_key, orgId, {
|
|
41
|
+
if (!flags.domain && flags.filter !== 'unassigned') {
|
|
42
|
+
error('Must provide either --domain <domain> or --filter unassigned');
|
|
43
|
+
}
|
|
44
|
+
const mailboxes = await sdkEmail.listMailboxes(config.api_key, {
|
|
23
45
|
domain: flags.domain,
|
|
24
|
-
filter: flags.filter === 'unassigned' ? 'unassigned' : undefined
|
|
46
|
+
filter: flags.filter === 'unassigned' ? 'unassigned' : undefined,
|
|
47
|
+
});
|
|
48
|
+
printTable(mailboxes, {
|
|
49
|
+
flags,
|
|
50
|
+
empty: 'No mailboxes found.',
|
|
25
51
|
});
|
|
26
|
-
printTable(mailboxes);
|
|
27
52
|
}
|
|
28
|
-
|
|
53
|
+
async function mailboxActivateSending(flags) {
|
|
29
54
|
const config = requireConfig();
|
|
30
|
-
const
|
|
31
|
-
if (!
|
|
32
|
-
error(
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
55
|
+
const address = flags.address;
|
|
56
|
+
if (!address)
|
|
57
|
+
error('Missing required arguments.\nUsage: myapi email mailbox activate-sending --address <email>');
|
|
58
|
+
const res = await sdkEmail.activateSending(config.api_key, address);
|
|
59
|
+
success(`Sending activated: ${address} (status: ${res.status})`);
|
|
60
|
+
}
|
|
61
|
+
const MAILBOX_USAGE = {
|
|
62
|
+
'create': 'myapi email mailbox create --domain <domain> --username <user> [--display-name <name>]',
|
|
63
|
+
'list': 'myapi email mailbox list (--domain <domain> | --filter unassigned)',
|
|
64
|
+
'activate-sending': 'myapi email mailbox activate-sending --address <email>',
|
|
65
|
+
};
|
|
66
|
+
async function mailboxRun(sub, flags) {
|
|
67
|
+
if (!sub || (flags.help && !sub)) {
|
|
68
|
+
info(`Usage: myapi email mailbox <subcommand>
|
|
69
|
+
|
|
70
|
+
Subcommands:
|
|
71
|
+
create Create a mailbox on a domain
|
|
72
|
+
list List mailboxes (--domain or --filter unassigned)
|
|
73
|
+
activate-sending Activate outbound sending for a mailbox`);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
if (flags.help) {
|
|
77
|
+
const usage = MAILBOX_USAGE[sub];
|
|
78
|
+
if (usage)
|
|
79
|
+
info(`Usage: ${usage}`);
|
|
80
|
+
else
|
|
81
|
+
info(`Unknown subcommand: ${sub}. Run "myapi email mailbox --help" for the list.`);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
switch (sub) {
|
|
85
|
+
case 'create': return mailboxCreate(flags);
|
|
86
|
+
case 'list': return mailboxList(flags);
|
|
87
|
+
case 'activate-sending': return mailboxActivateSending(flags);
|
|
88
|
+
default: error(`Unknown subcommand: ${sub}. Run "myapi email mailbox --help" for the list.`);
|
|
89
|
+
}
|
|
37
90
|
}
|
|
38
|
-
|
|
91
|
+
// ─── Message ─────────────────────────────────────────────────────────────────
|
|
92
|
+
async function messageSend(flags) {
|
|
39
93
|
const config = requireConfig();
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
error("Missing required arguments.\nUsage: myapi email send --org <id> --from <email> --to <email> --subject <str> [--body <str> | --template-id <id> [--template-vars <json_str>]]");
|
|
94
|
+
if (!flags.from || !flags.to || !flags.subject) {
|
|
95
|
+
error('Missing required arguments.\nUsage: myapi email message send --from <email> --to <email> --subject <str> [--body <str> | --html <str> | --template-id <id> [--template-vars <json>]]');
|
|
43
96
|
}
|
|
44
|
-
if (!flags.body && !flags['template-id'])
|
|
45
|
-
error(
|
|
46
|
-
if (flags.body && flags['template-id'])
|
|
47
|
-
error(
|
|
97
|
+
if (!flags.body && !flags.html && !flags['template-id'])
|
|
98
|
+
error('Must provide one of --body, --html, or --template-id');
|
|
99
|
+
if ((flags.body || flags.html) && flags['template-id'])
|
|
100
|
+
error('Cannot combine --body/--html with --template-id');
|
|
48
101
|
let templateVars;
|
|
49
102
|
if (flags['template-vars']) {
|
|
50
103
|
try {
|
|
51
104
|
templateVars = JSON.parse(flags['template-vars']);
|
|
52
105
|
}
|
|
53
|
-
catch
|
|
54
|
-
error(
|
|
106
|
+
catch {
|
|
107
|
+
error('--template-vars must be valid JSON');
|
|
55
108
|
}
|
|
56
109
|
}
|
|
57
|
-
const res = await sdkEmail.sendEmail(config.api_key,
|
|
110
|
+
const res = await sdkEmail.sendEmail(config.api_key, {
|
|
58
111
|
from: flags.from,
|
|
59
112
|
to: [flags.to],
|
|
60
113
|
subject: flags.subject,
|
|
61
114
|
text: flags.body,
|
|
115
|
+
html: flags.html,
|
|
62
116
|
template_id: flags['template-id'],
|
|
63
|
-
template_vars: templateVars
|
|
117
|
+
template_vars: templateVars,
|
|
64
118
|
});
|
|
65
119
|
success(`Email sent! Message ID: ${res.message_id}`);
|
|
66
120
|
}
|
|
67
|
-
|
|
121
|
+
async function messageStatus(messageId, _flags) {
|
|
68
122
|
const config = requireConfig();
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
printTable(messages);
|
|
123
|
+
if (!messageId)
|
|
124
|
+
error('Missing required arguments.\nUsage: myapi email message status <message_id>');
|
|
125
|
+
const res = await sdkEmail.getEmailStatus(config.api_key, messageId);
|
|
126
|
+
printJson(res);
|
|
74
127
|
}
|
|
75
|
-
|
|
128
|
+
async function messageSent(flags) {
|
|
76
129
|
const config = requireConfig();
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
130
|
+
const limit = flags.limit || 50;
|
|
131
|
+
const offset = flags.offset || 0;
|
|
132
|
+
const emails = await sdkEmail.getSentEmails(config.api_key, limit, offset);
|
|
133
|
+
printTable(emails, {
|
|
134
|
+
flags,
|
|
135
|
+
empty: 'No sent emails yet.',
|
|
136
|
+
});
|
|
82
137
|
}
|
|
83
|
-
|
|
138
|
+
async function messageInbox(address, flags) {
|
|
84
139
|
const config = requireConfig();
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
printTable(templates);
|
|
140
|
+
if (!address)
|
|
141
|
+
error('Missing required arguments.\nUsage: myapi email message inbox <address>');
|
|
142
|
+
const messages = await sdkEmail.getInbox(config.api_key, address);
|
|
143
|
+
printTable(messages, {
|
|
144
|
+
flags,
|
|
145
|
+
empty: `No messages in ${address}.`,
|
|
146
|
+
});
|
|
93
147
|
}
|
|
94
|
-
|
|
148
|
+
async function messageOutbox(address, flags) {
|
|
95
149
|
const config = requireConfig();
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
150
|
+
if (!address)
|
|
151
|
+
error('Missing required arguments.\nUsage: myapi email message outbox <address>');
|
|
152
|
+
const messages = await sdkEmail.getOutbox(config.api_key, address);
|
|
153
|
+
printTable(messages, {
|
|
154
|
+
flags,
|
|
155
|
+
empty: `No outbound messages from ${address}.`,
|
|
156
|
+
});
|
|
101
157
|
}
|
|
102
|
-
|
|
158
|
+
async function messageGet(messageId, flags) {
|
|
103
159
|
const config = requireConfig();
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
160
|
+
if (!messageId || !flags.address)
|
|
161
|
+
error('Missing required arguments.\nUsage: myapi email message get <message_id> --address <email>');
|
|
162
|
+
const res = await sdkEmail.getMessage(config.api_key, messageId, flags.address);
|
|
163
|
+
printJson(res);
|
|
164
|
+
}
|
|
165
|
+
const MESSAGE_USAGE = {
|
|
166
|
+
'send': 'myapi email message send --from <email> --to <email> --subject <str> [--body <str> | --html <str> | --template-id <id> [--template-vars <json>]]',
|
|
167
|
+
'status': 'myapi email message status <message_id>',
|
|
168
|
+
'sent': 'myapi email message sent [--limit <n>] [--offset <n>]',
|
|
169
|
+
'inbox': 'myapi email message inbox <address>',
|
|
170
|
+
'outbox': 'myapi email message outbox <address>',
|
|
171
|
+
'get': 'myapi email message get <message_id> --address <email>',
|
|
172
|
+
};
|
|
173
|
+
async function messageRun(sub, args, flags) {
|
|
174
|
+
if (!sub || (flags.help && !sub)) {
|
|
175
|
+
info(`Usage: myapi email message <subcommand>
|
|
176
|
+
|
|
177
|
+
Subcommands:
|
|
178
|
+
send Send an email (transactional or templated)
|
|
179
|
+
status <id> Get delivery status of a sent message
|
|
180
|
+
sent List sent emails
|
|
181
|
+
inbox <addr> Read inbox for a mailbox address
|
|
182
|
+
outbox <addr> Read outbox for a mailbox address
|
|
183
|
+
get <id> Get a single message (--address <email>)`);
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
if (flags.help) {
|
|
187
|
+
const usage = MESSAGE_USAGE[sub];
|
|
188
|
+
if (usage)
|
|
189
|
+
info(`Usage: ${usage}`);
|
|
190
|
+
else
|
|
191
|
+
info(`Unknown subcommand: ${sub}. Run "myapi email message --help" for the list.`);
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
switch (sub) {
|
|
195
|
+
case 'send': return messageSend(flags);
|
|
196
|
+
case 'status': return messageStatus(args[0], flags);
|
|
197
|
+
case 'sent': return messageSent(flags);
|
|
198
|
+
case 'inbox': return messageInbox(args[0], flags);
|
|
199
|
+
case 'outbox': return messageOutbox(args[0], flags);
|
|
200
|
+
case 'get': return messageGet(args[0], flags);
|
|
201
|
+
default: error(`Unknown subcommand: ${sub}. Run "myapi email message --help" for the list.`);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
// ─── Warmup ──────────────────────────────────────────────────────────────────
|
|
205
|
+
async function warmupRun(sub, args, flags) {
|
|
206
|
+
if (!sub || (flags.help && !sub)) {
|
|
207
|
+
info('Usage: myapi email warmup <start|pause|resume|stop|stats> --address <email>');
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
if (flags.help) {
|
|
211
|
+
info(`Usage: myapi email warmup ${sub} --address <email>`);
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
const config = requireConfig();
|
|
215
|
+
const address = flags.address || args[0];
|
|
216
|
+
if (!address)
|
|
217
|
+
error('Missing required argument: --address <email>');
|
|
218
|
+
switch (sub) {
|
|
219
|
+
case 'start': {
|
|
220
|
+
const res = await sdkEmail.startWarmup(config.api_key, address);
|
|
221
|
+
success(`Warmup started: ${address} (${res.warmup_status})`);
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
case 'pause':
|
|
225
|
+
await sdkEmail.pauseWarmup(config.api_key, address);
|
|
226
|
+
success(`Warmup paused: ${address}`);
|
|
227
|
+
return;
|
|
228
|
+
case 'resume':
|
|
229
|
+
await sdkEmail.resumeWarmup(config.api_key, address);
|
|
230
|
+
success(`Warmup resumed: ${address}`);
|
|
231
|
+
return;
|
|
232
|
+
case 'stop':
|
|
233
|
+
await sdkEmail.stopWarmup(config.api_key, address);
|
|
234
|
+
success(`Warmup stopped: ${address}`);
|
|
235
|
+
return;
|
|
236
|
+
case 'stats': {
|
|
237
|
+
const res = await sdkEmail.getWarmupStats(config.api_key, address);
|
|
238
|
+
printJson(res);
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
default:
|
|
242
|
+
error(`Unknown warmup subcommand: ${sub}. Use start|pause|resume|stop|stats`);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
// ─── Templates ───────────────────────────────────────────────────────────────
|
|
246
|
+
async function templateGenerate(flags) {
|
|
247
|
+
const config = requireConfig();
|
|
248
|
+
const orgId = requireOrg(flags, config, 'myapi email template generate --prompt <str> --name <str> [--org <id>]');
|
|
249
|
+
if (!flags.prompt || !flags.name) {
|
|
250
|
+
error('Missing required arguments.\nUsage: myapi email template generate --prompt <str> --name <str> [--org <id>]');
|
|
107
251
|
}
|
|
108
252
|
const job = await sdkEmail.generateTemplate(config.api_key, orgId, {
|
|
109
253
|
prompt: flags.prompt,
|
|
110
|
-
name: flags.name
|
|
254
|
+
name: flags.name,
|
|
111
255
|
});
|
|
112
|
-
process.stdout.write(
|
|
256
|
+
process.stdout.write('Generating template ');
|
|
113
257
|
const chars = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
114
258
|
let i = 0;
|
|
115
259
|
let elapsed = 0;
|
|
@@ -122,83 +266,301 @@ export async function generateTemplate(flags) {
|
|
|
122
266
|
}
|
|
123
267
|
if (status.status === 'failed') {
|
|
124
268
|
process.stdout.write('\r\x1b[K');
|
|
125
|
-
error(
|
|
269
|
+
error('Template generation failed');
|
|
126
270
|
}
|
|
127
271
|
process.stdout.write(`\rGenerating template ${chars[i++ % chars.length]}`);
|
|
128
272
|
await sleep(3000);
|
|
129
273
|
elapsed += 3000;
|
|
130
274
|
}
|
|
131
275
|
process.stdout.write('\r\x1b[K');
|
|
132
|
-
error(
|
|
276
|
+
error('Template generation timed out');
|
|
277
|
+
}
|
|
278
|
+
async function templateList(flags) {
|
|
279
|
+
const config = requireConfig();
|
|
280
|
+
const orgId = requireOrg(flags, config, 'myapi email template list [--org <id>]');
|
|
281
|
+
const templates = await sdkEmail.listTemplates(config.api_key, orgId);
|
|
282
|
+
if (flags.json) {
|
|
283
|
+
printJson(templates);
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
printTable(templates, {
|
|
287
|
+
flags,
|
|
288
|
+
empty: 'No templates yet. Generate one with: myapi email template generate --prompt <p> --name <n>',
|
|
289
|
+
});
|
|
133
290
|
}
|
|
134
|
-
|
|
291
|
+
async function templateEdit(id, flags) {
|
|
135
292
|
const config = requireConfig();
|
|
136
|
-
const orgId = flags
|
|
137
|
-
if (!
|
|
138
|
-
error(
|
|
293
|
+
const orgId = requireOrg(flags, config, 'myapi email template edit <id> --prompt <str> [--org <id>]');
|
|
294
|
+
if (!id || !flags.prompt)
|
|
295
|
+
error('Missing required arguments.\nUsage: myapi email template edit <id> --prompt <str> [--org <id>]');
|
|
296
|
+
const res = await sdkEmail.editTemplate(config.api_key, orgId, id, flags.prompt);
|
|
297
|
+
success(`Template ${res.template_id} edited\nPreview: ${res.preview_url}`);
|
|
298
|
+
}
|
|
299
|
+
async function templateSendTest(id, flags) {
|
|
300
|
+
const config = requireConfig();
|
|
301
|
+
const orgId = requireOrg(flags, config, 'myapi email template send-test <template_id> --to <email> [--org <id>]');
|
|
302
|
+
if (!id || !flags.to)
|
|
303
|
+
error('Missing required arguments.\nUsage: myapi email template send-test <template_id> --to <email> [--org <id>]');
|
|
304
|
+
const res = await sdkEmail.sendTestEmail(config.api_key, orgId, id, flags.to);
|
|
305
|
+
success(`Test sent! Message ID: ${res.message_id}`);
|
|
306
|
+
}
|
|
307
|
+
async function templateDelete(id, flags) {
|
|
308
|
+
const config = requireConfig();
|
|
309
|
+
const orgId = requireOrg(flags, config, 'myapi email template delete <id> [--org <id>]');
|
|
310
|
+
if (!id)
|
|
311
|
+
error('Missing required arguments.\nUsage: myapi email template delete <id> [--org <id>]');
|
|
312
|
+
await sdkEmail.deleteTemplate(config.api_key, orgId, id);
|
|
313
|
+
success(`Deleted template ${id}`);
|
|
314
|
+
}
|
|
315
|
+
const TEMPLATE_USAGE = {
|
|
316
|
+
'generate': 'myapi email template generate --prompt <str> --name <str> [--org <id>]',
|
|
317
|
+
'list': 'myapi email template list [--org <id>] [--json]',
|
|
318
|
+
'edit': 'myapi email template edit <id> --prompt <str> [--org <id>]',
|
|
319
|
+
'send-test': 'myapi email template send-test <template_id> --to <email> [--org <id>]',
|
|
320
|
+
'delete': 'myapi email template delete <id> [--org <id>]',
|
|
321
|
+
};
|
|
322
|
+
async function templateRun(sub, args, flags) {
|
|
323
|
+
if (!sub || (flags.help && !sub)) {
|
|
324
|
+
info(`Usage: myapi email template <subcommand>
|
|
325
|
+
|
|
326
|
+
Subcommands:
|
|
327
|
+
generate Generate AI template (--prompt --name)
|
|
328
|
+
list List templates
|
|
329
|
+
edit <id> Edit a template via prompt
|
|
330
|
+
send-test <id> Send a test email for a template (--to)
|
|
331
|
+
delete <id> Delete a template
|
|
332
|
+
|
|
333
|
+
All commands accept --org <id> (or set default: myapi config set-org <id>).`);
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
if (flags.help) {
|
|
337
|
+
const usage = TEMPLATE_USAGE[sub];
|
|
338
|
+
if (usage)
|
|
339
|
+
info(`Usage: ${usage}`);
|
|
340
|
+
else
|
|
341
|
+
info(`Unknown subcommand: ${sub}. Run "myapi email template --help" for the list.`);
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
switch (sub) {
|
|
345
|
+
case 'generate': return templateGenerate(flags);
|
|
346
|
+
case 'list': return templateList(flags);
|
|
347
|
+
case 'edit': return templateEdit(args[0], flags);
|
|
348
|
+
case 'send-test': return templateSendTest(args[0], flags);
|
|
349
|
+
case 'delete': return templateDelete(args[0], flags);
|
|
350
|
+
default: error(`Unknown subcommand: ${sub}. Run "myapi email template --help" for the list.`);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
// ─── Campaigns ───────────────────────────────────────────────────────────────
|
|
354
|
+
async function campaignCreate(flags) {
|
|
355
|
+
const config = requireConfig();
|
|
356
|
+
const orgId = requireOrg(flags, config, 'myapi email campaign create --name <str> --template-id <id> --from <email> [--per-day <n>] [--org <id>]');
|
|
357
|
+
if (!flags.name || !flags['template-id'] || !flags.from) {
|
|
358
|
+
error('Missing required arguments.\nUsage: myapi email campaign create --name <str> --template-id <id> --from <email> [--per-day <n>] [--org <id>]');
|
|
359
|
+
}
|
|
360
|
+
const perDayLimit = flags['per-day'];
|
|
361
|
+
const res = await sdkEmail.createCampaign(config.api_key, orgId, {
|
|
362
|
+
name: flags.name,
|
|
363
|
+
template_id: flags['template-id'],
|
|
364
|
+
from_address: flags.from,
|
|
365
|
+
per_day_limit: perDayLimit,
|
|
366
|
+
});
|
|
367
|
+
success(`Campaign created! ID: ${res.id}`);
|
|
368
|
+
}
|
|
369
|
+
async function campaignList(flags) {
|
|
370
|
+
const config = requireConfig();
|
|
371
|
+
const orgId = requireOrg(flags, config, 'myapi email campaign list [--org <id>]');
|
|
139
372
|
const campaigns = await sdkEmail.listCampaigns(config.api_key, orgId);
|
|
140
|
-
printTable(campaigns
|
|
373
|
+
printTable(campaigns, {
|
|
374
|
+
flags,
|
|
375
|
+
empty: 'No campaigns yet. Create one with: myapi email campaign create',
|
|
376
|
+
});
|
|
141
377
|
}
|
|
142
|
-
|
|
378
|
+
async function campaignGet(id, flags) {
|
|
143
379
|
const config = requireConfig();
|
|
144
|
-
const orgId = flags
|
|
145
|
-
if (!
|
|
146
|
-
error(
|
|
380
|
+
const orgId = requireOrg(flags, config, 'myapi email campaign get <id> [--org <id>]');
|
|
381
|
+
if (!id)
|
|
382
|
+
error('Missing required arguments.\nUsage: myapi email campaign get <id> [--org <id>]');
|
|
383
|
+
const c = await sdkEmail.getCampaign(config.api_key, orgId, id);
|
|
384
|
+
printJson(c);
|
|
385
|
+
}
|
|
386
|
+
async function campaignUpdate(id, flags) {
|
|
387
|
+
const config = requireConfig();
|
|
388
|
+
const orgId = requireOrg(flags, config, 'myapi email campaign update <id> [--name <str>] [--per-day <n>] [--org <id>]');
|
|
389
|
+
if (!id)
|
|
390
|
+
error('Missing required arguments.\nUsage: myapi email campaign update <id> [--name <str>] [--per-day <n>] [--org <id>]');
|
|
391
|
+
const payload = {};
|
|
392
|
+
if (flags.name)
|
|
393
|
+
payload.name = flags.name;
|
|
394
|
+
if (flags['per-day'])
|
|
395
|
+
payload.per_day_limit = flags['per-day'];
|
|
396
|
+
if (!payload.name && payload.per_day_limit === undefined) {
|
|
397
|
+
error('Nothing to update. Pass at least one of --name, --per-day.');
|
|
398
|
+
}
|
|
399
|
+
const res = await sdkEmail.updateCampaign(config.api_key, orgId, id, payload);
|
|
400
|
+
success(`Campaign ${res.id} updated`);
|
|
401
|
+
}
|
|
402
|
+
async function campaignUploadContacts(id, flags) {
|
|
403
|
+
const config = requireConfig();
|
|
404
|
+
const orgId = requireOrg(flags, config, 'myapi email campaign upload-contacts <campaign_id> --emails <a@x,b@y> [--org <id>]');
|
|
405
|
+
if (!id || !flags.emails) {
|
|
406
|
+
error('Missing required arguments.\nUsage: myapi email campaign upload-contacts <campaign_id> --emails <a@x,b@y> [--org <id>]');
|
|
407
|
+
}
|
|
408
|
+
const emails = flags.emails.split(',').map(s => s.trim()).filter(Boolean);
|
|
409
|
+
const res = await sdkEmail.uploadContactList(config.api_key, orgId, id, emails);
|
|
410
|
+
success(`Uploaded ${res.total} contacts (status: ${res.status})`);
|
|
411
|
+
}
|
|
412
|
+
async function campaignStart(id, flags) {
|
|
413
|
+
const config = requireConfig();
|
|
414
|
+
const orgId = requireOrg(flags, config, 'myapi email campaign start <id> [--org <id>]');
|
|
415
|
+
if (!id)
|
|
416
|
+
error('Missing required arguments.\nUsage: myapi email campaign start <id> [--org <id>]');
|
|
417
|
+
const status = await sdkEmail.getContactUploadStatus(config.api_key, orgId, id);
|
|
418
|
+
if (status.upload_status !== 'ready') {
|
|
419
|
+
error(`Contacts not ready (current status: ${status.upload_status})`);
|
|
420
|
+
}
|
|
421
|
+
const res = await sdkEmail.startCampaign(config.api_key, orgId, id);
|
|
422
|
+
success(`Campaign started (status: ${res.status})`);
|
|
423
|
+
}
|
|
424
|
+
async function campaignPause(id, flags) {
|
|
425
|
+
const config = requireConfig();
|
|
426
|
+
const orgId = requireOrg(flags, config, 'myapi email campaign pause <id> [--org <id>]');
|
|
427
|
+
if (!id)
|
|
428
|
+
error('Missing required arguments.\nUsage: myapi email campaign pause <id> [--org <id>]');
|
|
429
|
+
await sdkEmail.pauseCampaign(config.api_key, orgId, id);
|
|
430
|
+
success(`Campaign ${id} paused`);
|
|
431
|
+
}
|
|
432
|
+
async function campaignResume(id, flags) {
|
|
433
|
+
const config = requireConfig();
|
|
434
|
+
const orgId = requireOrg(flags, config, 'myapi email campaign resume <id> [--org <id>]');
|
|
435
|
+
if (!id)
|
|
436
|
+
error('Missing required arguments.\nUsage: myapi email campaign resume <id> [--org <id>]');
|
|
437
|
+
await sdkEmail.resumeCampaign(config.api_key, orgId, id);
|
|
438
|
+
success(`Campaign ${id} resumed`);
|
|
439
|
+
}
|
|
440
|
+
async function campaignStats(id, flags) {
|
|
441
|
+
const config = requireConfig();
|
|
442
|
+
const orgId = requireOrg(flags, config, 'myapi email campaign stats <id> [--org <id>]');
|
|
443
|
+
if (!id)
|
|
444
|
+
error('Missing required arguments.\nUsage: myapi email campaign stats <id> [--org <id>]');
|
|
147
445
|
const stats = await sdkEmail.getCampaignStats(config.api_key, orgId, id);
|
|
148
446
|
printJson(stats);
|
|
149
447
|
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
448
|
+
const CAMPAIGN_USAGE = {
|
|
449
|
+
'create': 'myapi email campaign create --name <str> --template-id <id> --from <email> [--per-day <n>] [--org <id>]',
|
|
450
|
+
'list': 'myapi email campaign list [--org <id>]',
|
|
451
|
+
'get': 'myapi email campaign get <id> [--org <id>]',
|
|
452
|
+
'update': 'myapi email campaign update <id> [--name <str>] [--per-day <n>] [--org <id>]',
|
|
453
|
+
'upload-contacts': 'myapi email campaign upload-contacts <campaign_id> --emails <a@x,b@y> [--org <id>]',
|
|
454
|
+
'start': 'myapi email campaign start <id> [--org <id>]',
|
|
455
|
+
'pause': 'myapi email campaign pause <id> [--org <id>]',
|
|
456
|
+
'resume': 'myapi email campaign resume <id> [--org <id>]',
|
|
457
|
+
'stats': 'myapi email campaign stats <id> [--org <id>]',
|
|
458
|
+
};
|
|
459
|
+
async function campaignRun(sub, args, flags) {
|
|
460
|
+
if (!sub || (flags.help && !sub)) {
|
|
461
|
+
info(`Usage: myapi email campaign <subcommand>
|
|
462
|
+
|
|
463
|
+
Subcommands:
|
|
464
|
+
create Create a campaign (--name --template-id --from)
|
|
465
|
+
list List campaigns
|
|
466
|
+
get <id> Get a single campaign
|
|
467
|
+
update <id> Patch name / per-day-limit
|
|
468
|
+
upload-contacts <id> Upload contact list (--emails a@x,b@y)
|
|
469
|
+
start <id> Start a campaign
|
|
470
|
+
pause <id> Pause a campaign
|
|
471
|
+
resume <id> Resume a campaign
|
|
472
|
+
stats <id> Get campaign stats
|
|
473
|
+
|
|
474
|
+
All commands accept --org <id> (or set default: myapi config set-org <id>).`);
|
|
153
475
|
return;
|
|
154
476
|
}
|
|
155
477
|
if (flags.help) {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
info('Usage: myapi email send --org <id> --from <email> --to <email> --subject <str> [--body <str> | --template-id <id> [--template-vars <json_str>]]');
|
|
162
|
-
else if (subcommand === 'sent')
|
|
163
|
-
info('Usage: myapi email sent --org <id> [--limit <num>] [--offset <num>]');
|
|
164
|
-
else if (subcommand === 'inbox')
|
|
165
|
-
info('Usage: myapi email inbox <address> --org <id>');
|
|
166
|
-
else if (subcommand === 'outbox')
|
|
167
|
-
info('Usage: myapi email outbox <address> --org <id>');
|
|
168
|
-
else if (subcommand === 'list-templates')
|
|
169
|
-
info('Usage: myapi email list-templates --org <id>');
|
|
170
|
-
else if (subcommand === 'generate-template')
|
|
171
|
-
info('Usage: myapi email generate-template --org <id> --prompt <str> --name <str>');
|
|
172
|
-
else if (subcommand === 'delete-template')
|
|
173
|
-
info('Usage: myapi email delete-template <id> --org <id>');
|
|
174
|
-
else if (subcommand === 'list-campaigns')
|
|
175
|
-
info('Usage: myapi email list-campaigns --org <id>');
|
|
176
|
-
else if (subcommand === 'campaign-stats')
|
|
177
|
-
info('Usage: myapi email campaign-stats <campaign_id> --org <id>');
|
|
478
|
+
const usage = CAMPAIGN_USAGE[sub];
|
|
479
|
+
if (usage)
|
|
480
|
+
info(`Usage: ${usage}`);
|
|
481
|
+
else
|
|
482
|
+
info(`Unknown subcommand: ${sub}. Run "myapi email campaign --help" for the list.`);
|
|
178
483
|
return;
|
|
179
484
|
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
485
|
+
switch (sub) {
|
|
486
|
+
case 'create': return campaignCreate(flags);
|
|
487
|
+
case 'list': return campaignList(flags);
|
|
488
|
+
case 'get': return campaignGet(args[0], flags);
|
|
489
|
+
case 'update': return campaignUpdate(args[0], flags);
|
|
490
|
+
case 'upload-contacts': return campaignUploadContacts(args[0], flags);
|
|
491
|
+
case 'start': return campaignStart(args[0], flags);
|
|
492
|
+
case 'pause': return campaignPause(args[0], flags);
|
|
493
|
+
case 'resume': return campaignResume(args[0], flags);
|
|
494
|
+
case 'stats': return campaignStats(args[0], flags);
|
|
495
|
+
default: error(`Unknown subcommand: ${sub}. Run "myapi email campaign --help" for the list.`);
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
// ─── Deprecated flat aliases ─────────────────────────────────────────────────
|
|
499
|
+
// Old subcommand → new namespace + sub. Kept so existing scripts/skills don't
|
|
500
|
+
// break. Emits a one-line stderr deprecation note then runs the new path.
|
|
501
|
+
const DEPRECATED_ALIASES = {
|
|
502
|
+
'create-mailbox': ['mailbox', 'create'],
|
|
503
|
+
'list-mailboxes': ['mailbox', 'list'],
|
|
504
|
+
'activate-sending': ['mailbox', 'activate-sending'],
|
|
505
|
+
'send': ['message', 'send'],
|
|
506
|
+
'get-status': ['message', 'status'],
|
|
507
|
+
'sent': ['message', 'sent'],
|
|
508
|
+
'inbox': ['message', 'inbox'],
|
|
509
|
+
'outbox': ['message', 'outbox'],
|
|
510
|
+
'get-message': ['message', 'get'],
|
|
511
|
+
'generate-template': ['template', 'generate'],
|
|
512
|
+
'list-templates': ['template', 'list'],
|
|
513
|
+
'edit-template': ['template', 'edit'],
|
|
514
|
+
'send-test': ['template', 'send-test'],
|
|
515
|
+
'delete-template': ['template', 'delete'],
|
|
516
|
+
'create-campaign': ['campaign', 'create'],
|
|
517
|
+
'list-campaigns': ['campaign', 'list'],
|
|
518
|
+
'get-campaign': ['campaign', 'get'],
|
|
519
|
+
'update-campaign': ['campaign', 'update'],
|
|
520
|
+
'upload-contacts': ['campaign', 'upload-contacts'],
|
|
521
|
+
'start-campaign': ['campaign', 'start'],
|
|
522
|
+
'pause-campaign': ['campaign', 'pause'],
|
|
523
|
+
'resume-campaign': ['campaign', 'resume'],
|
|
524
|
+
'campaign-stats': ['campaign', 'stats'],
|
|
525
|
+
};
|
|
526
|
+
// ─── Top-level dispatcher ────────────────────────────────────────────────────
|
|
527
|
+
export async function run(subcommand, args, flags) {
|
|
528
|
+
if (!subcommand || (flags.help && !subcommand)) {
|
|
529
|
+
info(`Usage: myapi email <namespace> <subcommand>
|
|
530
|
+
|
|
531
|
+
Namespaces:
|
|
532
|
+
mailbox Mailboxes (account-scoped) — create, list, activate-sending
|
|
533
|
+
message Send & read mail (account-scoped) — send, status, sent, inbox, outbox, get
|
|
534
|
+
warmup Warmup controls (account-scoped) — start, pause, resume, stop, stats
|
|
535
|
+
template Email templates (org-scoped) — generate, list, edit, send-test, delete
|
|
536
|
+
campaign Email campaigns (org-scoped) — create, list, get, update, upload-contacts, start, pause, resume, stats
|
|
537
|
+
|
|
538
|
+
Examples:
|
|
539
|
+
myapi email mailbox create --domain example.com --username hello
|
|
540
|
+
myapi email message send --from a@x --to b@y --subject hi --body "hello"
|
|
541
|
+
myapi email template generate --prompt "Welcome email" --name welcome
|
|
542
|
+
myapi email campaign create --name "Q2 Launch" --template-id <id> --from a@x
|
|
543
|
+
|
|
544
|
+
Org-scoped commands accept --org <id> (or set default: myapi config set-org <id>).
|
|
545
|
+
Run "myapi email <namespace> --help" for namespace-specific commands.`);
|
|
546
|
+
return;
|
|
547
|
+
}
|
|
548
|
+
// Deprecated flat command? Forward to the new path with a one-line note.
|
|
549
|
+
const aliased = DEPRECATED_ALIASES[subcommand];
|
|
550
|
+
if (aliased) {
|
|
551
|
+
const [ns, sub] = aliased;
|
|
552
|
+
process.stderr.write(`› Note: "email ${subcommand}" is deprecated — use "email ${ns} ${sub}" instead.\n`);
|
|
553
|
+
return dispatchNamespace(ns, sub, args, flags);
|
|
554
|
+
}
|
|
555
|
+
return dispatchNamespace(subcommand, args[0], args.slice(1), flags);
|
|
556
|
+
}
|
|
557
|
+
async function dispatchNamespace(ns, sub, restArgs, flags) {
|
|
558
|
+
switch (ns) {
|
|
559
|
+
case 'mailbox': return mailboxRun(sub, flags);
|
|
560
|
+
case 'message': return messageRun(sub, restArgs, flags);
|
|
561
|
+
case 'warmup': return warmupRun(sub, restArgs, flags);
|
|
562
|
+
case 'template': return templateRun(sub, restArgs, flags);
|
|
563
|
+
case 'campaign': return campaignRun(sub, restArgs, flags);
|
|
564
|
+
default: error(`Unknown namespace: ${ns}. Run "myapi email --help" for the list.`);
|
|
565
|
+
}
|
|
204
566
|
}
|