@myapihq/cli 1.1.0-wip.0 → 1.1.0-wip.2
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.js +75 -33
- package/dist/commands/billing.js +3 -5
- package/dist/commands/domain.js +8 -1
- package/dist/commands/email/campaign.d.ts +2 -0
- package/dist/commands/email/campaign.js +152 -0
- package/dist/commands/email/index.d.ts +4 -0
- package/dist/commands/email/index.js +98 -0
- package/dist/commands/email/mailbox.d.ts +2 -0
- package/dist/commands/email/mailbox.js +88 -0
- package/dist/commands/email/message.d.ts +2 -0
- package/dist/commands/email/message.js +115 -0
- package/dist/commands/email/template.d.ts +2 -0
- package/dist/commands/email/template.js +106 -0
- package/dist/commands/email/warmup.d.ts +2 -0
- package/dist/commands/email/warmup.js +43 -0
- package/dist/commands/email.js +71 -51
- package/dist/commands/funnel.d.ts +1 -1
- package/dist/commands/funnel.js +31 -9
- package/dist/commands/keys.d.ts +1 -1
- package/dist/commands/keys.js +6 -9
- package/dist/commands/org.js +17 -34
- package/dist/commands/setup.js +143 -115
- package/dist/commands/update.js +5 -0
- package/dist/commands/webhook.d.ts +1 -1
- package/dist/commands/webhook.js +23 -7
- package/dist/commands/workflow.d.ts +1 -1
- package/dist/commands/workflow.js +45 -6
- package/dist/config.js +10 -5
- package/dist/helpers.js +8 -6
- package/dist/index.js +9 -3
- package/dist/output.d.ts +3 -1
- package/dist/output.js +12 -0
- package/dist/prompt.d.ts +24 -0
- package/dist/prompt.js +41 -0
- package/dist/skills/my-email-api/README.md +1 -1
- package/dist/skills/my-email-api/SKILL.md +4 -6
- package/dist/skills/my-webhook-api/README.md +1 -1
- package/dist/skills/my-webhook-api/SKILL.md +77 -4
- package/dist/skills/my-workflow-api/README.md +3 -4
- package/dist/skills/my-workflow-api/SKILL.md +79 -10
- package/dist/utils.d.ts +26 -0
- package/dist/utils.js +32 -0
- package/package.json +1 -1
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { email as sdkEmail } from '@myapihq/sdk';
|
|
2
|
+
import { requireConfig } from '../../config.js';
|
|
3
|
+
import { success, error, printTable, printJson, info } from '../../output.js';
|
|
4
|
+
async function send(flags) {
|
|
5
|
+
const config = requireConfig();
|
|
6
|
+
if (!flags.from || !flags.to || !flags.subject) {
|
|
7
|
+
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>]]');
|
|
8
|
+
}
|
|
9
|
+
if (!flags.body && !flags.html && !flags['template-id'])
|
|
10
|
+
error('Must provide one of --body, --html, or --template-id');
|
|
11
|
+
if ((flags.body || flags.html) && flags['template-id'])
|
|
12
|
+
error('Cannot combine --body/--html with --template-id');
|
|
13
|
+
let templateVars;
|
|
14
|
+
if (flags['template-vars']) {
|
|
15
|
+
try {
|
|
16
|
+
templateVars = JSON.parse(flags['template-vars']);
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
error('--template-vars must be valid JSON');
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
const res = await sdkEmail.sendEmail(config.api_key, {
|
|
23
|
+
from: flags.from,
|
|
24
|
+
to: [flags.to],
|
|
25
|
+
subject: flags.subject,
|
|
26
|
+
text: flags.body,
|
|
27
|
+
html: flags.html,
|
|
28
|
+
template_id: flags['template-id'],
|
|
29
|
+
template_vars: templateVars,
|
|
30
|
+
});
|
|
31
|
+
success(`Email sent! Message ID: ${res.message_id}`);
|
|
32
|
+
}
|
|
33
|
+
async function status(messageId, _flags) {
|
|
34
|
+
const config = requireConfig();
|
|
35
|
+
if (!messageId)
|
|
36
|
+
error('Missing required arguments.\nUsage: myapi email message status <message_id>');
|
|
37
|
+
const res = await sdkEmail.getEmailStatus(config.api_key, messageId);
|
|
38
|
+
printJson(res);
|
|
39
|
+
}
|
|
40
|
+
async function sent(flags) {
|
|
41
|
+
const config = requireConfig();
|
|
42
|
+
const limit = flags.limit || 50;
|
|
43
|
+
const offset = flags.offset || 0;
|
|
44
|
+
const emails = await sdkEmail.getSentEmails(config.api_key, limit, offset);
|
|
45
|
+
printTable(emails, {
|
|
46
|
+
flags,
|
|
47
|
+
empty: 'No sent emails yet.',
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
async function inbox(address, flags) {
|
|
51
|
+
const config = requireConfig();
|
|
52
|
+
if (!address)
|
|
53
|
+
error('Missing required arguments.\nUsage: myapi email message inbox <address>');
|
|
54
|
+
const messages = await sdkEmail.getInbox(config.api_key, address);
|
|
55
|
+
printTable(messages, {
|
|
56
|
+
flags,
|
|
57
|
+
empty: `No messages in ${address}.`,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
async function outbox(address, flags) {
|
|
61
|
+
const config = requireConfig();
|
|
62
|
+
if (!address)
|
|
63
|
+
error('Missing required arguments.\nUsage: myapi email message outbox <address>');
|
|
64
|
+
const messages = await sdkEmail.getOutbox(config.api_key, address);
|
|
65
|
+
printTable(messages, {
|
|
66
|
+
flags,
|
|
67
|
+
empty: `No outbound messages from ${address}.`,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
async function get(messageId, flags) {
|
|
71
|
+
const config = requireConfig();
|
|
72
|
+
if (!messageId || !flags.address)
|
|
73
|
+
error('Missing required arguments.\nUsage: myapi email message get <message_id> --address <email>');
|
|
74
|
+
const res = await sdkEmail.getMessage(config.api_key, messageId, flags.address);
|
|
75
|
+
printJson(res);
|
|
76
|
+
}
|
|
77
|
+
const USAGE = {
|
|
78
|
+
'send': 'myapi email message send --from <email> --to <email> --subject <str> [--body <str> | --html <str> | --template-id <id> [--template-vars <json>]]',
|
|
79
|
+
'status': 'myapi email message status <message_id>',
|
|
80
|
+
'sent': 'myapi email message sent [--limit <n>] [--offset <n>]',
|
|
81
|
+
'inbox': 'myapi email message inbox <address>',
|
|
82
|
+
'outbox': 'myapi email message outbox <address>',
|
|
83
|
+
'get': 'myapi email message get <message_id> --address <email>',
|
|
84
|
+
};
|
|
85
|
+
export async function run(sub, args, flags) {
|
|
86
|
+
if (!sub || (flags.help && !sub)) {
|
|
87
|
+
info(`Usage: myapi email message <subcommand>
|
|
88
|
+
|
|
89
|
+
Subcommands:
|
|
90
|
+
send Send an email (transactional or templated)
|
|
91
|
+
status <id> Get delivery status of a sent message
|
|
92
|
+
sent List sent emails
|
|
93
|
+
inbox <addr> Read inbox for a mailbox address
|
|
94
|
+
outbox <addr> Read outbox for a mailbox address
|
|
95
|
+
get <id> Get a single message (--address <email>)`);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
if (flags.help) {
|
|
99
|
+
const usage = USAGE[sub];
|
|
100
|
+
if (usage)
|
|
101
|
+
info(`Usage: ${usage}`);
|
|
102
|
+
else
|
|
103
|
+
info(`Unknown subcommand: ${sub}. Run "myapi email message --help" for the list.`);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
switch (sub) {
|
|
107
|
+
case 'send': return send(flags);
|
|
108
|
+
case 'status': return status(args[0], flags);
|
|
109
|
+
case 'sent': return sent(flags);
|
|
110
|
+
case 'inbox': return inbox(args[0], flags);
|
|
111
|
+
case 'outbox': return outbox(args[0], flags);
|
|
112
|
+
case 'get': return get(args[0], flags);
|
|
113
|
+
default: error(`Unknown subcommand: ${sub}. Run "myapi email message --help" for the list.`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { email as sdkEmail } from '@myapihq/sdk';
|
|
2
|
+
import { requireConfig } from '../../config.js';
|
|
3
|
+
import { success, error, printTable, printJson, info } from '../../output.js';
|
|
4
|
+
import { pollJob } from '../../utils.js';
|
|
5
|
+
import { requireOrg } from '../../helpers.js';
|
|
6
|
+
async function generate(nameArg, flags) {
|
|
7
|
+
const config = requireConfig();
|
|
8
|
+
const orgId = requireOrg(flags, config, 'myapi email template generate <name> --prompt <str> [--org <id>]');
|
|
9
|
+
const name = nameArg || flags.name;
|
|
10
|
+
if (!name || !flags.prompt) {
|
|
11
|
+
error('Missing required arguments.\nUsage: myapi email template generate <name> --prompt <str> [--org <id>]\n or: myapi email template generate --name <name> --prompt <str> [--org <id>]');
|
|
12
|
+
}
|
|
13
|
+
const job = await sdkEmail.generateTemplate(config.api_key, orgId, {
|
|
14
|
+
prompt: flags.prompt,
|
|
15
|
+
name,
|
|
16
|
+
});
|
|
17
|
+
const status = await pollJob({
|
|
18
|
+
label: 'Generating template',
|
|
19
|
+
timeoutMs: 90_000,
|
|
20
|
+
intervalMs: 3000,
|
|
21
|
+
check: () => sdkEmail.getTemplateJobStatus(config.api_key, orgId, job.job_id),
|
|
22
|
+
isDone: s => s.status === 'completed',
|
|
23
|
+
isFailed: s => s.status === 'failed',
|
|
24
|
+
failedMessage: 'Template generation failed',
|
|
25
|
+
timeoutMessage: 'Template generation timed out',
|
|
26
|
+
});
|
|
27
|
+
success(`Template generated! ID: ${status.template_id}\nPreview: ${status.result?.preview_url}`);
|
|
28
|
+
}
|
|
29
|
+
async function list(flags) {
|
|
30
|
+
const config = requireConfig();
|
|
31
|
+
const orgId = requireOrg(flags, config, 'myapi email template list [--org <id>]');
|
|
32
|
+
const templates = await sdkEmail.listTemplates(config.api_key, orgId);
|
|
33
|
+
if (flags.json) {
|
|
34
|
+
printJson(templates);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
printTable(templates, {
|
|
38
|
+
flags,
|
|
39
|
+
empty: 'No templates yet. Generate one with: myapi email template generate --prompt <p> --name <n>',
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
async function edit(id, flags) {
|
|
43
|
+
const config = requireConfig();
|
|
44
|
+
const orgId = requireOrg(flags, config, 'myapi email template edit <id> --prompt <str> [--org <id>]');
|
|
45
|
+
if (!id || !flags.prompt)
|
|
46
|
+
error('Missing required arguments.\nUsage: myapi email template edit <id> --prompt <str> [--org <id>]');
|
|
47
|
+
const res = await sdkEmail.editTemplate(config.api_key, orgId, id, flags.prompt);
|
|
48
|
+
success(`Template ${res.template_id} edited\nPreview: ${res.preview_url}`);
|
|
49
|
+
}
|
|
50
|
+
async function sendTest(id, flags) {
|
|
51
|
+
const config = requireConfig();
|
|
52
|
+
const orgId = requireOrg(flags, config, 'myapi email template send-test <template_id> --to <email> [--org <id>]');
|
|
53
|
+
if (!id || !flags.to)
|
|
54
|
+
error('Missing required arguments.\nUsage: myapi email template send-test <template_id> --to <email> [--org <id>]');
|
|
55
|
+
const res = await sdkEmail.sendTestEmail(config.api_key, orgId, id, flags.to);
|
|
56
|
+
success(`Test sent! Message ID: ${res.message_id}`);
|
|
57
|
+
}
|
|
58
|
+
async function del(id, flags) {
|
|
59
|
+
const config = requireConfig();
|
|
60
|
+
const orgId = requireOrg(flags, config, 'myapi email template delete <id> [--org <id>]');
|
|
61
|
+
if (!id)
|
|
62
|
+
error('Missing required arguments.\nUsage: myapi email template delete <id> [--org <id>]');
|
|
63
|
+
await sdkEmail.deleteTemplate(config.api_key, orgId, id);
|
|
64
|
+
success(`Deleted template ${id}`);
|
|
65
|
+
}
|
|
66
|
+
const USAGE = {
|
|
67
|
+
'generate': `myapi email template generate <name> --prompt <str> [--org <id>]
|
|
68
|
+
myapi email template generate --name <name> --prompt <str> [--org <id>]
|
|
69
|
+
|
|
70
|
+
Either form works; the positional name is the recommended shape.`,
|
|
71
|
+
'list': 'myapi email template list [--org <id>] [--json]',
|
|
72
|
+
'edit': 'myapi email template edit <id> --prompt <str> [--org <id>]',
|
|
73
|
+
'send-test': 'myapi email template send-test <template_id> --to <email> [--org <id>]',
|
|
74
|
+
'delete': 'myapi email template delete <id> [--org <id>]',
|
|
75
|
+
};
|
|
76
|
+
export async function run(sub, args, flags) {
|
|
77
|
+
if (!sub || (flags.help && !sub)) {
|
|
78
|
+
info(`Usage: myapi email template <subcommand>
|
|
79
|
+
|
|
80
|
+
Subcommands:
|
|
81
|
+
generate <name> Generate AI template (--prompt)
|
|
82
|
+
list List templates
|
|
83
|
+
edit <id> Edit a template via prompt
|
|
84
|
+
send-test <id> Send a test email for a template (--to)
|
|
85
|
+
delete <id> Delete a template
|
|
86
|
+
|
|
87
|
+
All commands accept --org <id> (or set default: myapi config set-org <id>).`);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
if (flags.help) {
|
|
91
|
+
const usage = USAGE[sub];
|
|
92
|
+
if (usage)
|
|
93
|
+
info(`Usage: ${usage}`);
|
|
94
|
+
else
|
|
95
|
+
info(`Unknown subcommand: ${sub}. Run "myapi email template --help" for the list.`);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
switch (sub) {
|
|
99
|
+
case 'generate': return generate(args[0], flags);
|
|
100
|
+
case 'list': return list(flags);
|
|
101
|
+
case 'edit': return edit(args[0], flags);
|
|
102
|
+
case 'send-test': return sendTest(args[0], flags);
|
|
103
|
+
case 'delete': return del(args[0], flags);
|
|
104
|
+
default: error(`Unknown subcommand: ${sub}. Run "myapi email template --help" for the list.`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { email as sdkEmail } from '@myapihq/sdk';
|
|
2
|
+
import { requireConfig } from '../../config.js';
|
|
3
|
+
import { success, error, printJson, info } from '../../output.js';
|
|
4
|
+
export async function run(sub, args, flags) {
|
|
5
|
+
if (!sub || (flags.help && !sub)) {
|
|
6
|
+
info('Usage: myapi email warmup <start|pause|resume|stop|stats> --address <email>');
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
if (flags.help) {
|
|
10
|
+
info(`Usage: myapi email warmup ${sub} --address <email>`);
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
const config = requireConfig();
|
|
14
|
+
const address = flags.address || args[0];
|
|
15
|
+
if (!address)
|
|
16
|
+
error('Missing required argument: --address <email>');
|
|
17
|
+
switch (sub) {
|
|
18
|
+
case 'start': {
|
|
19
|
+
const res = await sdkEmail.startWarmup(config.api_key, address);
|
|
20
|
+
success(`Warmup started: ${address} (${res.warmup_status})`);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
case 'pause':
|
|
24
|
+
await sdkEmail.pauseWarmup(config.api_key, address);
|
|
25
|
+
success(`Warmup paused: ${address}`);
|
|
26
|
+
return;
|
|
27
|
+
case 'resume':
|
|
28
|
+
await sdkEmail.resumeWarmup(config.api_key, address);
|
|
29
|
+
success(`Warmup resumed: ${address}`);
|
|
30
|
+
return;
|
|
31
|
+
case 'stop':
|
|
32
|
+
await sdkEmail.stopWarmup(config.api_key, address);
|
|
33
|
+
success(`Warmup stopped: ${address}`);
|
|
34
|
+
return;
|
|
35
|
+
case 'stats': {
|
|
36
|
+
const res = await sdkEmail.getWarmupStats(config.api_key, address);
|
|
37
|
+
printJson(res);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
default:
|
|
41
|
+
error(`Unknown warmup subcommand: ${sub}. Use start|pause|resume|stop|stats`);
|
|
42
|
+
}
|
|
43
|
+
}
|
package/dist/commands/email.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
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
|
-
import {
|
|
4
|
+
import { pollJob } from '../utils.js';
|
|
5
5
|
import { requireOrg } from '../helpers.js';
|
|
6
6
|
export const SCHEMA = {
|
|
7
7
|
org: 'string',
|
|
@@ -25,12 +25,25 @@ export const SCHEMA = {
|
|
|
25
25
|
'per-day': 'number',
|
|
26
26
|
};
|
|
27
27
|
// ─── Mailbox ─────────────────────────────────────────────────────────────────
|
|
28
|
-
async function mailboxCreate(flags) {
|
|
28
|
+
async function mailboxCreate(addressArg, flags) {
|
|
29
29
|
const config = requireConfig();
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
// Convention: first required arg is positional. For mailboxes that's the
|
|
31
|
+
// full address `user@domain`. The flag form (--username + --domain) is
|
|
32
|
+
// still accepted for back-compat / scripts that built up parts separately.
|
|
33
|
+
let username = flags.username;
|
|
34
|
+
let domain = flags.domain || config.default_domain;
|
|
35
|
+
if (addressArg) {
|
|
36
|
+
const at = addressArg.indexOf('@');
|
|
37
|
+
if (at > 0 && at < addressArg.length - 1) {
|
|
38
|
+
username = addressArg.slice(0, at);
|
|
39
|
+
domain = addressArg.slice(at + 1);
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
error(`"${addressArg}" is not a valid email address. Expected format: user@domain.com`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (!username || !domain) {
|
|
46
|
+
error('Missing required arguments.\nUsage: myapi email mailbox create <user@domain> [--display-name <name>]\n or: myapi email mailbox create --username <u> --domain <d> [--display-name <name>]\n(Or set default: myapi config set-domain <domain>)');
|
|
34
47
|
}
|
|
35
48
|
const res = await sdkEmail.createMailbox(config.api_key, domain, username, flags['display-name']);
|
|
36
49
|
// Backend response sometimes omits address; we know it from the inputs.
|
|
@@ -39,7 +52,7 @@ async function mailboxCreate(flags) {
|
|
|
39
52
|
async function mailboxList(flags) {
|
|
40
53
|
const config = requireConfig();
|
|
41
54
|
if (!flags.domain && flags.filter !== 'unassigned') {
|
|
42
|
-
error('Must provide either --domain <domain> or --filter unassigned');
|
|
55
|
+
error('Must provide either --domain <domain> (mailboxes on that domain) or --filter unassigned (mailboxes whose domain is not assigned to any org).');
|
|
43
56
|
}
|
|
44
57
|
const mailboxes = await sdkEmail.listMailboxes(config.api_key, {
|
|
45
58
|
domain: flags.domain,
|
|
@@ -59,17 +72,26 @@ async function mailboxActivateSending(flags) {
|
|
|
59
72
|
success(`Sending activated: ${address} (status: ${res.status})`);
|
|
60
73
|
}
|
|
61
74
|
const MAILBOX_USAGE = {
|
|
62
|
-
'create':
|
|
63
|
-
|
|
75
|
+
'create': `myapi email mailbox create <user@domain> [--display-name <name>]
|
|
76
|
+
myapi email mailbox create --username <u> --domain <d> [--display-name <name>]
|
|
77
|
+
|
|
78
|
+
Either form works. The positional address is the recommended shape and
|
|
79
|
+
matches the rest of the CLI ("first required arg is positional").`,
|
|
80
|
+
'list': `myapi email mailbox list (--domain <domain> | --filter unassigned)
|
|
81
|
+
|
|
82
|
+
--domain <domain> List mailboxes on the given domain.
|
|
83
|
+
--filter unassigned List mailboxes whose domain is NOT assigned to any
|
|
84
|
+
org (orphaned mailboxes — domain was unassigned
|
|
85
|
+
without first deleting them).`,
|
|
64
86
|
'activate-sending': 'myapi email mailbox activate-sending --address <email>',
|
|
65
87
|
};
|
|
66
|
-
async function mailboxRun(sub, flags) {
|
|
88
|
+
async function mailboxRun(sub, args, flags) {
|
|
67
89
|
if (!sub || (flags.help && !sub)) {
|
|
68
90
|
info(`Usage: myapi email mailbox <subcommand>
|
|
69
91
|
|
|
70
92
|
Subcommands:
|
|
71
|
-
create Create a mailbox
|
|
72
|
-
list List mailboxes (--domain or --filter unassigned)
|
|
93
|
+
create Create a mailbox (positional <user@domain> or --username/--domain)
|
|
94
|
+
list List mailboxes on a domain (--domain) or orphaned ones (--filter unassigned)
|
|
73
95
|
activate-sending Activate outbound sending for a mailbox`);
|
|
74
96
|
return;
|
|
75
97
|
}
|
|
@@ -82,7 +104,7 @@ Subcommands:
|
|
|
82
104
|
return;
|
|
83
105
|
}
|
|
84
106
|
switch (sub) {
|
|
85
|
-
case 'create': return mailboxCreate(flags);
|
|
107
|
+
case 'create': return mailboxCreate(args[0], flags);
|
|
86
108
|
case 'list': return mailboxList(flags);
|
|
87
109
|
case 'activate-sending': return mailboxActivateSending(flags);
|
|
88
110
|
default: error(`Unknown subcommand: ${sub}. Run "myapi email mailbox --help" for the list.`);
|
|
@@ -243,37 +265,28 @@ async function warmupRun(sub, args, flags) {
|
|
|
243
265
|
}
|
|
244
266
|
}
|
|
245
267
|
// ─── Templates ───────────────────────────────────────────────────────────────
|
|
246
|
-
async function templateGenerate(flags) {
|
|
268
|
+
async function templateGenerate(nameArg, flags) {
|
|
247
269
|
const config = requireConfig();
|
|
248
|
-
const orgId = requireOrg(flags, config, 'myapi email template generate
|
|
249
|
-
|
|
250
|
-
|
|
270
|
+
const orgId = requireOrg(flags, config, 'myapi email template generate <name> --prompt <str> [--org <id>]');
|
|
271
|
+
const name = nameArg || flags.name;
|
|
272
|
+
if (!name || !flags.prompt) {
|
|
273
|
+
error('Missing required arguments.\nUsage: myapi email template generate <name> --prompt <str> [--org <id>]\n or: myapi email template generate --name <name> --prompt <str> [--org <id>]');
|
|
251
274
|
}
|
|
252
275
|
const job = await sdkEmail.generateTemplate(config.api_key, orgId, {
|
|
253
276
|
prompt: flags.prompt,
|
|
254
|
-
name
|
|
277
|
+
name,
|
|
255
278
|
});
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
if (status.status === 'failed') {
|
|
268
|
-
process.stdout.write('\r\x1b[K');
|
|
269
|
-
error('Template generation failed');
|
|
270
|
-
}
|
|
271
|
-
process.stdout.write(`\rGenerating template ${chars[i++ % chars.length]}`);
|
|
272
|
-
await sleep(3000);
|
|
273
|
-
elapsed += 3000;
|
|
274
|
-
}
|
|
275
|
-
process.stdout.write('\r\x1b[K');
|
|
276
|
-
error('Template generation timed out');
|
|
279
|
+
const status = await pollJob({
|
|
280
|
+
label: 'Generating template',
|
|
281
|
+
timeoutMs: 90_000,
|
|
282
|
+
intervalMs: 3000,
|
|
283
|
+
check: () => sdkEmail.getTemplateJobStatus(config.api_key, orgId, job.job_id),
|
|
284
|
+
isDone: s => s.status === 'completed',
|
|
285
|
+
isFailed: s => s.status === 'failed',
|
|
286
|
+
failedMessage: 'Template generation failed',
|
|
287
|
+
timeoutMessage: 'Template generation timed out',
|
|
288
|
+
});
|
|
289
|
+
success(`Template generated! ID: ${status.template_id}\nPreview: ${status.result?.preview_url}`);
|
|
277
290
|
}
|
|
278
291
|
async function templateList(flags) {
|
|
279
292
|
const config = requireConfig();
|
|
@@ -313,7 +326,10 @@ async function templateDelete(id, flags) {
|
|
|
313
326
|
success(`Deleted template ${id}`);
|
|
314
327
|
}
|
|
315
328
|
const TEMPLATE_USAGE = {
|
|
316
|
-
'generate':
|
|
329
|
+
'generate': `myapi email template generate <name> --prompt <str> [--org <id>]
|
|
330
|
+
myapi email template generate --name <name> --prompt <str> [--org <id>]
|
|
331
|
+
|
|
332
|
+
Either form works; the positional name is the recommended shape.`,
|
|
317
333
|
'list': 'myapi email template list [--org <id>] [--json]',
|
|
318
334
|
'edit': 'myapi email template edit <id> --prompt <str> [--org <id>]',
|
|
319
335
|
'send-test': 'myapi email template send-test <template_id> --to <email> [--org <id>]',
|
|
@@ -324,7 +340,7 @@ async function templateRun(sub, args, flags) {
|
|
|
324
340
|
info(`Usage: myapi email template <subcommand>
|
|
325
341
|
|
|
326
342
|
Subcommands:
|
|
327
|
-
generate
|
|
343
|
+
generate <name> Generate AI template (--prompt)
|
|
328
344
|
list List templates
|
|
329
345
|
edit <id> Edit a template via prompt
|
|
330
346
|
send-test <id> Send a test email for a template (--to)
|
|
@@ -342,7 +358,7 @@ All commands accept --org <id> (or set default: myapi config set-org <id>).`);
|
|
|
342
358
|
return;
|
|
343
359
|
}
|
|
344
360
|
switch (sub) {
|
|
345
|
-
case 'generate': return templateGenerate(flags);
|
|
361
|
+
case 'generate': return templateGenerate(args[0], flags);
|
|
346
362
|
case 'list': return templateList(flags);
|
|
347
363
|
case 'edit': return templateEdit(args[0], flags);
|
|
348
364
|
case 'send-test': return templateSendTest(args[0], flags);
|
|
@@ -351,15 +367,16 @@ All commands accept --org <id> (or set default: myapi config set-org <id>).`);
|
|
|
351
367
|
}
|
|
352
368
|
}
|
|
353
369
|
// ─── Campaigns ───────────────────────────────────────────────────────────────
|
|
354
|
-
async function campaignCreate(flags) {
|
|
370
|
+
async function campaignCreate(nameArg, flags) {
|
|
355
371
|
const config = requireConfig();
|
|
356
|
-
const orgId = requireOrg(flags, config, 'myapi email campaign create
|
|
357
|
-
|
|
358
|
-
|
|
372
|
+
const orgId = requireOrg(flags, config, 'myapi email campaign create <name> --template-id <id> --from <email> [--per-day <n>] [--org <id>]');
|
|
373
|
+
const name = nameArg || flags.name;
|
|
374
|
+
if (!name || !flags['template-id'] || !flags.from) {
|
|
375
|
+
error('Missing required arguments.\nUsage: myapi email campaign create <name> --template-id <id> --from <email> [--per-day <n>] [--org <id>]\n or: myapi email campaign create --name <name> --template-id <id> --from <email> [--per-day <n>] [--org <id>]');
|
|
359
376
|
}
|
|
360
377
|
const perDayLimit = flags['per-day'];
|
|
361
378
|
const res = await sdkEmail.createCampaign(config.api_key, orgId, {
|
|
362
|
-
name
|
|
379
|
+
name,
|
|
363
380
|
template_id: flags['template-id'],
|
|
364
381
|
from_address: flags.from,
|
|
365
382
|
per_day_limit: perDayLimit,
|
|
@@ -446,7 +463,10 @@ async function campaignStats(id, flags) {
|
|
|
446
463
|
printJson(stats);
|
|
447
464
|
}
|
|
448
465
|
const CAMPAIGN_USAGE = {
|
|
449
|
-
'create':
|
|
466
|
+
'create': `myapi email campaign create <name> --template-id <id> --from <email> [--per-day <n>] [--org <id>]
|
|
467
|
+
myapi email campaign create --name <name> --template-id <id> --from <email> [--per-day <n>] [--org <id>]
|
|
468
|
+
|
|
469
|
+
Either form works; the positional name is the recommended shape.`,
|
|
450
470
|
'list': 'myapi email campaign list [--org <id>]',
|
|
451
471
|
'get': 'myapi email campaign get <id> [--org <id>]',
|
|
452
472
|
'update': 'myapi email campaign update <id> [--name <str>] [--per-day <n>] [--org <id>]',
|
|
@@ -461,7 +481,7 @@ async function campaignRun(sub, args, flags) {
|
|
|
461
481
|
info(`Usage: myapi email campaign <subcommand>
|
|
462
482
|
|
|
463
483
|
Subcommands:
|
|
464
|
-
create
|
|
484
|
+
create <name> Create a campaign (--template-id --from)
|
|
465
485
|
list List campaigns
|
|
466
486
|
get <id> Get a single campaign
|
|
467
487
|
update <id> Patch name / per-day-limit
|
|
@@ -483,7 +503,7 @@ All commands accept --org <id> (or set default: myapi config set-org <id>).`);
|
|
|
483
503
|
return;
|
|
484
504
|
}
|
|
485
505
|
switch (sub) {
|
|
486
|
-
case 'create': return campaignCreate(flags);
|
|
506
|
+
case 'create': return campaignCreate(args[0], flags);
|
|
487
507
|
case 'list': return campaignList(flags);
|
|
488
508
|
case 'get': return campaignGet(args[0], flags);
|
|
489
509
|
case 'update': return campaignUpdate(args[0], flags);
|
|
@@ -556,7 +576,7 @@ Run "myapi email <namespace> --help" for namespace-specific commands.`);
|
|
|
556
576
|
}
|
|
557
577
|
async function dispatchNamespace(ns, sub, restArgs, flags) {
|
|
558
578
|
switch (ns) {
|
|
559
|
-
case 'mailbox': return mailboxRun(sub, flags);
|
|
579
|
+
case 'mailbox': return mailboxRun(sub, restArgs, flags);
|
|
560
580
|
case 'message': return messageRun(sub, restArgs, flags);
|
|
561
581
|
case 'warmup': return warmupRun(sub, restArgs, flags);
|
|
562
582
|
case 'template': return templateRun(sub, restArgs, flags);
|
|
@@ -6,5 +6,5 @@ export declare function create(flags: Flags): Promise<void>;
|
|
|
6
6
|
export declare function get(id: string, flags: Flags): Promise<void>;
|
|
7
7
|
export declare function del(id: string, flags: Flags): Promise<void>;
|
|
8
8
|
export declare function push(slug: string, flags: Flags): Promise<void>;
|
|
9
|
-
export declare function verify(
|
|
9
|
+
export declare function verify(slug: string, flags: Flags): Promise<void>;
|
|
10
10
|
export declare function run(subcommand: string | undefined, args: string[], flags: Flags): Promise<void>;
|
package/dist/commands/funnel.js
CHANGED
|
@@ -43,6 +43,10 @@ export async function get(id, flags) {
|
|
|
43
43
|
if (!id)
|
|
44
44
|
error('Missing required arguments.\nUsage: myapi funnel get <id> [--org <id>]');
|
|
45
45
|
const raw = await sdkFunnel.getFunnel(config.api_key, orgId, id);
|
|
46
|
+
// Backend response shape varies between two layouts:
|
|
47
|
+
// 1) { funnel: {...}, subdomain_url, domain_url } (newer, wrapped)
|
|
48
|
+
// 2) { id, ..., subdomain_url, domain_url } (older, flat)
|
|
49
|
+
// Coalesce both so this works regardless of which shape we get back.
|
|
46
50
|
const funnel = raw.funnel ?? raw;
|
|
47
51
|
const subdomain_url = raw.subdomain_url ?? funnel.subdomain_url;
|
|
48
52
|
const domain_url = raw.domain_url ?? funnel.domain_url;
|
|
@@ -114,15 +118,24 @@ export async function push(slug, flags) {
|
|
|
114
118
|
}
|
|
115
119
|
}
|
|
116
120
|
}
|
|
117
|
-
|
|
121
|
+
// Verify uses the same shape as push: slug positional (default '/'), funnel
|
|
122
|
+
// resolved from --funnel / default / the org's only funnel.
|
|
123
|
+
export async function verify(slug, flags) {
|
|
118
124
|
const config = requireConfig();
|
|
119
|
-
const orgId = requireOrg(flags, config, 'myapi funnel verify
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
if (
|
|
124
|
-
|
|
125
|
-
|
|
125
|
+
const orgId = requireOrg(flags, config, 'myapi funnel verify [slug] [--funnel <id>] [--org <id>]');
|
|
126
|
+
const rawSlug = slug || flags.slug || '/';
|
|
127
|
+
const finalSlug = rawSlug.startsWith('/') ? rawSlug : `/${rawSlug}`;
|
|
128
|
+
let funnelId = flags.funnel || config.default_funnel;
|
|
129
|
+
if (!funnelId) {
|
|
130
|
+
const existing = await sdkFunnel.listFunnels(config.api_key, orgId);
|
|
131
|
+
if (existing.length === 0)
|
|
132
|
+
error('No funnel found for this org. Create one with: myapi funnel create');
|
|
133
|
+
if (existing.length > 1) {
|
|
134
|
+
error(`Multiple funnels exist for this org and no default is set.\nPick one with --funnel <id>, or set a default:\n myapi config set-funnel <id>\n\nFunnels:\n${existing.map(f => ` ${f.id}`).join('\n')}`);
|
|
135
|
+
}
|
|
136
|
+
funnelId = existing[0].id;
|
|
137
|
+
}
|
|
138
|
+
const v = await sdkFunnel.verifyFunnel(config.api_key, orgId, funnelId, { slug: finalSlug });
|
|
126
139
|
printJson(v);
|
|
127
140
|
}
|
|
128
141
|
// ── Dispatcher ───────────────────────────────────────────────────────────────
|
|
@@ -141,7 +154,16 @@ Examples:
|
|
|
141
154
|
cat about.html | myapi funnel push /about
|
|
142
155
|
myapi funnel push < index.html
|
|
143
156
|
cat p.html | myapi funnel push /pricing --funnel <uuid>`,
|
|
144
|
-
'verify':
|
|
157
|
+
'verify': `myapi funnel verify [slug] [--funnel <id>] [--org <id>]
|
|
158
|
+
|
|
159
|
+
Verifies the page at <slug> on a funnel. Slug defaults to '/'. Funnel is
|
|
160
|
+
resolved from --funnel, the default funnel, or (only if the org has exactly
|
|
161
|
+
one) auto-picked — same shape as "funnel push".
|
|
162
|
+
|
|
163
|
+
Examples:
|
|
164
|
+
myapi funnel verify # verifies '/' on the default funnel
|
|
165
|
+
myapi funnel verify /pricing
|
|
166
|
+
myapi funnel verify / --funnel <uuid>`,
|
|
145
167
|
};
|
|
146
168
|
export async function run(subcommand, args, flags) {
|
|
147
169
|
if (!subcommand || (flags.help && !subcommand)) {
|
package/dist/commands/keys.d.ts
CHANGED
|
@@ -5,4 +5,4 @@ export declare function run(subcommand: string | undefined, args: string[], flag
|
|
|
5
5
|
export declare function runApiKeys(subcommand: string | undefined, args: string[], flags: Flags): Promise<void>;
|
|
6
6
|
export declare function createNew(flags: Flags): Promise<void>;
|
|
7
7
|
export declare function list(flags: Flags): Promise<void>;
|
|
8
|
-
export declare function revoke(id: string,
|
|
8
|
+
export declare function revoke(id: string, _flags: Flags): Promise<void>;
|
package/dist/commands/keys.js
CHANGED
|
@@ -2,7 +2,8 @@ import { hq } from '@myapihq/sdk';
|
|
|
2
2
|
import { requireConfig } from '../config.js';
|
|
3
3
|
import { success, error, printTable, info, printJson } from '../output.js';
|
|
4
4
|
import { formatDate } from '../utils.js';
|
|
5
|
-
import
|
|
5
|
+
import { ask } from '../prompt.js';
|
|
6
|
+
import { requireArg } from '../helpers.js';
|
|
6
7
|
export const SCHEMA = {
|
|
7
8
|
name: 'string',
|
|
8
9
|
};
|
|
@@ -62,11 +63,8 @@ export async function runApiKeys(subcommand, args, flags) {
|
|
|
62
63
|
export async function createNew(flags) {
|
|
63
64
|
const config = requireConfig();
|
|
64
65
|
let name = flags.name || '';
|
|
65
|
-
if (!name)
|
|
66
|
-
|
|
67
|
-
name = await new Promise(resolve => rl.question('Enter a name for the new key: ', resolve));
|
|
68
|
-
rl.close();
|
|
69
|
-
}
|
|
66
|
+
if (!name)
|
|
67
|
+
name = await ask('Enter a name for the new key: ');
|
|
70
68
|
if (!name.trim())
|
|
71
69
|
error('Key name cannot be empty. Use --name <name>');
|
|
72
70
|
const keyInfo = await hq.createApiKey(config.api_key, name.trim());
|
|
@@ -91,9 +89,8 @@ export async function list(flags) {
|
|
|
91
89
|
empty: 'No API keys yet. Create one with: myapi keys create',
|
|
92
90
|
});
|
|
93
91
|
}
|
|
94
|
-
export async function revoke(id,
|
|
95
|
-
|
|
96
|
-
error('Missing key ID. Usage: myapi keys revoke <id>');
|
|
92
|
+
export async function revoke(id, _flags) {
|
|
93
|
+
requireArg(id, 'id', 'myapi keys revoke <id>');
|
|
97
94
|
const config = requireConfig();
|
|
98
95
|
await hq.revokeApiKey(config.api_key, id);
|
|
99
96
|
success(`Key ${id} revoked successfully.`);
|