@myapihq/cli 1.0.61 → 1.0.65
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 +13 -5
- package/dist/commands/config.d.ts +4 -4
- package/dist/commands/config.js +13 -13
- package/dist/commands/domain.d.ts +0 -1
- package/dist/commands/domain.js +10 -24
- package/dist/commands/funnel.js +7 -3
- package/dist/commands/keys.js +2 -2
- package/dist/commands/org.js +8 -4
- package/dist/commands/update.js +1 -1
- package/dist/index.js +6 -6
- package/dist/skills/my-api-hq/README.md +37 -0
- package/dist/skills/my-api-hq/SKILL.md +116 -0
- package/dist/skills/my-api-hq/claude/.claude-plugin/plugin.json +6 -0
- package/dist/skills/my-api-hq/make/.gitkeep +0 -0
- package/dist/skills/my-api-hq/n8n/.gitkeep +0 -0
- package/dist/skills/my-api-hq/openapi/.gitkeep +0 -0
- package/dist/skills/my-domain-api/README.md +37 -0
- package/dist/skills/my-domain-api/SKILL.md +83 -0
- package/dist/skills/my-domain-api/claude/.claude-plugin/plugin.json +6 -0
- package/dist/skills/my-domain-api/make/.gitkeep +0 -0
- package/dist/skills/my-domain-api/n8n/.gitkeep +0 -0
- package/dist/skills/my-domain-api/openapi/.gitkeep +0 -0
- package/dist/skills/my-funnel-api/README.md +39 -0
- package/dist/skills/my-funnel-api/SKILL.md +35 -0
- package/dist/skills/my-funnel-api/claude/.claude-plugin/plugin.json +6 -0
- package/dist/skills/my-funnel-api/make/.gitkeep +0 -0
- package/dist/skills/my-funnel-api/n8n/.gitkeep +0 -0
- package/dist/skills/my-funnel-api/openapi/.gitkeep +0 -0
- package/package.json +4 -1
- package/scripts/copy-skills.js +0 -13
- package/src/commands/auth.ts +0 -190
- package/src/commands/billing.ts +0 -92
- package/src/commands/config.ts +0 -71
- package/src/commands/domain.ts +0 -146
- package/src/commands/email.ts +0 -185
- package/src/commands/funnel.ts +0 -122
- package/src/commands/image.ts +0 -85
- package/src/commands/keys.ts +0 -68
- package/src/commands/org.ts +0 -134
- package/src/commands/pixel.ts +0 -62
- package/src/commands/setup.ts +0 -335
- package/src/commands/storage.ts +0 -56
- package/src/commands/update.ts +0 -89
- package/src/commands/url.ts +0 -28
- package/src/commands/webhook.ts +0 -66
- package/src/commands/workflow.ts +0 -102
- package/src/config.ts +0 -123
- package/src/index.ts +0 -200
- package/src/output.ts +0 -49
- package/src/utils.ts +0 -45
- package/thank-you.html +0 -56
- package/tsconfig.json +0 -15
package/src/commands/url.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { url as sdkUrl } from '@myapihq/sdk';
|
|
2
|
-
import { requireConfig } from '../config.js';
|
|
3
|
-
import { success, error, info, printJson } from '../output.js';
|
|
4
|
-
|
|
5
|
-
export async function shorten(targetUrl: string, flags: Record<string, string | boolean>) {
|
|
6
|
-
const config = requireConfig();
|
|
7
|
-
const orgId = (flags.org as string) || config.default_org;
|
|
8
|
-
if (!orgId || !targetUrl) error("Missing required arguments.\nUsage: myapi url shorten <url> --org <id>\n(Or set defaults via: myapi config set-org <id>)");
|
|
9
|
-
|
|
10
|
-
const res = await sdkUrl.shortenUrl(config.api_key, orgId, targetUrl);
|
|
11
|
-
if (flags.json) printJson(res);
|
|
12
|
-
else success(`Shortened URL: ${res.short_url}\nCode: ${res.short_code}`);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export async function run(subcommand: string | undefined, args: string[], flags: Record<string, string | boolean>) {
|
|
16
|
-
if (!subcommand || (flags.help && !subcommand)) {
|
|
17
|
-
info('Usage: myapi url <subcommand>\n\nSubcommands:\n shorten Shorten a long URL\n\nNote: All url commands require the --org <id> flag.');
|
|
18
|
-
return;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
if (flags.help) {
|
|
22
|
-
if (subcommand === 'shorten') info('Usage: myapi url shorten <url> --org <id> [--json]\n\nShortens a long URL and returns the compact myurlto.com link.');
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
if (subcommand === 'shorten') await shorten(args[0], flags);
|
|
27
|
-
else error(`Unknown subcommand: ${subcommand}. Run "myapi url --help" for a list of valid subcommands.`);
|
|
28
|
-
}
|
package/src/commands/webhook.ts
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { webhook as sdkWebhook } from '@myapihq/sdk';
|
|
2
|
-
import { requireConfig } from '../config.js';
|
|
3
|
-
import { success, error, printTable, info, printJson } from '../output.js';
|
|
4
|
-
|
|
5
|
-
export async function list(flags: Record<string, string | boolean>) {
|
|
6
|
-
const config = requireConfig();
|
|
7
|
-
const orgId = (flags.org as string) || config.default_org;
|
|
8
|
-
if (!orgId) error("Missing required arguments.\nUsage: myapi webhook list --org <id>\n(Or set defaults via: myapi config set-org <id>)");
|
|
9
|
-
|
|
10
|
-
const endpoints = await sdkWebhook.listEndpoints(config.api_key, orgId);
|
|
11
|
-
if (flags.json) printJson(endpoints);
|
|
12
|
-
else printTable(endpoints as unknown as Record<string, unknown>[]);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export async function create(flags: Record<string, string | boolean>) {
|
|
16
|
-
const config = requireConfig();
|
|
17
|
-
const orgId = (flags.org as string) || config.default_org;
|
|
18
|
-
const name = flags.name as string;
|
|
19
|
-
const description = flags.description as string;
|
|
20
|
-
|
|
21
|
-
if (!orgId || !name) {
|
|
22
|
-
error("Missing required arguments.\nUsage: myapi webhook create --name <name> [--description <desc>] --org <id>\n(Or set defaults via: myapi config set-org <id>)");
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const res = await sdkWebhook.createEndpoint(config.api_key, orgId, name, description);
|
|
26
|
-
success(`Webhook created! ID: ${res.id}\nInbound URL: ${res.inbound_url}`);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export async function del(id: string, flags: Record<string, string | boolean>) {
|
|
30
|
-
const config = requireConfig();
|
|
31
|
-
const orgId = (flags.org as string) || config.default_org;
|
|
32
|
-
if (!orgId || !id) error("Missing required arguments.\nUsage: myapi webhook delete <id> --org <id>\n(Or set defaults via: myapi config set-org <id>)");
|
|
33
|
-
|
|
34
|
-
await sdkWebhook.deleteEndpoint(config.api_key, orgId, id);
|
|
35
|
-
success(`Webhook ${id} deleted`);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export async function delivery(id: string, flags: Record<string, string | boolean>) {
|
|
39
|
-
const config = requireConfig();
|
|
40
|
-
const orgId = (flags.org as string) || config.default_org;
|
|
41
|
-
if (!orgId || !id) error("Missing required arguments.\nUsage: myapi webhook delivery <id> --org <id>\n(Or set defaults via: myapi config set-org <id>)");
|
|
42
|
-
|
|
43
|
-
const res = await sdkWebhook.getDelivery(config.api_key, orgId, id);
|
|
44
|
-
printJson(res);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export async function run(subcommand: string | undefined, args: string[], flags: Record<string, string | boolean>) {
|
|
48
|
-
if (!subcommand || (flags.help && !subcommand)) {
|
|
49
|
-
info('Usage: myapi webhook <subcommand>\n\nSubcommands:\n list List all inbound webhook endpoints\n create Create a new endpoint to receive data (returns an inbound URL)\n delete Delete a webhook endpoint\n delivery Inspect a specific webhook delivery (headers, payload, status)\n\nNote: All webhook commands require the --org <id> flag.');
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
if (flags.help) {
|
|
54
|
-
if (subcommand === 'list') info('Usage: myapi webhook list --org <id> [--json]\n\nLists all webhook endpoints for the organization, including their IDs and inbound slugs.');
|
|
55
|
-
else if (subcommand === 'create') info('Usage: myapi webhook create --name <name> [--description <desc>] --org <id>\n\nCreates a new inbound webhook endpoint. Returns the unique inbound URL to give to third parties.');
|
|
56
|
-
else if (subcommand === 'delete') info('Usage: myapi webhook delete <id> --org <id>\n\nPermanently deletes the specified webhook endpoint.');
|
|
57
|
-
else if (subcommand === 'delivery') info('Usage: myapi webhook delivery <delivery_id> --org <id>\n\nRetrieves the exact HTTP headers, JSON payload, and processing status of a specific received webhook. Useful for debugging inbound data.');
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
if (subcommand === 'list') await list(flags);
|
|
62
|
-
else if (subcommand === 'create') await create(flags);
|
|
63
|
-
else if (subcommand === 'delete') await del(args[0], flags);
|
|
64
|
-
else if (subcommand === 'delivery') await delivery(args[0], flags);
|
|
65
|
-
else error(`Unknown subcommand: ${subcommand}. Run "myapi webhook --help" for a list of valid subcommands.`);
|
|
66
|
-
}
|
package/src/commands/workflow.ts
DELETED
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
import { workflow as sdkWorkflow } from '@myapihq/sdk';
|
|
2
|
-
import { requireConfig } from '../config.js';
|
|
3
|
-
import { success, error, printTable, info, printJson } from '../output.js';
|
|
4
|
-
|
|
5
|
-
export async function list(flags: Record<string, string | boolean>) {
|
|
6
|
-
const config = requireConfig();
|
|
7
|
-
const orgId = (flags.org as string) || config.default_org;
|
|
8
|
-
if (!orgId) error("Missing required arguments.\nUsage: myapi workflow list --org <id>\n(Or set defaults via: myapi config set-org <id>)");
|
|
9
|
-
|
|
10
|
-
const workflows = await sdkWorkflow.listWorkflows(config.api_key, orgId);
|
|
11
|
-
if (flags.json) printJson(workflows);
|
|
12
|
-
else printTable(workflows as unknown as Record<string, unknown>[]);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export async function create(flags: Record<string, string | boolean>) {
|
|
16
|
-
const config = requireConfig();
|
|
17
|
-
const orgId = (flags.org as string) || config.default_org;
|
|
18
|
-
const name = flags.name as string;
|
|
19
|
-
const endpointId = flags['endpoint-id'] as string;
|
|
20
|
-
|
|
21
|
-
if (!orgId || !name || !endpointId || !flags.steps) {
|
|
22
|
-
error("Missing required arguments.\nUsage: myapi workflow create --name <name> --endpoint-id <id> --steps <json> --org <id>\n(Or set defaults via: myapi config set-org <id>)");
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
let steps;
|
|
26
|
-
try {
|
|
27
|
-
steps = JSON.parse(flags.steps as string);
|
|
28
|
-
} catch (err) {
|
|
29
|
-
error("Invalid JSON for --steps");
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const wf = await sdkWorkflow.createWorkflow(config.api_key, orgId, {
|
|
33
|
-
name,
|
|
34
|
-
trigger_config: { endpoint_id: endpointId },
|
|
35
|
-
steps
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
await sdkWorkflow.enableWorkflow(config.api_key, orgId, wf.id);
|
|
39
|
-
success(`Workflow created and enabled! ID: ${wf.id}`);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export async function enable(id: string, flags: Record<string, string | boolean>) {
|
|
43
|
-
const config = requireConfig();
|
|
44
|
-
const orgId = (flags.org as string) || config.default_org;
|
|
45
|
-
if (!orgId || !id) error("Missing required arguments.\nUsage: myapi workflow enable <id> --org <id>\n(Or set defaults via: myapi config set-org <id>)");
|
|
46
|
-
|
|
47
|
-
await sdkWorkflow.enableWorkflow(config.api_key, orgId, id);
|
|
48
|
-
success(`Workflow ${id} enabled`);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export async function disable(id: string, flags: Record<string, string | boolean>) {
|
|
52
|
-
const config = requireConfig();
|
|
53
|
-
const orgId = (flags.org as string) || config.default_org;
|
|
54
|
-
if (!orgId || !id) error("Missing required arguments.\nUsage: myapi workflow disable <id> --org <id>\n(Or set defaults via: myapi config set-org <id>)");
|
|
55
|
-
|
|
56
|
-
await sdkWorkflow.disableWorkflow(config.api_key, orgId, id);
|
|
57
|
-
success(`Disabled workflow ${id}`);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export async function del(id: string, flags: Record<string, string | boolean>) {
|
|
61
|
-
const config = requireConfig();
|
|
62
|
-
const orgId = (flags.org as string) || config.default_org;
|
|
63
|
-
if (!orgId || !id) error("Missing required arguments.\nUsage: myapi workflow delete <id> --org <id>\n(Or set defaults via: myapi config set-org <id>)");
|
|
64
|
-
|
|
65
|
-
await sdkWorkflow.deleteWorkflow(config.api_key, orgId, id);
|
|
66
|
-
success(`Deleted workflow ${id}`);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export async function runs(id: string, flags: Record<string, string | boolean>) {
|
|
70
|
-
const config = requireConfig();
|
|
71
|
-
const orgId = (flags.org as string) || config.default_org;
|
|
72
|
-
if (!orgId || !id) error("Missing required arguments.\nUsage: myapi workflow runs <id> --org <id>\n(Or set defaults via: myapi config set-org <id>)");
|
|
73
|
-
|
|
74
|
-
const wRuns = await sdkWorkflow.listWorkflowRuns(config.api_key, orgId, id);
|
|
75
|
-
if (flags.json) printJson(wRuns);
|
|
76
|
-
else printTable(wRuns as unknown as Record<string, unknown>[]);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
export async function run(subcommand: string | undefined, args: string[], flags: Record<string, string | boolean>) {
|
|
80
|
-
if (!subcommand || (flags.help && !subcommand)) {
|
|
81
|
-
info('Usage: myapi workflow <subcommand>\n\nSubcommands:\n list List all workflows\n create Create and enable a new workflow\n enable Enable a workflow\n disable Disable a workflow\n delete Delete a workflow\n runs List recent executions (runs) of a workflow\n\nNote: All workflow commands require the --org <id> flag.');
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
if (flags.help) {
|
|
86
|
-
if (subcommand === 'list') info('Usage: myapi workflow list --org <id> [--json]\n\nLists all workflows in your organization, showing their ID, name, status, and attached webhook endpoint.');
|
|
87
|
-
else if (subcommand === 'create') info('Usage: myapi workflow create --name <name> --endpoint-id <id> --steps <json_array> --org <id>\n\nCreates a new webhook-triggered workflow and immediately enables it.\n\nArguments:\n --name A friendly name for your workflow.\n --endpoint-id The UUID of the my-webhook-api endpoint that will trigger this workflow.\n --steps A raw JSON array defining the actions to take when triggered.\n\nExample Steps Payload:\n \'[{"type": "send_email", "from": "hello@example.com", "to": "{{payload.user.email}}", "subject": "Welcome!", "template_id": "abc-123"}]\n \'[{"type": "slack_message", "webhook_url": "https://hooks.slack.com/...", "text": "New lead: {{payload.name}}"}]\'');
|
|
88
|
-
else if (subcommand === 'enable') info('Usage: myapi workflow enable <id> --org <id>\n\nActivates a disabled workflow so it begins listening to its webhook trigger again.');
|
|
89
|
-
else if (subcommand === 'disable') info('Usage: myapi workflow disable <id> --org <id>\n\nPauses a workflow. The attached webhook will still accept data, but the workflow steps will not execute.');
|
|
90
|
-
else if (subcommand === 'delete') info('Usage: myapi workflow delete <id> --org <id>\n\nDeletes the workflow permanently.');
|
|
91
|
-
else if (subcommand === 'runs') info('Usage: myapi workflow runs <workflow_id> --org <id> [--json]\n\nLists the 100 most recent executions of the specified workflow, including completion status and any error messages.');
|
|
92
|
-
return;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
if (subcommand === 'list') await list(flags);
|
|
96
|
-
else if (subcommand === 'create') await create(flags);
|
|
97
|
-
else if (subcommand === 'enable') await enable(args[0], flags);
|
|
98
|
-
else if (subcommand === 'disable') await disable(args[0], flags);
|
|
99
|
-
else if (subcommand === 'delete') await del(args[0], flags);
|
|
100
|
-
else if (subcommand === 'runs') await runs(args[0], flags);
|
|
101
|
-
else error(`Unknown subcommand: ${subcommand}. Run "myapi workflow --help" for a list of valid subcommands.`);
|
|
102
|
-
}
|
package/src/config.ts
DELETED
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
import * as fs from 'fs';
|
|
2
|
-
import * as path from 'path';
|
|
3
|
-
import * as os from 'os';
|
|
4
|
-
|
|
5
|
-
export interface AccountEntry {
|
|
6
|
-
api_key: string;
|
|
7
|
-
account_id: string;
|
|
8
|
-
email?: string;
|
|
9
|
-
default_org?: string;
|
|
10
|
-
default_funnel?: string;
|
|
11
|
-
default_domain?: string;
|
|
12
|
-
is_anonymous?: boolean;
|
|
13
|
-
skills_installed?: boolean;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
// Flat interface used by all command files — represents the active account.
|
|
17
|
-
export interface Config extends AccountEntry {
|
|
18
|
-
autocomplete_setup?: boolean;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export interface FullConfig {
|
|
22
|
-
active: number;
|
|
23
|
-
accounts: AccountEntry[];
|
|
24
|
-
autocomplete_setup?: boolean;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export const CONFIG_DIR = path.join(os.homedir(), '.myapi');
|
|
28
|
-
export const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
|
|
29
|
-
|
|
30
|
-
function ensureDir() {
|
|
31
|
-
if (!fs.existsSync(CONFIG_DIR)) fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function readRaw(): any {
|
|
35
|
-
try {
|
|
36
|
-
if (fs.existsSync(CONFIG_FILE)) return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf-8'));
|
|
37
|
-
} catch { /* ignore */ }
|
|
38
|
-
return null;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function isFullConfig(raw: any): raw is FullConfig {
|
|
42
|
-
return raw && Array.isArray(raw.accounts);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Migrate a flat (legacy) config to the new multi-account shape.
|
|
46
|
-
function migrate(raw: any): FullConfig {
|
|
47
|
-
const { autocomplete_setup, ...account } = raw;
|
|
48
|
-
return { active: 0, accounts: [account as AccountEntry], autocomplete_setup };
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export function loadFullConfig(): FullConfig | null {
|
|
52
|
-
const raw = readRaw();
|
|
53
|
-
if (!raw) return null;
|
|
54
|
-
return isFullConfig(raw) ? raw : migrate(raw);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// loadConfig returns the active account merged with globals — unchanged interface for all callers.
|
|
58
|
-
export function loadConfig(): Config | null {
|
|
59
|
-
const envKey = process.env.MYAPI_API_KEY || process.env.MYAPI_KEY;
|
|
60
|
-
const full = loadFullConfig();
|
|
61
|
-
|
|
62
|
-
if (!full && envKey) return { api_key: envKey, account_id: '' };
|
|
63
|
-
if (!full) return null;
|
|
64
|
-
|
|
65
|
-
const active = full.accounts[full.active] ?? full.accounts[0];
|
|
66
|
-
if (!active) return null;
|
|
67
|
-
|
|
68
|
-
const config: Config = {
|
|
69
|
-
...active,
|
|
70
|
-
autocomplete_setup: full.autocomplete_setup,
|
|
71
|
-
};
|
|
72
|
-
if (envKey) config.api_key = envKey;
|
|
73
|
-
return config;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export function saveConfig(config: Config): void {
|
|
77
|
-
ensureDir();
|
|
78
|
-
const full = loadFullConfig() ?? { active: 0, accounts: [] };
|
|
79
|
-
const { autocomplete_setup, ...account } = config;
|
|
80
|
-
if (full.accounts.length === 0) full.accounts.push(account as AccountEntry);
|
|
81
|
-
else full.accounts[full.active] = account as AccountEntry;
|
|
82
|
-
if (autocomplete_setup !== undefined) full.autocomplete_setup = autocomplete_setup;
|
|
83
|
-
fs.writeFileSync(CONFIG_FILE, JSON.stringify(full, null, 2), { mode: 0o600 });
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
export function addAccount(account: AccountEntry): number {
|
|
87
|
-
ensureDir();
|
|
88
|
-
const full = loadFullConfig() ?? { active: 0, accounts: [] };
|
|
89
|
-
// Replace if same account_id already exists.
|
|
90
|
-
const existing = full.accounts.findIndex(a => a.account_id === account.account_id);
|
|
91
|
-
if (existing >= 0) {
|
|
92
|
-
full.accounts[existing] = account;
|
|
93
|
-
full.active = existing;
|
|
94
|
-
} else {
|
|
95
|
-
full.accounts.push(account);
|
|
96
|
-
full.active = full.accounts.length - 1;
|
|
97
|
-
}
|
|
98
|
-
fs.writeFileSync(CONFIG_FILE, JSON.stringify(full, null, 2), { mode: 0o600 });
|
|
99
|
-
return full.active;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
export function switchAccount(index: number): boolean {
|
|
103
|
-
const full = loadFullConfig();
|
|
104
|
-
if (!full || index < 0 || index >= full.accounts.length) return false;
|
|
105
|
-
full.active = index;
|
|
106
|
-
fs.writeFileSync(CONFIG_FILE, JSON.stringify(full, null, 2), { mode: 0o600 });
|
|
107
|
-
return true;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
export function listAccounts(): Array<AccountEntry & { index: number; active: boolean }> {
|
|
111
|
-
const full = loadFullConfig();
|
|
112
|
-
if (!full) return [];
|
|
113
|
-
return full.accounts.map((a, i) => ({ ...a, index: i, active: i === full.active }));
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
export function requireConfig(): Config {
|
|
117
|
-
const config = loadConfig();
|
|
118
|
-
if (!config || !config.api_key) {
|
|
119
|
-
console.error("No API key found. Provide MYAPI_KEY env var or run: myapi auth setup");
|
|
120
|
-
process.exit(1);
|
|
121
|
-
}
|
|
122
|
-
return config;
|
|
123
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,200 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// manually maintained — do not regenerate from scripts/generate-indexes.js
|
|
3
|
-
import { parseArgs } from './utils.js';
|
|
4
|
-
import { error, info, success } from './output.js';
|
|
5
|
-
import { loadConfig } from './config.js';
|
|
6
|
-
import { MyApiError } from '@myapihq/sdk';
|
|
7
|
-
import * as fs from 'fs';
|
|
8
|
-
|
|
9
|
-
const pkgPath = new URL('../package.json', import.meta.url);
|
|
10
|
-
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
|
11
|
-
import * as keysCmd from './commands/keys.js';
|
|
12
|
-
import * as billingCmd from './commands/billing.js';
|
|
13
|
-
import * as orgCmd from './commands/org.js';
|
|
14
|
-
import * as setupCmd from './commands/setup.js';
|
|
15
|
-
import * as updateCmd from './commands/update.js';
|
|
16
|
-
import * as domainCmd from './commands/domain.js';
|
|
17
|
-
import * as funnelCmd from './commands/funnel.js';
|
|
18
|
-
import * as authCmd from './commands/auth.js';
|
|
19
|
-
import * as configCmd from './commands/config.js';
|
|
20
|
-
|
|
21
|
-
const ERROR_MESSAGES: Record<string, string> = {
|
|
22
|
-
DOMAIN_NOT_FOUND: 'Domain not found.',
|
|
23
|
-
INVALID_DOMAIN: 'Invalid domain name.',
|
|
24
|
-
ORG_NOT_FOUND: 'Organization not found.',
|
|
25
|
-
org_not_found: 'Organization not found.',
|
|
26
|
-
FUNNEL_NOT_FOUND: 'Funnel not found.',
|
|
27
|
-
funnel_not_found: 'Funnel not found.',
|
|
28
|
-
db_error: 'Resource not found or invalid ID.',
|
|
29
|
-
NOT_FOUND: 'Resource not found.',
|
|
30
|
-
FORBIDDEN: 'You do not have permission to perform this action.',
|
|
31
|
-
RATE_LIMITED: 'Too many requests. Please wait a moment and try again.',
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
function friendlyError(code: string): string {
|
|
35
|
-
return ERROR_MESSAGES[code] || code;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
async function main() {
|
|
39
|
-
const updatePromise = updateCmd.checkForUpdate(pkg.version).catch(() => {});
|
|
40
|
-
|
|
41
|
-
const { args, flags } = parseArgs(process.argv.slice(2));
|
|
42
|
-
|
|
43
|
-
if (flags.version || flags.v || flags.V) {
|
|
44
|
-
const [latest] = await Promise.all([updateCmd.latestVersion(), updatePromise]);
|
|
45
|
-
const updateNote = latest && updateCmd.isNewer(latest, pkg.version)
|
|
46
|
-
? ` (update available: ${latest})`
|
|
47
|
-
: '';
|
|
48
|
-
info(`myapi ${pkg.version}${updateNote}`);
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
if (flags.help && args.length === 0) {
|
|
53
|
-
printHelp();
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
if (args.length === 0) {
|
|
58
|
-
const config = loadConfig();
|
|
59
|
-
if (!config?.api_key) {
|
|
60
|
-
info('No account found. Run: myapi auth setup');
|
|
61
|
-
info('');
|
|
62
|
-
}
|
|
63
|
-
printHelp();
|
|
64
|
-
await updatePromise;
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const [command, subcommand, ...restArgs] = args;
|
|
69
|
-
try {
|
|
70
|
-
switch (command) {
|
|
71
|
-
case 'auth':
|
|
72
|
-
if (!subcommand || (flags.help && !subcommand)) {
|
|
73
|
-
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\n link [email] Attach an email to your anonymous account (upgrades it to registered)\n If the email already has an account, signs you into it as a second session\n switch [index] Switch between accounts\n config Manage CLI defaults (org_id, domain…)\n install-skills Install the MyAPI skills pack\n api-keys Manage API keys');
|
|
74
|
-
break;
|
|
75
|
-
}
|
|
76
|
-
if (subcommand === 'setup') await setupCmd.setup(flags);
|
|
77
|
-
else if (subcommand === 'import-key') await setupCmd.importKey(restArgs[0], flags);
|
|
78
|
-
else if (subcommand === 'whoami') await authCmd.whoami(flags);
|
|
79
|
-
else if (subcommand === 'link') await authCmd.link(flags, restArgs[0]);
|
|
80
|
-
else if (subcommand === 'switch') await authCmd.switchCmd(flags, restArgs[0]);
|
|
81
|
-
else if (subcommand === 'install-skills') {
|
|
82
|
-
if (flags.help) {
|
|
83
|
-
info('Usage: myapi auth install-skills\n\nInstalls the MyAPI skills pack for Claude, Gemini, and Cursor agents.');
|
|
84
|
-
break;
|
|
85
|
-
}
|
|
86
|
-
await setupCmd.installSkills();
|
|
87
|
-
success('› Skills installed.');
|
|
88
|
-
} else if (subcommand === 'config') await configCmd.run(restArgs[0], restArgs.slice(1), flags);
|
|
89
|
-
else if (subcommand === 'api-keys') {
|
|
90
|
-
if (flags.help && !restArgs[0]) {
|
|
91
|
-
info('Usage: myapi auth api-keys <subcommand>\n\nSubcommands:\n list List all API keys\n create Create a new API key\n revoke <id> Revoke an API key by ID');
|
|
92
|
-
break;
|
|
93
|
-
}
|
|
94
|
-
if (!restArgs[0]) { info('Usage: myapi auth api-keys <list|create|revoke>'); break; }
|
|
95
|
-
if (restArgs[0] === 'create') await keysCmd.createNew(flags);
|
|
96
|
-
else if (restArgs[0] === 'list') await keysCmd.list(flags);
|
|
97
|
-
else if (restArgs[0] === 'revoke') await keysCmd.revoke(restArgs[1], flags);
|
|
98
|
-
} else info('Unknown subcommand. Run: myapi auth --help');
|
|
99
|
-
break;
|
|
100
|
-
case 'update':
|
|
101
|
-
await updateCmd.update(flags);
|
|
102
|
-
break;
|
|
103
|
-
case 'org':
|
|
104
|
-
if (!subcommand || (flags.help && !subcommand)) {
|
|
105
|
-
info('Usage: myapi org <subcommand>\n\nSubcommands:\n list List organizations\n create Create an organization (use --yes to auto-set it as your default org and funnel)\n get Get details of an organization\n delete Delete an organization\n import Extract org from domain');
|
|
106
|
-
break;
|
|
107
|
-
}
|
|
108
|
-
if (subcommand === 'list') await orgCmd.list(flags);
|
|
109
|
-
else if (subcommand === 'create') await orgCmd.create(flags);
|
|
110
|
-
else if (subcommand === 'get') await orgCmd.get(restArgs[0], flags);
|
|
111
|
-
else if (subcommand === 'delete') await orgCmd.del(restArgs[0], flags);
|
|
112
|
-
else if (subcommand === 'import') await orgCmd.importOrg(restArgs, flags);
|
|
113
|
-
else printHelp();
|
|
114
|
-
break;
|
|
115
|
-
case 'billing':
|
|
116
|
-
if (!subcommand || (flags.help && !subcommand)) {
|
|
117
|
-
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');
|
|
118
|
-
break;
|
|
119
|
-
}
|
|
120
|
-
if (subcommand === 'balance') await billingCmd.balance(flags);
|
|
121
|
-
else if (subcommand === 'history') await billingCmd.history(flags);
|
|
122
|
-
else if (subcommand === 'topup') await billingCmd.topup(restArgs[0], flags);
|
|
123
|
-
else if (subcommand === 'setup') await billingCmd.setup(flags);
|
|
124
|
-
else printHelp();
|
|
125
|
-
break;
|
|
126
|
-
case 'domain':
|
|
127
|
-
await domainCmd.run(subcommand, restArgs, flags);
|
|
128
|
-
break;
|
|
129
|
-
case 'funnel':
|
|
130
|
-
await funnelCmd.run(subcommand, restArgs, flags);
|
|
131
|
-
break;
|
|
132
|
-
// Convenience aliases
|
|
133
|
-
case 'setup':
|
|
134
|
-
await setupCmd.setup(flags);
|
|
135
|
-
break;
|
|
136
|
-
case 'whoami':
|
|
137
|
-
await authCmd.whoami(flags);
|
|
138
|
-
break;
|
|
139
|
-
case 'keys':
|
|
140
|
-
if (!subcommand) { info('Usage: myapi keys <list|create|revoke>'); break; }
|
|
141
|
-
if (subcommand === 'create') await keysCmd.createNew(flags);
|
|
142
|
-
else if (subcommand === 'list') await keysCmd.list(flags);
|
|
143
|
-
else if (subcommand === 'revoke') await keysCmd.revoke(restArgs[0], flags);
|
|
144
|
-
break;
|
|
145
|
-
case 'config':
|
|
146
|
-
await configCmd.run(subcommand, restArgs, { ...flags, _via: 'config' });
|
|
147
|
-
break;
|
|
148
|
-
case 'help':
|
|
149
|
-
printHelp();
|
|
150
|
-
break;
|
|
151
|
-
default:
|
|
152
|
-
error(`Unknown command: ${command}. Run "myapi" for available commands.`);
|
|
153
|
-
}
|
|
154
|
-
} catch (err: any) {
|
|
155
|
-
if (err instanceof MyApiError) {
|
|
156
|
-
if (err.status === 401) error('Invalid API key. Run: myapi auth setup');
|
|
157
|
-
else if (err.status === 402) {
|
|
158
|
-
if (err.code === 'REGISTRATION_REQUIRED' || err.code === 'UPGRADE_REQUIRED') error('A verified email is required. Run: myapi auth link');
|
|
159
|
-
else if (err.code === 'NO_PAYMENT_METHOD') error('No payment method on file. Run: myapi billing setup');
|
|
160
|
-
else error(`Insufficient balance. Run: myapi billing topup <amount>`);
|
|
161
|
-
}
|
|
162
|
-
else error(friendlyError(err.code) || err.message);
|
|
163
|
-
} else {
|
|
164
|
-
error(err.message || (typeof err === 'object' ? JSON.stringify(err) : String(err)));
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
function printHelp() {
|
|
170
|
-
const config = loadConfig();
|
|
171
|
-
const quickStart = config?.api_key
|
|
172
|
-
? `Quick start:
|
|
173
|
-
echo '<h1>Hello!</h1>' | myapi funnel push /`
|
|
174
|
-
: `Quick start:
|
|
175
|
-
myapi auth setup --help`;
|
|
176
|
-
info(`myapi - MyAPI command-line interface
|
|
177
|
-
|
|
178
|
-
Usage: myapi <command> [subcommand] [args]
|
|
179
|
-
myapi --version
|
|
180
|
-
|
|
181
|
-
Commands:
|
|
182
|
-
auth Manage account · setup · whoami · link
|
|
183
|
-
billing Check balance and manage billing
|
|
184
|
-
org Manage organizations (tip: myapi org create "name" --yes to auto-set as default)
|
|
185
|
-
update Update CLI and skills to the latest version
|
|
186
|
-
domain Manage domain configurations
|
|
187
|
-
funnel Manage websites (publish pages, custom domains, funnels)
|
|
188
|
-
|
|
189
|
-
Aliases:
|
|
190
|
-
whoami → myapi auth whoami
|
|
191
|
-
keys → myapi auth api-keys
|
|
192
|
-
setup → myapi auth setup
|
|
193
|
-
config → myapi auth config
|
|
194
|
-
|
|
195
|
-
Run "myapi <command> --help" for subcommand help.
|
|
196
|
-
|
|
197
|
-
${quickStart}`);
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
main().catch(err => { error(err.message || (typeof err === 'object' ? JSON.stringify(err) : String(err))); });
|
package/src/output.ts
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
const useColor = process.stdout.isTTY && !process.env.NO_COLOR;
|
|
2
|
-
|
|
3
|
-
export function success(message: string): void {
|
|
4
|
-
console.log(useColor ? `\x1b[32m✓\x1b[0m ${message}` : `✓ ${message}`);
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export function error(message: string): never {
|
|
8
|
-
console.error(useColor ? `\x1b[31m✗\x1b[0m ${message}` : `✗ ${message}`);
|
|
9
|
-
process.exit(1);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function info(message: string): void {
|
|
13
|
-
console.log(message);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function printJson(data: unknown): void {
|
|
17
|
-
console.log(JSON.stringify(data, null, 2));
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function printTable(rows: Record<string, unknown>[]): void {
|
|
21
|
-
if (process.argv.includes('--json')) {
|
|
22
|
-
printJson(rows);
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
if (rows.length === 0) {
|
|
27
|
-
console.log("No data found.");
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const columns = Object.keys(rows[0]);
|
|
32
|
-
const colWidths = columns.map(col => {
|
|
33
|
-
return Math.max(
|
|
34
|
-
col.length,
|
|
35
|
-
...rows.map(row => String(row[col] ?? '').length)
|
|
36
|
-
);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
const printRow = (row: string[]) => {
|
|
40
|
-
console.log(row.map((cell, i) => cell.padEnd(colWidths[i] + 2)).join(''));
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
printRow(columns);
|
|
44
|
-
console.log(colWidths.map(w => '-'.repeat(w + 2)).join(''));
|
|
45
|
-
|
|
46
|
-
for (const row of rows) {
|
|
47
|
-
printRow(columns.map(col => String(row[col] ?? '')));
|
|
48
|
-
}
|
|
49
|
-
}
|
package/src/utils.ts
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
export function parseArgs(argv: string[]) {
|
|
2
|
-
const args: string[] = [];
|
|
3
|
-
const flags: Record<string, string | boolean> = {};
|
|
4
|
-
|
|
5
|
-
for (let i = 0; i < argv.length; i++) {
|
|
6
|
-
const arg = argv[i];
|
|
7
|
-
if (arg === '-h') {
|
|
8
|
-
flags['help'] = true;
|
|
9
|
-
} else if (arg === '-v') {
|
|
10
|
-
flags['version'] = true;
|
|
11
|
-
} else if (arg.startsWith('--')) {
|
|
12
|
-
if (arg.includes('=')) {
|
|
13
|
-
const [key, value] = arg.slice(2).split('=', 2);
|
|
14
|
-
flags[key] = value;
|
|
15
|
-
} else {
|
|
16
|
-
const next = argv[i + 1];
|
|
17
|
-
if (next && !next.startsWith('--')) {
|
|
18
|
-
flags[arg.slice(2)] = next;
|
|
19
|
-
i++;
|
|
20
|
-
} else {
|
|
21
|
-
flags[arg.slice(2)] = true;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
} else {
|
|
25
|
-
args.push(arg);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
return { args, flags };
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export function sleep(ms: number) {
|
|
33
|
-
return new Promise(resolve => setTimeout(resolve, ms));
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Formats an ISO/Go timestamp string to "YYYY-MM-DD HH:mm" (UTC).
|
|
38
|
-
* Strips Go's " +0000 UTC" suffix before parsing.
|
|
39
|
-
*/
|
|
40
|
-
export function formatDate(str: string): string {
|
|
41
|
-
const clean = str.replace(' +0000 UTC', 'Z');
|
|
42
|
-
const date = new Date(clean);
|
|
43
|
-
if (isNaN(date.getTime())) return str;
|
|
44
|
-
return date.toISOString().replace('T', ' ').slice(0, 16);
|
|
45
|
-
}
|
package/thank-you.html
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>Thank You</title>
|
|
7
|
-
<style>
|
|
8
|
-
body {
|
|
9
|
-
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
10
|
-
background-color: #f3f4f6;
|
|
11
|
-
color: #1f2937;
|
|
12
|
-
display: flex;
|
|
13
|
-
align-items: center;
|
|
14
|
-
justify-content: center;
|
|
15
|
-
height: 100vh;
|
|
16
|
-
margin: 0;
|
|
17
|
-
text-align: center;
|
|
18
|
-
}
|
|
19
|
-
.container {
|
|
20
|
-
background: white;
|
|
21
|
-
padding: 3rem;
|
|
22
|
-
border-radius: 1rem;
|
|
23
|
-
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
|
24
|
-
max-width: 400px;
|
|
25
|
-
width: 90%;
|
|
26
|
-
}
|
|
27
|
-
h1 {
|
|
28
|
-
margin-top: 0;
|
|
29
|
-
color: #4f46e5;
|
|
30
|
-
font-size: 2.25rem;
|
|
31
|
-
margin-bottom: 0.5rem;
|
|
32
|
-
}
|
|
33
|
-
p {
|
|
34
|
-
color: #6b7280;
|
|
35
|
-
line-height: 1.6;
|
|
36
|
-
margin-bottom: 0;
|
|
37
|
-
font-size: 1.125rem;
|
|
38
|
-
}
|
|
39
|
-
.icon {
|
|
40
|
-
width: 64px;
|
|
41
|
-
height: 64px;
|
|
42
|
-
color: #10b981;
|
|
43
|
-
margin-bottom: 1.5rem;
|
|
44
|
-
}
|
|
45
|
-
</style>
|
|
46
|
-
</head>
|
|
47
|
-
<body>
|
|
48
|
-
<div class="container">
|
|
49
|
-
<svg class="icon" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
|
50
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
|
51
|
-
</svg>
|
|
52
|
-
<h1>Thank You!</h1>
|
|
53
|
-
<p>We've received your request and will be in touch shortly.</p>
|
|
54
|
-
</div>
|
|
55
|
-
</body>
|
|
56
|
-
</html>
|