@myapihq/cli 1.0.84 → 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 +52 -27
- 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 +75 -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 +99 -46
- 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 +93 -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/index.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// manually maintained — do not regenerate from scripts/generate-indexes.js
|
|
3
|
-
import { parseArgs } from './utils.js';
|
|
4
2
|
import { error, info, success } from './output.js';
|
|
5
3
|
import { loadConfig } from './config.js';
|
|
6
4
|
import { MyApiError } from '@myapihq/sdk';
|
|
7
5
|
import * as fs from 'fs';
|
|
6
|
+
import { parseFlags } from './flags.js';
|
|
8
7
|
const pkgPath = new URL('../package.json', import.meta.url);
|
|
9
8
|
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
|
10
9
|
import * as keysCmd from './commands/keys.js';
|
|
@@ -14,8 +13,29 @@ import * as setupCmd from './commands/setup.js';
|
|
|
14
13
|
import * as updateCmd from './commands/update.js';
|
|
15
14
|
import * as domainCmd from './commands/domain.js';
|
|
16
15
|
import * as funnelCmd from './commands/funnel.js';
|
|
16
|
+
import * as webhookCmd from './commands/webhook.js';
|
|
17
|
+
import * as workflowCmd from './commands/workflow.js';
|
|
18
|
+
import * as emailCmd from './commands/email.js';
|
|
17
19
|
import * as authCmd from './commands/auth.js';
|
|
18
20
|
import * as configCmd from './commands/config.js';
|
|
21
|
+
// Each command file declares the value flags it understands. We union them
|
|
22
|
+
// into a single schema for the upfront parse, so adding a new value flag in
|
|
23
|
+
// one command means editing one file (its SCHEMA), not a global allowlist.
|
|
24
|
+
const COMBINED_SCHEMA = {
|
|
25
|
+
...authCmd.SCHEMA,
|
|
26
|
+
...billingCmd.SCHEMA,
|
|
27
|
+
...configCmd.SCHEMA,
|
|
28
|
+
...domainCmd.SCHEMA,
|
|
29
|
+
...emailCmd.SCHEMA,
|
|
30
|
+
...funnelCmd.SCHEMA,
|
|
31
|
+
...keysCmd.SCHEMA,
|
|
32
|
+
...orgCmd.SCHEMA,
|
|
33
|
+
...webhookCmd.SCHEMA,
|
|
34
|
+
...workflowCmd.SCHEMA,
|
|
35
|
+
// Top-level flags
|
|
36
|
+
version: 'boolean',
|
|
37
|
+
V: 'boolean',
|
|
38
|
+
};
|
|
19
39
|
const ERROR_MESSAGES = {
|
|
20
40
|
DOMAIN_NOT_FOUND: 'Domain not found.',
|
|
21
41
|
INVALID_DOMAIN: 'Invalid domain name.',
|
|
@@ -43,7 +63,7 @@ function friendlyError(code) {
|
|
|
43
63
|
return ERROR_MESSAGES[code] || code;
|
|
44
64
|
}
|
|
45
65
|
async function main() {
|
|
46
|
-
const { args, flags } =
|
|
66
|
+
const { args, flags } = parseFlags(process.argv.slice(2), COMBINED_SCHEMA);
|
|
47
67
|
if (flags.version || flags.v || flags.V) {
|
|
48
68
|
const latest = await updateCmd.latestVersion();
|
|
49
69
|
const updateNote = latest && updateCmd.isNewer(latest, pkg.version)
|
|
@@ -71,89 +91,16 @@ async function main() {
|
|
|
71
91
|
try {
|
|
72
92
|
switch (command) {
|
|
73
93
|
case 'auth':
|
|
74
|
-
|
|
75
|
-
info('Usage: myapi auth <subcommand>\n\nSubcommands:\n setup Configure your account\n import-key Import an existing API key non-interactively\n whoami Show current account · supports --json\n link [email] Upgrade anonymous account to registered (or add a second session)\n Use myapi auth setup to create a completely new account\n switch [index] Switch active account by index or email\n config Manage CLI defaults (org, funnel, domain) · supports set-org / set-funnel / set-domain\n install-skills Install or update the MyAPI skills pack for AI agents\n api-keys Manage API keys · list / create / revoke\n keys Alias for api-keys');
|
|
76
|
-
break;
|
|
77
|
-
}
|
|
78
|
-
if (subcommand === 'setup')
|
|
79
|
-
await setupCmd.setup(flags);
|
|
80
|
-
else if (subcommand === 'import-key')
|
|
81
|
-
await setupCmd.importKey(restArgs[0], flags);
|
|
82
|
-
else if (subcommand === 'whoami')
|
|
83
|
-
await authCmd.whoami(flags);
|
|
84
|
-
else if (subcommand === 'link')
|
|
85
|
-
await authCmd.link(flags, restArgs[0]);
|
|
86
|
-
else if (subcommand === 'switch')
|
|
87
|
-
await authCmd.switchCmd(flags, restArgs[0]);
|
|
88
|
-
else if (subcommand === 'install-skills') {
|
|
89
|
-
if (flags.help) {
|
|
90
|
-
info('Usage: myapi auth install-skills\n\nInstalls the MyAPI skills pack for AI coding agents (Claude, Gemini, Cursor).\n\nThis command writes skill definition files to:\n ~/.agents/skills/myapi/\n\nAnd creates symlinks in the appropriate agent config directories:\n ~/.claude/ (Claude)\n ~/.gemini/ (Gemini)\n ~/.cursor/ (Cursor, if detected)\n\nThese files teach agents how to use the MyAPI CLI and API directly.\nRun this command again to update existing skills to the latest version.');
|
|
91
|
-
break;
|
|
92
|
-
}
|
|
93
|
-
await setupCmd.installSkills();
|
|
94
|
-
success('› Skills installed.');
|
|
95
|
-
}
|
|
96
|
-
else if (subcommand === 'config')
|
|
97
|
-
await configCmd.run(restArgs[0], restArgs.slice(1), flags);
|
|
98
|
-
else if (subcommand === 'api-keys') {
|
|
99
|
-
if (flags.help && !restArgs[0]) {
|
|
100
|
-
info('Usage: myapi auth api-keys <subcommand>\n\nManage programmatic API keys for your account. API keys are used to authenticate\nrequests to the MyAPI SDK and REST API.\n\nSubcommands:\n list List all API keys with their IDs and creation dates\n create Create a new API key (the key value is shown once)\n revoke <id> Permanently revoke an API key by ID\n\nExamples:\n myapi auth api-keys list\n myapi auth api-keys create\n myapi auth api-keys revoke hq_live_xxxxxxxxxxxxxxxxxxxx');
|
|
101
|
-
break;
|
|
102
|
-
}
|
|
103
|
-
if (!restArgs[0]) {
|
|
104
|
-
info('Run: myapi auth api-keys --help');
|
|
105
|
-
break;
|
|
106
|
-
}
|
|
107
|
-
if (restArgs[0] === 'create')
|
|
108
|
-
await keysCmd.createNew(flags);
|
|
109
|
-
else if (restArgs[0] === 'list')
|
|
110
|
-
await keysCmd.list(flags);
|
|
111
|
-
else if (restArgs[0] === 'revoke')
|
|
112
|
-
await keysCmd.revoke(restArgs[1], flags);
|
|
113
|
-
}
|
|
114
|
-
else
|
|
115
|
-
info('Unknown subcommand. Run: myapi auth --help');
|
|
94
|
+
await dispatchAuth(subcommand, restArgs, flags);
|
|
116
95
|
break;
|
|
117
96
|
case 'update':
|
|
118
97
|
await updateCmd.update(flags);
|
|
119
98
|
break;
|
|
120
99
|
case 'org':
|
|
121
|
-
|
|
122
|
-
info('Usage: myapi org <subcommand>\n\nSubcommands:\n list List organizations\n create Create an organization · myapi org create "Name" --yes\n get Get details of an organization\n delete Delete an organization\n sync-brand Sync brand info (name, logo, description) from an existing website into an org');
|
|
123
|
-
break;
|
|
124
|
-
}
|
|
125
|
-
if (subcommand === 'list')
|
|
126
|
-
await orgCmd.list(flags);
|
|
127
|
-
else if (subcommand === 'create')
|
|
128
|
-
await orgCmd.create(restArgs, flags);
|
|
129
|
-
else if (subcommand === 'get')
|
|
130
|
-
await orgCmd.get(restArgs[0], flags);
|
|
131
|
-
else if (subcommand === 'delete')
|
|
132
|
-
await orgCmd.del(restArgs[0], flags);
|
|
133
|
-
else if (subcommand === 'sync-brand')
|
|
134
|
-
await orgCmd.importOrg(restArgs, flags);
|
|
135
|
-
else if (subcommand === 'import') {
|
|
136
|
-
process.stderr.write('› Note: "org import" is deprecated — use "org sync-brand" instead.\n');
|
|
137
|
-
await orgCmd.importOrg(restArgs, flags);
|
|
138
|
-
}
|
|
139
|
-
else
|
|
140
|
-
printHelp();
|
|
100
|
+
await orgCmd.run(subcommand, restArgs, flags);
|
|
141
101
|
break;
|
|
142
102
|
case 'billing':
|
|
143
|
-
|
|
144
|
-
info('Usage: myapi billing <subcommand>\n\nSubcommands:\n balance Check balance\n history View billing history\n topup Top up your balance\n setup Setup a payment method');
|
|
145
|
-
break;
|
|
146
|
-
}
|
|
147
|
-
if (subcommand === 'balance')
|
|
148
|
-
await billingCmd.balance(flags);
|
|
149
|
-
else if (subcommand === 'history')
|
|
150
|
-
await billingCmd.history(flags);
|
|
151
|
-
else if (subcommand === 'topup')
|
|
152
|
-
await billingCmd.topup(restArgs[0], flags);
|
|
153
|
-
else if (subcommand === 'setup')
|
|
154
|
-
await billingCmd.setup(flags);
|
|
155
|
-
else
|
|
156
|
-
printHelp();
|
|
103
|
+
await billingCmd.run(subcommand, restArgs, flags);
|
|
157
104
|
break;
|
|
158
105
|
case 'domain':
|
|
159
106
|
await domainCmd.run(subcommand, restArgs, flags);
|
|
@@ -161,6 +108,15 @@ async function main() {
|
|
|
161
108
|
case 'funnel':
|
|
162
109
|
await funnelCmd.run(subcommand, restArgs, flags);
|
|
163
110
|
break;
|
|
111
|
+
case 'webhook':
|
|
112
|
+
await webhookCmd.run(subcommand, restArgs, flags);
|
|
113
|
+
break;
|
|
114
|
+
case 'workflow':
|
|
115
|
+
await workflowCmd.run(subcommand, restArgs, flags);
|
|
116
|
+
break;
|
|
117
|
+
case 'email':
|
|
118
|
+
await emailCmd.run(subcommand, restArgs, flags);
|
|
119
|
+
break;
|
|
164
120
|
// Convenience aliases
|
|
165
121
|
case 'setup':
|
|
166
122
|
await setupCmd.setup(flags);
|
|
@@ -169,45 +125,21 @@ async function main() {
|
|
|
169
125
|
await authCmd.whoami(flags);
|
|
170
126
|
break;
|
|
171
127
|
case 'keys':
|
|
172
|
-
|
|
173
|
-
info('Usage: myapi keys <subcommand>\n\nManage programmatic API keys for your account. API keys are used to authenticate\nrequests to the MyAPI SDK and REST API.\n\nSubcommands:\n list List all API keys with their IDs and creation dates\n create Create a new API key (the key value is shown once)\n revoke <id> Permanently revoke an API key by ID\n\nExamples:\n myapi keys list\n myapi keys create\n myapi keys revoke hq_live_xxxxxxxxxxxxxxxxxxxx\n\nAlias for: myapi auth api-keys');
|
|
174
|
-
break;
|
|
175
|
-
}
|
|
176
|
-
if (subcommand === 'create')
|
|
177
|
-
await keysCmd.createNew(flags);
|
|
178
|
-
else if (subcommand === 'list')
|
|
179
|
-
await keysCmd.list(flags);
|
|
180
|
-
else if (subcommand === 'revoke')
|
|
181
|
-
await keysCmd.revoke(restArgs[0], flags);
|
|
128
|
+
await keysCmd.run(subcommand, restArgs, flags);
|
|
182
129
|
break;
|
|
183
130
|
case 'config':
|
|
184
131
|
await configCmd.run(subcommand, restArgs, { ...flags, _via: 'config' });
|
|
185
132
|
break;
|
|
186
133
|
case 'install-skills':
|
|
187
134
|
if (flags.help) {
|
|
188
|
-
info(
|
|
135
|
+
info(authCmd.INSTALL_SKILLS_HELP);
|
|
189
136
|
break;
|
|
190
137
|
}
|
|
191
138
|
await setupCmd.installSkills();
|
|
192
139
|
success('› Skills installed.');
|
|
193
140
|
break;
|
|
194
141
|
case 'help':
|
|
195
|
-
|
|
196
|
-
await funnelCmd.run(undefined, [], { help: true });
|
|
197
|
-
else if (subcommand === 'domain')
|
|
198
|
-
await domainCmd.run(undefined, [], { help: true });
|
|
199
|
-
else if (subcommand === 'auth')
|
|
200
|
-
info('Usage: myapi auth <subcommand>\n\nSubcommands:\n setup Configure your account\n import-key Import an existing API key non-interactively\n whoami Show current account · supports --json\n link [email] Upgrade anonymous account to registered (or add a second session)\n switch [index] Switch active account by index or email\n config Manage CLI defaults (org, funnel, domain)\n install-skills Install or update the MyAPI skills pack for AI agents\n api-keys Manage API keys · list / create / revoke');
|
|
201
|
-
else if (subcommand === 'org')
|
|
202
|
-
info('Usage: myapi org <subcommand>\n\nSubcommands:\n list List organizations\n create Create an organization · myapi org create "Name" --yes\n get Get details of an organization\n delete Delete an organization\n sync-brand Sync brand info from an existing website into an org');
|
|
203
|
-
else if (subcommand === 'billing')
|
|
204
|
-
info('Usage: myapi billing <subcommand>\n\nSubcommands:\n balance Check balance\n history View billing history\n topup Top up your balance\n setup Setup a payment method');
|
|
205
|
-
else if (subcommand === 'keys')
|
|
206
|
-
info('Usage: myapi keys <subcommand>\n\nSubcommands:\n list List all API keys\n create Create a new API key\n revoke <id> Revoke an API key\n\nAlias for: myapi auth api-keys');
|
|
207
|
-
else if (subcommand)
|
|
208
|
-
info(`Run: myapi ${subcommand} --help`);
|
|
209
|
-
else
|
|
210
|
-
printHelp();
|
|
142
|
+
await dispatchHelp(subcommand);
|
|
211
143
|
break;
|
|
212
144
|
default:
|
|
213
145
|
error(`Unknown command: ${command}. Run "myapi" for available commands.`);
|
|
@@ -223,7 +155,7 @@ async function main() {
|
|
|
223
155
|
else if (err.code === 'NO_PAYMENT_METHOD')
|
|
224
156
|
error('No payment method on file. Run: myapi billing setup');
|
|
225
157
|
else
|
|
226
|
-
error(
|
|
158
|
+
error('Insufficient balance. Run: myapi billing topup <amount>');
|
|
227
159
|
}
|
|
228
160
|
else
|
|
229
161
|
error(friendlyError(err.code) || err.message);
|
|
@@ -233,6 +165,57 @@ async function main() {
|
|
|
233
165
|
}
|
|
234
166
|
}
|
|
235
167
|
}
|
|
168
|
+
async function dispatchAuth(subcommand, restArgs, flags) {
|
|
169
|
+
if (!subcommand || (flags.help && !subcommand)) {
|
|
170
|
+
info(authCmd.HELP);
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
switch (subcommand) {
|
|
174
|
+
case 'setup': return setupCmd.setup(flags);
|
|
175
|
+
case 'import-key': return setupCmd.importKey(restArgs[0], flags);
|
|
176
|
+
case 'whoami': return authCmd.whoami(flags);
|
|
177
|
+
case 'link': return authCmd.link(flags, restArgs[0]);
|
|
178
|
+
case 'switch': return authCmd.switchCmd(flags, restArgs[0]);
|
|
179
|
+
case 'install-skills':
|
|
180
|
+
if (flags.help) {
|
|
181
|
+
info(authCmd.INSTALL_SKILLS_HELP);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
await setupCmd.installSkills();
|
|
185
|
+
success('› Skills installed.');
|
|
186
|
+
return;
|
|
187
|
+
case 'config': return configCmd.run(restArgs[0], restArgs.slice(1), flags);
|
|
188
|
+
case 'api-keys':
|
|
189
|
+
case 'keys': return keysCmd.runApiKeys(restArgs[0], restArgs.slice(1), flags);
|
|
190
|
+
default: info('Unknown subcommand. Run: myapi auth --help');
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
const HELP_TARGETS = {
|
|
194
|
+
funnel: f => funnelCmd.run(undefined, [], f),
|
|
195
|
+
domain: f => domainCmd.run(undefined, [], f),
|
|
196
|
+
webhook: f => webhookCmd.run(undefined, [], f),
|
|
197
|
+
workflow: f => workflowCmd.run(undefined, [], f),
|
|
198
|
+
email: f => emailCmd.run(undefined, [], f),
|
|
199
|
+
org: f => orgCmd.run(undefined, [], f),
|
|
200
|
+
billing: f => billingCmd.run(undefined, [], f),
|
|
201
|
+
keys: f => keysCmd.run(undefined, [], f),
|
|
202
|
+
config: f => configCmd.run(undefined, [], f),
|
|
203
|
+
};
|
|
204
|
+
async function dispatchHelp(target) {
|
|
205
|
+
if (!target) {
|
|
206
|
+
printHelp();
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
if (target === 'auth') {
|
|
210
|
+
info(authCmd.HELP);
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
const handler = HELP_TARGETS[target];
|
|
214
|
+
if (handler)
|
|
215
|
+
await handler({ help: true });
|
|
216
|
+
else
|
|
217
|
+
info(`Run: myapi ${target} --help`);
|
|
218
|
+
}
|
|
236
219
|
function printHelp() {
|
|
237
220
|
const config = loadConfig();
|
|
238
221
|
const quickStart = config?.api_key
|
|
@@ -252,6 +235,9 @@ Commands:
|
|
|
252
235
|
update Update CLI and skills to the latest version
|
|
253
236
|
domain Manage domain configurations
|
|
254
237
|
funnel Manage websites (publish pages, custom domains, funnels)
|
|
238
|
+
webhook Manage inbound webhook endpoints and inspect deliveries
|
|
239
|
+
email Manage mailboxes, send/read email, templates, and campaigns
|
|
240
|
+
workflow Run actions (send email, post to Slack) when a webhook fires
|
|
255
241
|
|
|
256
242
|
Aliases:
|
|
257
243
|
whoami → myapi auth whoami
|
package/dist/output.d.ts
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
|
+
export type TableFlags = {
|
|
2
|
+
json?: boolean | string | number;
|
|
3
|
+
} & Record<string, unknown>;
|
|
1
4
|
export declare function success(message: string): void;
|
|
2
5
|
export declare function error(message: string): never;
|
|
3
6
|
export declare function info(message: string): void;
|
|
4
7
|
export declare function banner(message: string): void;
|
|
5
8
|
export declare function printJson(data: unknown): void;
|
|
6
|
-
export
|
|
9
|
+
export interface PrintTableOptions {
|
|
10
|
+
/** Pass `flags` so `--json` (any truthy form) routes to JSON output. */
|
|
11
|
+
flags?: TableFlags;
|
|
12
|
+
/** Hint shown when the table is empty (instead of "No data found."). */
|
|
13
|
+
empty?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function printTable(rows: Record<string, unknown>[], opts?: PrintTableOptions): void;
|
package/dist/output.js
CHANGED
|
@@ -15,19 +15,17 @@ export function banner(message) {
|
|
|
15
15
|
export function printJson(data) {
|
|
16
16
|
console.log(JSON.stringify(data, null, 2));
|
|
17
17
|
}
|
|
18
|
-
export function printTable(rows) {
|
|
19
|
-
if (
|
|
18
|
+
export function printTable(rows, opts = {}) {
|
|
19
|
+
if (opts.flags && opts.flags.json) {
|
|
20
20
|
printJson(rows);
|
|
21
21
|
return;
|
|
22
22
|
}
|
|
23
23
|
if (rows.length === 0) {
|
|
24
|
-
console.log(
|
|
24
|
+
console.log(opts.empty ?? 'No data found.');
|
|
25
25
|
return;
|
|
26
26
|
}
|
|
27
27
|
const columns = Object.keys(rows[0]);
|
|
28
|
-
const colWidths = columns.map(col =>
|
|
29
|
-
return Math.max(col.length, ...rows.map(row => String(row[col] ?? '').length));
|
|
30
|
-
});
|
|
28
|
+
const colWidths = columns.map(col => Math.max(col.length, ...rows.map(row => String(row[col] ?? '').length)));
|
|
31
29
|
const printRow = (row) => {
|
|
32
30
|
console.log(row.map((cell, i) => cell.padEnd(colWidths[i] + 2)).join(''));
|
|
33
31
|
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
# my-email-api
|
|
3
|
+
|
|
4
|
+
Send transactional email and run drip campaigns from mailboxes on your own registered domains. Includes AI template generation, warmup, and inbox/outbox reading.
|
|
5
|
+
|
|
6
|
+
## What it does
|
|
7
|
+
|
|
8
|
+
- Create mailboxes on your registered domains
|
|
9
|
+
- Send transactional emails (one-shot or templated)
|
|
10
|
+
- Read inbox, outbox, sent history, and per-message status
|
|
11
|
+
- Generate HTML email templates with AI from a prompt
|
|
12
|
+
- Run paced drip campaigns against uploaded contact lists
|
|
13
|
+
- Manage IP/domain warmup for sender reputation
|
|
14
|
+
|
|
15
|
+
## Quickstart
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# Create a mailbox + activate sending
|
|
19
|
+
myapi email mailbox create --domain yourdomain.com --username hello
|
|
20
|
+
myapi email mailbox activate-sending --address hello@yourdomain.com
|
|
21
|
+
|
|
22
|
+
# Send
|
|
23
|
+
myapi email message send \
|
|
24
|
+
--from hello@yourdomain.com \
|
|
25
|
+
--to recipient@example.com \
|
|
26
|
+
--subject "Hi" \
|
|
27
|
+
--body "Test"
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Authentication
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
export MYAPI_KEY=mak_...
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Requires:
|
|
37
|
+
- An `api_key` from **myapihq**
|
|
38
|
+
- A registered domain via **mydomainapi**, assigned to your org
|
|
39
|
+
- Default `org_id` (for templates/campaigns) — set with `myapi auth config set-org <id>`
|
|
40
|
+
|
|
41
|
+
## Documentation
|
|
42
|
+
|
|
43
|
+
Full command reference and flow diagrams: see `SKILL.md`.
|
|
44
|
+
|
|
45
|
+
Run `myapi email --help` for inline reference.
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: my-email-api
|
|
3
|
+
description: >
|
|
4
|
+
Send transactional and bulk email from your own domain. Create mailboxes, send/receive messages, generate AI templates, run drip campaigns, and manage warmup.
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# MyEmailAPI
|
|
8
|
+
|
|
9
|
+
Account-scoped email infrastructure tied to your registered domains. Mailboxes belong to domains; sending and receiving work without per-org plumbing. Templates and campaigns are org-scoped (one campaign belongs to one org).
|
|
10
|
+
|
|
11
|
+
## How It Fits Together
|
|
12
|
+
|
|
13
|
+
- Requires `api_key` from **myapihq** and a registered domain via **mydomainapi**.
|
|
14
|
+
- Mailboxes live on a domain (e.g. `hello@yourdomain.com`).
|
|
15
|
+
- Sending must be activated per-mailbox (`mailbox activate-sending`) before transactional sends or campaigns.
|
|
16
|
+
- Templates and campaigns require `org_id` (set a default with `myapi auth config set-org`).
|
|
17
|
+
|
|
18
|
+
## Quick Start
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# 1. Create a mailbox on your registered domain
|
|
22
|
+
myapi email mailbox create --domain yourdomain.com --username hello --display-name "Hello"
|
|
23
|
+
|
|
24
|
+
# 2. Activate sending (required before send/campaign)
|
|
25
|
+
myapi email mailbox activate-sending --address hello@yourdomain.com
|
|
26
|
+
|
|
27
|
+
# 3. Send a transactional email
|
|
28
|
+
myapi email message send \
|
|
29
|
+
--from hello@yourdomain.com \
|
|
30
|
+
--to recipient@example.com \
|
|
31
|
+
--subject "Hi" \
|
|
32
|
+
--body "Test message"
|
|
33
|
+
|
|
34
|
+
# 4. Read inbox / outbox
|
|
35
|
+
myapi email message inbox hello@yourdomain.com
|
|
36
|
+
myapi email message outbox hello@yourdomain.com
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Command Map
|
|
40
|
+
|
|
41
|
+
| Namespace | Subcommands | Purpose |
|
|
42
|
+
|---|---|---|
|
|
43
|
+
| `email mailbox` | `create`, `list`, `activate-sending` | Create and manage mailboxes on your domains |
|
|
44
|
+
| `email message` | `send`, `status`, `sent`, `inbox`, `outbox`, `get` | Transactional send + read |
|
|
45
|
+
| `email warmup` | `start`, `stats`, `pause`, `resume`, `stop` | IP/domain warmup for sending reputation |
|
|
46
|
+
| `email template` | `generate`, `list`, `edit`, `send-test`, `delete` | AI-generated HTML templates (org-scoped) |
|
|
47
|
+
| `email campaign` | `create`, `list`, `get`, `update`, `upload-contacts`, `start`, `pause`, `resume`, `stats` | Drip campaigns (org-scoped) |
|
|
48
|
+
|
|
49
|
+
## Templates (AI-generated)
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
# Generate a template — polls the LLM job (up to 90s)
|
|
53
|
+
myapi email template generate \
|
|
54
|
+
--prompt "A welcome email with our brand colors and a CTA to /onboarding" \
|
|
55
|
+
--name welcome-v1
|
|
56
|
+
|
|
57
|
+
# List, edit, delete
|
|
58
|
+
myapi email template list
|
|
59
|
+
myapi email template edit <id> --prompt "Make the CTA larger and red"
|
|
60
|
+
myapi email template send-test <id> --to me@yourdomain.com
|
|
61
|
+
myapi email template delete <id>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Campaigns
|
|
65
|
+
|
|
66
|
+
Campaigns send a template to a contact list at a per-day rate.
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
# 1. Create a campaign linked to an existing template + sender mailbox
|
|
70
|
+
myapi email campaign create \
|
|
71
|
+
--name "Welcome series" \
|
|
72
|
+
--template-id <template_id> \
|
|
73
|
+
--from hello@yourdomain.com \
|
|
74
|
+
--per-day 50
|
|
75
|
+
|
|
76
|
+
# 2. Upload contacts
|
|
77
|
+
myapi email campaign upload-contacts <campaign_id> \
|
|
78
|
+
--emails "alice@example.com,bob@example.com"
|
|
79
|
+
|
|
80
|
+
# 3. Start (only after upload-contacts has finished processing)
|
|
81
|
+
myapi email campaign start <campaign_id>
|
|
82
|
+
|
|
83
|
+
# 4. Monitor
|
|
84
|
+
myapi email campaign stats <campaign_id>
|
|
85
|
+
myapi email campaign pause <campaign_id>
|
|
86
|
+
myapi email campaign resume <campaign_id>
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Warmup
|
|
90
|
+
|
|
91
|
+
Warmup gradually ramps mailbox sending to build reputation with inbox providers. Recommended before high-volume campaigns.
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
myapi email warmup start --address hello@yourdomain.com
|
|
95
|
+
myapi email warmup stats --address hello@yourdomain.com
|
|
96
|
+
myapi email warmup pause --address hello@yourdomain.com
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Notes
|
|
100
|
+
|
|
101
|
+
- A single mailbox is uniquely identified by its address (`username@domain`).
|
|
102
|
+
- Sending must be activated explicitly — newly-created mailboxes can receive but not send.
|
|
103
|
+
- Templates and campaigns are org-scoped. Set a default org once: `myapi auth config set-org <id>`.
|
|
104
|
+
- Domain assignment to org is enforced at unassign time: an active or paused campaign sending from a mailbox on the domain will block `domain unassign` with `DOMAIN_IN_USE`.
|
|
105
|
+
|
|
106
|
+
Run `myapi email --help` or `myapi email <namespace> --help` for full flag reference.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
# my-webhook-api
|
|
3
|
+
|
|
4
|
+
Inbound HTTP endpoints that receive POSTs from third-party services and store every delivery for inspection. Pair with my-workflow-api to react to incoming events.
|
|
5
|
+
|
|
6
|
+
## What it does
|
|
7
|
+
|
|
8
|
+
- Create per-org webhook endpoints with unique inbound URLs
|
|
9
|
+
- Store every inbound delivery (body + headers)
|
|
10
|
+
- Inspect individual deliveries by id
|
|
11
|
+
- Bind webhooks to workflows for event-driven actions
|
|
12
|
+
|
|
13
|
+
## Quickstart
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# Create an endpoint
|
|
17
|
+
myapi webhook create --name "stripe-events"
|
|
18
|
+
# → prints: Inbound URL: https://api.myapihq.com/webhook/in/<slug>
|
|
19
|
+
|
|
20
|
+
# POST to it from anywhere
|
|
21
|
+
curl -X POST <inbound-url> -d '{"event":"x"}'
|
|
22
|
+
|
|
23
|
+
# List + inspect
|
|
24
|
+
myapi webhook list
|
|
25
|
+
myapi webhook delivery <delivery_id>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Authentication
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
export MYAPI_KEY=mak_...
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Requires `api_key` and `org_id` from **myapihq**.
|
|
35
|
+
|
|
36
|
+
## Documentation
|
|
37
|
+
|
|
38
|
+
Full command reference and workflow integration: see `SKILL.md`.
|
|
39
|
+
|
|
40
|
+
Run `myapi webhook --help` for inline reference.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: my-webhook-api
|
|
3
|
+
description: >
|
|
4
|
+
Inbound webhook endpoints. Receive HTTP POSTs from third parties (forms, Stripe, GitHub, etc.) and either inspect the deliveries directly or wire them to a workflow.
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# MyWebhookAPI
|
|
8
|
+
|
|
9
|
+
Per-org HTTP endpoints that accept inbound POSTs and durably store every delivery. A webhook on its own is a passive receiver — pair it with **myworkflowapi** to react to incoming events (send email, post to Slack, etc.).
|
|
10
|
+
|
|
11
|
+
## How It Fits Together
|
|
12
|
+
|
|
13
|
+
- Requires `api_key` and `org_id` from **myapihq**.
|
|
14
|
+
- Each endpoint has a unique inbound URL (returned at create time).
|
|
15
|
+
- Deliveries are stored verbatim — full request body + headers — for inspection.
|
|
16
|
+
- `myworkflowapi` workflows bind to a webhook endpoint via its `id`.
|
|
17
|
+
|
|
18
|
+
## Quick Start
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# 1. Create a webhook endpoint
|
|
22
|
+
myapi webhook create --name "stripe-events" --description "Stripe payment events"
|
|
23
|
+
# → prints: Inbound URL: https://api.myapihq.com/webhook/in/<slug>
|
|
24
|
+
|
|
25
|
+
# 2. POST to the inbound URL from your service
|
|
26
|
+
curl -X POST https://api.myapihq.com/webhook/in/<slug> \
|
|
27
|
+
-H "Content-Type: application/json" \
|
|
28
|
+
-d '{"event":"payment.succeeded"}'
|
|
29
|
+
|
|
30
|
+
# 3. List endpoints / inspect a delivery
|
|
31
|
+
myapi webhook list
|
|
32
|
+
myapi webhook delivery <delivery_id>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## All Commands
|
|
36
|
+
|
|
37
|
+
| Command | What it does |
|
|
38
|
+
|---|---|
|
|
39
|
+
| `myapi webhook create` | Create an endpoint, returns id + inbound URL |
|
|
40
|
+
| `myapi webhook list` | List all endpoints in your org |
|
|
41
|
+
| `myapi webhook delete <id>` | Delete an endpoint and all its deliveries |
|
|
42
|
+
| `myapi webhook delivery <delivery_id>` | Get the full payload + headers for one delivery |
|
|
43
|
+
|
|
44
|
+
## Wiring to a Workflow
|
|
45
|
+
|
|
46
|
+
Webhooks become useful when a workflow fires on each inbound POST. See **myworkflowapi**:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
# Create the webhook
|
|
50
|
+
WID=$(myapi webhook create --name "leads" --json | jq -r .id)
|
|
51
|
+
|
|
52
|
+
# Bind a workflow that sends an email each time the webhook fires
|
|
53
|
+
myapi workflow create \
|
|
54
|
+
--name "Notify on lead" \
|
|
55
|
+
--endpoint-id $WID \
|
|
56
|
+
--steps '[{"type":"send_email","to":"sales@yourdomain.com","subject":"New lead"}]'
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Notes
|
|
60
|
+
|
|
61
|
+
- The inbound URL is public — anyone with the URL can POST to it. Treat the slug as a secret.
|
|
62
|
+
- Deliveries are kept indefinitely. Delete the endpoint to purge them.
|
|
63
|
+
- Failed workflow runs do not affect the delivery record — the inbound POST is always saved.
|
|
64
|
+
|
|
65
|
+
Run `myapi webhook --help` for full flag reference.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
# my-workflow-api
|
|
3
|
+
|
|
4
|
+
Run a chain of actions (send email, post to Slack, call an HTTP endpoint) every time an inbound webhook fires. No backend required.
|
|
5
|
+
|
|
6
|
+
## What it does
|
|
7
|
+
|
|
8
|
+
- Bind ordered step chains to webhook endpoints
|
|
9
|
+
- Steps can: send transactional email, hit Slack, call any HTTP URL
|
|
10
|
+
- Template values from the inbound webhook payload (`{{ payload.field }}`)
|
|
11
|
+
- Per-run status tracking (attempt, error, started/finished timestamps)
|
|
12
|
+
- Enable/disable without losing config
|
|
13
|
+
|
|
14
|
+
## Quickstart
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
# Create a webhook + workflow that sends Slack on every POST
|
|
18
|
+
WID=$(myapi webhook create --name "leads" --json | jq -r .id)
|
|
19
|
+
myapi workflow create \
|
|
20
|
+
--name "Slack on lead" \
|
|
21
|
+
--endpoint-id $WID \
|
|
22
|
+
--steps '[{"type":"slack","webhook_url":"..."}]'
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Authentication
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
export MYAPI_KEY=mak_...
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Requires `api_key` + `org_id` from **myapihq**, and a webhook endpoint id from **mywebhookapi**.
|
|
32
|
+
|
|
33
|
+
## Documentation
|
|
34
|
+
|
|
35
|
+
Full command reference, step types, and templating: see `SKILL.md`.
|
|
36
|
+
|
|
37
|
+
Run `myapi workflow --help` for inline reference.
|