@myapihq/cli 1.0.37 → 1.0.40
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 +8 -0
- package/dist/commands/billing.js +15 -17
- package/dist/commands/domain.d.ts +1 -0
- package/dist/commands/domain.js +33 -13
- package/dist/commands/org.js +9 -4
- package/dist/index.js +10 -26
- package/dist/utils.d.ts +5 -0
- package/dist/utils.js +11 -0
- package/package.json +1 -1
- package/src/commands/auth.ts +8 -0
- package/src/commands/billing.ts +20 -21
- package/src/commands/domain.ts +33 -16
- package/src/commands/org.ts +14 -9
- package/src/index.ts +10 -22
- package/src/utils.ts +11 -0
package/dist/commands/auth.js
CHANGED
|
@@ -2,6 +2,7 @@ import * as readline from 'readline';
|
|
|
2
2
|
import { loadConfig, saveConfig, addAccount, switchAccount, listAccounts } from '../config.js';
|
|
3
3
|
import { info, success, error } from '../output.js';
|
|
4
4
|
import { installSkills } from './setup.js';
|
|
5
|
+
import { hq } from '@myapihq/sdk';
|
|
5
6
|
const API_BASE = process.env.MYAPI_API_BASE ?? 'https://api.myapihq.com';
|
|
6
7
|
function ask(rl, q) {
|
|
7
8
|
return new Promise(resolve => rl.question(q, resolve));
|
|
@@ -114,6 +115,13 @@ export async function whoami() {
|
|
|
114
115
|
info(`Org: ${config.default_org ?? '(none)'}`);
|
|
115
116
|
info(`Funnel: ${config.default_funnel ?? '(none)'}`);
|
|
116
117
|
info(`Type: ${config.is_anonymous ? 'anonymous' : 'registered'}`);
|
|
118
|
+
try {
|
|
119
|
+
const bal = await hq.getBalance(config.api_key);
|
|
120
|
+
info(`Balance: ${bal.balance_display} | Credits: ${bal.credits_display}`);
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
// Balance fetch is best-effort; don't fail whoami if it errors.
|
|
124
|
+
}
|
|
117
125
|
}
|
|
118
126
|
// myapi auth switch — switch between saved accounts.
|
|
119
127
|
export async function switchCmd() {
|
package/dist/commands/billing.js
CHANGED
|
@@ -2,6 +2,7 @@ import * as readline from 'readline';
|
|
|
2
2
|
import { hq } from '@myapihq/sdk';
|
|
3
3
|
import { requireConfig } from '../config.js';
|
|
4
4
|
import { success, error, printTable, info, printJson } from '../output.js';
|
|
5
|
+
import { formatDate } from '../utils.js';
|
|
5
6
|
export async function balance(flags) {
|
|
6
7
|
if (flags.help) {
|
|
7
8
|
info('Usage: myapi billing balance\n\nShows your current account balance, credits, and payment method status.');
|
|
@@ -10,6 +11,8 @@ export async function balance(flags) {
|
|
|
10
11
|
const config = requireConfig();
|
|
11
12
|
const result = await hq.getBalance(config.api_key);
|
|
12
13
|
const pm = result.has_payment_method ? 'yes' : 'no';
|
|
14
|
+
const accountType = config.is_anonymous ? 'anonymous' : `registered (${config.email ?? ''})`;
|
|
15
|
+
info(`Account: ${accountType}`);
|
|
13
16
|
info(`Balance: ${result.balance_display} | Credits: ${result.credits_display} | Payment method: ${pm}`);
|
|
14
17
|
}
|
|
15
18
|
export async function history(flags) {
|
|
@@ -23,17 +26,16 @@ export async function history(flags) {
|
|
|
23
26
|
printJson(items);
|
|
24
27
|
return;
|
|
25
28
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
});
|
|
29
|
+
if (items.length === 0) {
|
|
30
|
+
info('No transactions yet.');
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const formattedItems = items.map(item => ({
|
|
34
|
+
Type: item.type || 'unknown',
|
|
35
|
+
Amount: item.amount_display,
|
|
36
|
+
Status: item.status ? item.status.charAt(0).toUpperCase() + item.status.slice(1) : '',
|
|
37
|
+
Date: formatDate(item.created_at),
|
|
38
|
+
}));
|
|
37
39
|
printTable(formattedItems);
|
|
38
40
|
}
|
|
39
41
|
export async function topup(amountStr, flags) {
|
|
@@ -41,13 +43,9 @@ export async function topup(amountStr, flags) {
|
|
|
41
43
|
info('Usage: myapi billing topup <amount>\n\nAmount is in whole dollars (e.g. "10" charges $10).\nUse --yes to skip confirmation.\nExample: myapi billing topup 10');
|
|
42
44
|
return;
|
|
43
45
|
}
|
|
44
|
-
if (!amountStr) {
|
|
45
|
-
error("Missing amount. Usage: myapi billing topup <amount>\nExample: myapi billing topup 10");
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
46
|
const amount = Math.round(parseFloat(amountStr));
|
|
49
|
-
if (isNaN(amount) || amount <= 0) {
|
|
50
|
-
error("
|
|
47
|
+
if (!amountStr || isNaN(amount) || amount <= 0) {
|
|
48
|
+
error("Amount must be a positive whole number of dollars (e.g. myapi billing topup 10)");
|
|
51
49
|
return;
|
|
52
50
|
}
|
|
53
51
|
if (!flags.yes && !flags.y && amount >= 50) {
|
|
@@ -4,6 +4,7 @@ export declare function importDomain(domainArg: string, flags: Record<string, st
|
|
|
4
4
|
export declare function list(flags: Record<string, string | boolean>): Promise<void>;
|
|
5
5
|
export declare function assign(domainArg: string, flags: Record<string, string | boolean>): Promise<void>;
|
|
6
6
|
export declare function unassign(domainArg: string, flags: Record<string, string | boolean>): Promise<void>;
|
|
7
|
+
export declare function status(domainArg: string, flags: Record<string, string | boolean>): Promise<void>;
|
|
7
8
|
export declare function settings(domainArg: string, flags: Record<string, string | boolean>): Promise<void>;
|
|
8
9
|
export declare function updateSettings(domainArg: string, flags: Record<string, string | boolean>): Promise<void>;
|
|
9
10
|
export declare function run(subcommand: string | undefined, args: string[], flags: Record<string, string | boolean>): Promise<void>;
|
package/dist/commands/domain.js
CHANGED
|
@@ -6,13 +6,14 @@ export async function check(domainArg, flags) {
|
|
|
6
6
|
const orgId = flags.org || config.default_org;
|
|
7
7
|
const domain = domainArg || config.default_domain;
|
|
8
8
|
if (!orgId || !domain)
|
|
9
|
-
error("Missing required arguments.\nUsage: myapi domain check <domain> --org <id>\n(Or set defaults via: myapi config set-org <id> / set-domain <domain>)");
|
|
9
|
+
error("Missing required arguments.\nUsage: myapi domain check <domain> --org <id>\n(Or set defaults via: myapi auth config set-org <id> / set-domain <domain>)");
|
|
10
10
|
const res = await sdkDomain.checkDomain(config.api_key, orgId, domain);
|
|
11
11
|
if (res.available) {
|
|
12
|
-
|
|
12
|
+
const price = res.price_display || `$${(res.price_cents / 100).toFixed(2)}`;
|
|
13
|
+
info(`${domain} — Available ✓ ${price}/yr`);
|
|
13
14
|
}
|
|
14
15
|
else {
|
|
15
|
-
info(
|
|
16
|
+
info(`${domain} — ${res.message || 'Not available'} ✗`);
|
|
16
17
|
}
|
|
17
18
|
}
|
|
18
19
|
export async function register(domainArg, flags) {
|
|
@@ -20,7 +21,7 @@ export async function register(domainArg, flags) {
|
|
|
20
21
|
const orgId = flags.org || config.default_org;
|
|
21
22
|
const domain = domainArg || config.default_domain;
|
|
22
23
|
if (!orgId || !domain)
|
|
23
|
-
error("Missing required arguments.\nUsage: myapi domain register <domain> --org <id> [--years <num>]\n(Or set defaults via: myapi config set-org <id> / set-domain <domain>)");
|
|
24
|
+
error("Missing required arguments.\nUsage: myapi domain register <domain> --org <id> [--years <num>]\n(Or set defaults via: myapi auth config set-org <id> / set-domain <domain>)");
|
|
24
25
|
const years = parseInt(flags.years) || 1;
|
|
25
26
|
const res = await sdkDomain.registerDomain(config.api_key, orgId, domain, years);
|
|
26
27
|
success(`Registered ${domain}!\n${JSON.stringify(res, null, 2)}`);
|
|
@@ -30,7 +31,7 @@ export async function importDomain(domainArg, flags) {
|
|
|
30
31
|
const orgId = flags.org || config.default_org;
|
|
31
32
|
const domain = domainArg || config.default_domain;
|
|
32
33
|
if (!orgId || !domain)
|
|
33
|
-
error("Missing required arguments.\nUsage: myapi domain import <domain> --org <id> [--namecheap-user <user> --namecheap-key <key>]\n(Or set defaults via: myapi config set-org <id> / set-domain <domain>)");
|
|
34
|
+
error("Missing required arguments.\nUsage: myapi domain import <domain> --org <id> [--namecheap-user <user> --namecheap-key <key>]\n(Or set defaults via: myapi auth config set-org <id> / set-domain <domain>)");
|
|
34
35
|
const payload = { domain };
|
|
35
36
|
if (flags['namecheap-user'])
|
|
36
37
|
payload.namecheap_api_user = flags['namecheap-user'];
|
|
@@ -43,7 +44,7 @@ export async function list(flags) {
|
|
|
43
44
|
const config = requireConfig();
|
|
44
45
|
const orgId = flags.org || config.default_org;
|
|
45
46
|
if (!orgId)
|
|
46
|
-
error("Missing required arguments.\nUsage: myapi domain list --org <id> [--filter=all|unassigned|org]\n(Or set a default org via: myapi config set-org <id>)");
|
|
47
|
+
error("Missing required arguments.\nUsage: myapi domain list --org <id> [--filter=all|unassigned|org]\n(Or set a default org via: myapi auth config set-org <id>)");
|
|
47
48
|
const filter = flags.filter;
|
|
48
49
|
const domains = await sdkDomain.listDomains(config.api_key, orgId, filter);
|
|
49
50
|
printTable(domains);
|
|
@@ -54,8 +55,8 @@ export async function assign(domainArg, flags) {
|
|
|
54
55
|
const domain = domainArg || config.default_domain;
|
|
55
56
|
const targetOrgId = flags.target;
|
|
56
57
|
if (!orgId || !domain || !targetOrgId)
|
|
57
|
-
error("Missing required arguments.\nUsage: myapi domain assign <domain> --org <id> --target <target_org_id>\n(Or set defaults via: myapi config set-org <id> / set-domain <domain>)");
|
|
58
|
-
|
|
58
|
+
error("Missing required arguments.\nUsage: myapi domain assign <domain> --org <id> --target <target_org_id>\n(Or set defaults via: myapi auth config set-org <id> / set-domain <domain>)");
|
|
59
|
+
await sdkDomain.assignDomain(config.api_key, orgId, domain, targetOrgId);
|
|
59
60
|
success(`Assigned ${domain} to org ${targetOrgId}`);
|
|
60
61
|
}
|
|
61
62
|
export async function unassign(domainArg, flags) {
|
|
@@ -63,16 +64,31 @@ export async function unassign(domainArg, flags) {
|
|
|
63
64
|
const orgId = flags.org || config.default_org;
|
|
64
65
|
const domain = domainArg || config.default_domain;
|
|
65
66
|
if (!orgId || !domain)
|
|
66
|
-
error("Missing required arguments.\nUsage: myapi domain unassign <domain> --org <id>\n(Or set defaults via: myapi config set-org <id> / set-domain <domain>)");
|
|
67
|
-
|
|
67
|
+
error("Missing required arguments.\nUsage: myapi domain unassign <domain> --org <id>\n(Or set defaults via: myapi auth config set-org <id> / set-domain <domain>)");
|
|
68
|
+
await sdkDomain.unassignDomain(config.api_key, orgId, domain);
|
|
68
69
|
success(`Unassigned ${domain} from org ${orgId}`);
|
|
69
70
|
}
|
|
71
|
+
export async function status(domainArg, flags) {
|
|
72
|
+
const config = requireConfig();
|
|
73
|
+
const orgId = flags.org || config.default_org;
|
|
74
|
+
const domain = domainArg || config.default_domain;
|
|
75
|
+
if (!orgId || !domain)
|
|
76
|
+
error("Missing required arguments.\nUsage: myapi domain status <domain> --org <id>\n(Or set defaults via: myapi auth config set-org <id> / set-domain <domain>)");
|
|
77
|
+
const res = await sdkDomain.getDomainStatus(config.api_key, orgId, domain);
|
|
78
|
+
const display = {
|
|
79
|
+
domain: res.domain,
|
|
80
|
+
status: res.status,
|
|
81
|
+
};
|
|
82
|
+
if (res.expires_at)
|
|
83
|
+
display.expires_at = res.expires_at;
|
|
84
|
+
printJson(display);
|
|
85
|
+
}
|
|
70
86
|
export async function settings(domainArg, flags) {
|
|
71
87
|
const config = requireConfig();
|
|
72
88
|
const orgId = flags.org || config.default_org;
|
|
73
89
|
const domain = domainArg || config.default_domain;
|
|
74
90
|
if (!orgId || !domain)
|
|
75
|
-
error("Missing required arguments.\nUsage: myapi domain settings <domain> --org <id>\n(Or set defaults via: myapi config set-org <id> / set-domain <domain>)");
|
|
91
|
+
error("Missing required arguments.\nUsage: myapi domain settings <domain> --org <id>\n(Or set defaults via: myapi auth config set-org <id> / set-domain <domain>)");
|
|
76
92
|
const res = await sdkDomain.getDomainSettings(config.api_key, orgId, domain);
|
|
77
93
|
printJson(res);
|
|
78
94
|
}
|
|
@@ -81,7 +97,7 @@ export async function updateSettings(domainArg, flags) {
|
|
|
81
97
|
const orgId = flags.org || config.default_org;
|
|
82
98
|
const domain = domainArg || config.default_domain;
|
|
83
99
|
if (!orgId || !domain)
|
|
84
|
-
error("Missing required arguments.\nUsage: myapi domain update-settings <domain> --org <id> [--security=...] [--browser-check=...] [--purge-cache]\n(Or set defaults via: myapi config set-org <id> / set-domain <domain>)");
|
|
100
|
+
error("Missing required arguments.\nUsage: myapi domain update-settings <domain> --org <id> [--security=...] [--browser-check=...] [--purge-cache]\n(Or set defaults via: myapi auth config set-org <id> / set-domain <domain>)");
|
|
85
101
|
const payload = {};
|
|
86
102
|
if (flags.security)
|
|
87
103
|
payload.security_level = flags.security;
|
|
@@ -94,7 +110,7 @@ export async function updateSettings(domainArg, flags) {
|
|
|
94
110
|
}
|
|
95
111
|
export async function run(subcommand, args, flags) {
|
|
96
112
|
if (!subcommand || (flags.help && !subcommand)) {
|
|
97
|
-
info('Usage: myapi domain <subcommand>\n\nSubcommands:\n list List domains\n check Check domain availability\n register Register a domain\n import Import an existing domain\n assign Assign domain to org\n unassign Unassign domain from its current org\n settings Get domain settings\n update-settings Update domain settings\n\nNote: All domain commands require the --org <id> flag.');
|
|
113
|
+
info('Usage: myapi domain <subcommand>\n\nSubcommands:\n list List domains\n check Check domain availability\n register Register a domain\n import Import an existing domain\n assign Assign domain to org\n unassign Unassign domain from its current org\n status Get domain status\n settings Get domain settings\n update-settings Update domain settings\n\nNote: All domain commands require the --org <id> flag.');
|
|
98
114
|
return;
|
|
99
115
|
}
|
|
100
116
|
if (flags.help) {
|
|
@@ -110,6 +126,8 @@ export async function run(subcommand, args, flags) {
|
|
|
110
126
|
info('Usage: myapi domain assign <domain> --org <id> --target <target_org_id>\n\nAssigns a domain to a different organization.');
|
|
111
127
|
else if (subcommand === 'unassign')
|
|
112
128
|
info('Usage: myapi domain unassign <domain> --org <id>\n\nUnassigns a domain from its current organization.');
|
|
129
|
+
else if (subcommand === 'status')
|
|
130
|
+
info('Usage: myapi domain status <domain> --org <id>\n\nGets the registration status of a domain.');
|
|
113
131
|
else if (subcommand === 'settings')
|
|
114
132
|
info('Usage: myapi domain settings <domain> --org <id>\n\nGets the DNS settings and configuration for a domain.');
|
|
115
133
|
else if (subcommand === 'update-settings')
|
|
@@ -128,6 +146,8 @@ export async function run(subcommand, args, flags) {
|
|
|
128
146
|
await assign(args[0], flags);
|
|
129
147
|
else if (subcommand === 'unassign')
|
|
130
148
|
await unassign(args[0], flags);
|
|
149
|
+
else if (subcommand === 'status')
|
|
150
|
+
await status(args[0], flags);
|
|
131
151
|
else if (subcommand === 'settings')
|
|
132
152
|
await settings(args[0], flags);
|
|
133
153
|
else if (subcommand === 'update-settings')
|
package/dist/commands/org.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { hq } from '@myapihq/sdk';
|
|
2
2
|
import { requireConfig } from '../config.js';
|
|
3
|
-
import { success, error, printJson, info } from '../output.js';
|
|
4
|
-
import { sleep } from '../utils.js';
|
|
3
|
+
import { success, error, printTable, printJson, info } from '../output.js';
|
|
4
|
+
import { sleep, formatDate } from '../utils.js';
|
|
5
5
|
export async function create(flags) {
|
|
6
6
|
if (flags.help) {
|
|
7
7
|
info('Usage: myapi org create --name="My Org" [options]\n\nOptions:\n --name Organization name (required)\n --tagline Short tagline\n --description Detailed description\n --business-sector Sector (e.g. Technology)\n --logo-url URL to logo image');
|
|
@@ -29,12 +29,17 @@ export async function create(flags) {
|
|
|
29
29
|
}
|
|
30
30
|
export async function list(flags) {
|
|
31
31
|
if (flags.help) {
|
|
32
|
-
info('Usage: myapi org list\n\nLists all organizations in your account
|
|
32
|
+
info('Usage: myapi org list\n\nLists all organizations in your account.');
|
|
33
33
|
return;
|
|
34
34
|
}
|
|
35
35
|
const config = requireConfig();
|
|
36
36
|
const orgs = await hq.listOrgs(config.api_key);
|
|
37
|
-
|
|
37
|
+
const rows = orgs.map((o) => ({
|
|
38
|
+
id: o.id,
|
|
39
|
+
name: o.name,
|
|
40
|
+
created_at: o.created_at ? formatDate(o.created_at) : '',
|
|
41
|
+
}));
|
|
42
|
+
printTable(rows);
|
|
38
43
|
}
|
|
39
44
|
export async function get(id, flags) {
|
|
40
45
|
if (flags.help) {
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
//
|
|
2
|
+
// manually maintained — do not regenerate from scripts/generate-indexes.js
|
|
3
3
|
import { parseArgs } from './utils.js';
|
|
4
4
|
import { error, info, success } from './output.js';
|
|
5
5
|
import { loadConfig } from './config.js';
|
|
@@ -17,16 +17,15 @@ import * as funnelCmd from './commands/funnel.js';
|
|
|
17
17
|
import * as authCmd from './commands/auth.js';
|
|
18
18
|
import * as configCmd from './commands/config.js';
|
|
19
19
|
async function main() {
|
|
20
|
-
|
|
21
|
-
updateCmd.checkForUpdate(pkg.version).catch(() => { });
|
|
20
|
+
const updatePromise = updateCmd.checkForUpdate(pkg.version).catch(() => { });
|
|
22
21
|
const { args, flags } = parseArgs(process.argv.slice(2));
|
|
23
22
|
if (flags.version || flags.v) {
|
|
24
|
-
const latest = await updateCmd.latestVersion();
|
|
23
|
+
const [latest] = await Promise.all([updateCmd.latestVersion(), updatePromise]);
|
|
25
24
|
const updateNote = latest && updateCmd.isNewer(latest, pkg.version)
|
|
26
25
|
? ` (update available: ${latest})`
|
|
27
26
|
: '';
|
|
28
27
|
info(`myapi ${pkg.version}${updateNote}`);
|
|
29
|
-
|
|
28
|
+
return;
|
|
30
29
|
}
|
|
31
30
|
if (args.length === 0) {
|
|
32
31
|
const config = loadConfig();
|
|
@@ -35,7 +34,8 @@ async function main() {
|
|
|
35
34
|
info('');
|
|
36
35
|
}
|
|
37
36
|
printHelp();
|
|
38
|
-
|
|
37
|
+
await updatePromise;
|
|
38
|
+
return;
|
|
39
39
|
}
|
|
40
40
|
const [command, subcommand, ...restArgs] = args;
|
|
41
41
|
try {
|
|
@@ -77,20 +77,6 @@ async function main() {
|
|
|
77
77
|
case 'update':
|
|
78
78
|
await updateCmd.update();
|
|
79
79
|
break;
|
|
80
|
-
case 'keys':
|
|
81
|
-
if (!subcommand || (flags.help && !subcommand)) {
|
|
82
|
-
info('Usage: myapi keys <subcommand>\n\nSubcommands:\n list List your API keys\n create Create a new API key\n revoke Revoke an API key (e.g. myapi keys revoke <id>)');
|
|
83
|
-
break;
|
|
84
|
-
}
|
|
85
|
-
if (subcommand === 'create')
|
|
86
|
-
await keysCmd.createNew(flags);
|
|
87
|
-
else if (subcommand === 'list')
|
|
88
|
-
await keysCmd.list(flags);
|
|
89
|
-
else if (subcommand === 'revoke')
|
|
90
|
-
await keysCmd.revoke(restArgs[0], flags);
|
|
91
|
-
else
|
|
92
|
-
printHelp();
|
|
93
|
-
break;
|
|
94
80
|
case 'org':
|
|
95
81
|
if (!subcommand || (flags.help && !subcommand)) {
|
|
96
82
|
info('Usage: myapi org <subcommand>\n\nSubcommands:\n list List organizations\n create Create an organization\n get Get details of an organization\n delete Delete an organization\n import Extract org from domain');
|
|
@@ -132,8 +118,7 @@ async function main() {
|
|
|
132
118
|
await funnelCmd.run(subcommand, restArgs, flags);
|
|
133
119
|
break;
|
|
134
120
|
default:
|
|
135
|
-
|
|
136
|
-
process.exit(0);
|
|
121
|
+
error(`Unknown command: ${command}. Run "myapi" for available commands.`);
|
|
137
122
|
}
|
|
138
123
|
}
|
|
139
124
|
catch (err) {
|
|
@@ -141,7 +126,7 @@ async function main() {
|
|
|
141
126
|
if (err.status === 402)
|
|
142
127
|
error('Insufficient balance. Run: myapi billing topup <amount>');
|
|
143
128
|
else if (err.status === 401)
|
|
144
|
-
error('Invalid API key. Run: myapi setup');
|
|
129
|
+
error('Invalid API key. Run: myapi auth setup');
|
|
145
130
|
}
|
|
146
131
|
error(err.message || (typeof err === 'object' ? JSON.stringify(err) : String(err)));
|
|
147
132
|
}
|
|
@@ -153,17 +138,16 @@ function printHelp() {
|
|
|
153
138
|
myapi funnel create
|
|
154
139
|
echo '<h1>Hello!</h1>' | myapi funnel push <funnel_id> /`
|
|
155
140
|
: `Quick start:
|
|
156
|
-
myapi setup`;
|
|
141
|
+
myapi auth setup`;
|
|
157
142
|
info(`myapi - MyAPI command-line interface
|
|
158
143
|
|
|
159
144
|
Usage: myapi <command> [subcommand] [args]
|
|
160
145
|
myapi --version
|
|
161
146
|
|
|
162
147
|
Commands:
|
|
163
|
-
|
|
148
|
+
auth Manage account · setup · whoami · signup
|
|
164
149
|
billing Check balance and manage billing
|
|
165
150
|
org Manage organizations
|
|
166
|
-
setup Configure account · whoami · signup · config · install-skills
|
|
167
151
|
update Update CLI and skills to the latest version
|
|
168
152
|
domain Manage domain configurations
|
|
169
153
|
funnel Manage headless funnels and pages
|
package/dist/utils.d.ts
CHANGED
|
@@ -3,3 +3,8 @@ export declare function parseArgs(argv: string[]): {
|
|
|
3
3
|
flags: Record<string, string | boolean>;
|
|
4
4
|
};
|
|
5
5
|
export declare function sleep(ms: number): Promise<unknown>;
|
|
6
|
+
/**
|
|
7
|
+
* Formats an ISO/Go timestamp string to "YYYY-MM-DD HH:mm" (UTC).
|
|
8
|
+
* Strips Go's " +0000 UTC" suffix before parsing.
|
|
9
|
+
*/
|
|
10
|
+
export declare function formatDate(str: string): string;
|
package/dist/utils.js
CHANGED
|
@@ -28,3 +28,14 @@ export function parseArgs(argv) {
|
|
|
28
28
|
export function sleep(ms) {
|
|
29
29
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
30
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* Formats an ISO/Go timestamp string to "YYYY-MM-DD HH:mm" (UTC).
|
|
33
|
+
* Strips Go's " +0000 UTC" suffix before parsing.
|
|
34
|
+
*/
|
|
35
|
+
export function formatDate(str) {
|
|
36
|
+
const clean = str.replace(' +0000 UTC', 'Z');
|
|
37
|
+
const date = new Date(clean);
|
|
38
|
+
if (isNaN(date.getTime()))
|
|
39
|
+
return str;
|
|
40
|
+
return date.toISOString().replace('T', ' ').slice(0, 16);
|
|
41
|
+
}
|
package/package.json
CHANGED
package/src/commands/auth.ts
CHANGED
|
@@ -3,6 +3,7 @@ import * as readline from 'readline';
|
|
|
3
3
|
import { loadConfig, saveConfig, addAccount, switchAccount, listAccounts } from '../config.js';
|
|
4
4
|
import { info, success, error } from '../output.js';
|
|
5
5
|
import { installSkills } from './setup.js';
|
|
6
|
+
import { hq } from '@myapihq/sdk';
|
|
6
7
|
|
|
7
8
|
const API_BASE = process.env.MYAPI_API_BASE ?? 'https://api.myapihq.com';
|
|
8
9
|
|
|
@@ -121,6 +122,13 @@ export async function whoami() {
|
|
|
121
122
|
info(`Org: ${config!.default_org ?? '(none)'}`);
|
|
122
123
|
info(`Funnel: ${config!.default_funnel ?? '(none)'}`);
|
|
123
124
|
info(`Type: ${config!.is_anonymous ? 'anonymous' : 'registered'}`);
|
|
125
|
+
|
|
126
|
+
try {
|
|
127
|
+
const bal = await hq.getBalance(config!.api_key);
|
|
128
|
+
info(`Balance: ${bal.balance_display} | Credits: ${bal.credits_display}`);
|
|
129
|
+
} catch {
|
|
130
|
+
// Balance fetch is best-effort; don't fail whoami if it errors.
|
|
131
|
+
}
|
|
124
132
|
}
|
|
125
133
|
|
|
126
134
|
// myapi auth switch — switch between saved accounts.
|
package/src/commands/billing.ts
CHANGED
|
@@ -2,6 +2,7 @@ import * as readline from 'readline';
|
|
|
2
2
|
import { hq } from '@myapihq/sdk';
|
|
3
3
|
import { requireConfig } from '../config.js';
|
|
4
4
|
import { success, error, printTable, info, printJson } from '../output.js';
|
|
5
|
+
import { formatDate } from '../utils.js';
|
|
5
6
|
|
|
6
7
|
export async function balance(flags: Record<string, string | boolean>) {
|
|
7
8
|
if (flags.help) {
|
|
@@ -10,8 +11,10 @@ export async function balance(flags: Record<string, string | boolean>) {
|
|
|
10
11
|
}
|
|
11
12
|
const config = requireConfig();
|
|
12
13
|
const result = await hq.getBalance(config.api_key);
|
|
13
|
-
|
|
14
|
+
|
|
14
15
|
const pm = result.has_payment_method ? 'yes' : 'no';
|
|
16
|
+
const accountType = config.is_anonymous ? 'anonymous' : `registered (${config.email ?? ''})`;
|
|
17
|
+
info(`Account: ${accountType}`);
|
|
15
18
|
info(`Balance: ${result.balance_display} | Credits: ${result.credits_display} | Payment method: ${pm}`);
|
|
16
19
|
}
|
|
17
20
|
|
|
@@ -22,24 +25,24 @@ export async function history(flags: Record<string, string | boolean>) {
|
|
|
22
25
|
}
|
|
23
26
|
const config = requireConfig();
|
|
24
27
|
const items = await hq.getBillingHistory(config.api_key);
|
|
25
|
-
|
|
28
|
+
|
|
26
29
|
if (flags.json) {
|
|
27
30
|
printJson(items);
|
|
28
31
|
return;
|
|
29
32
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
});
|
|
42
|
-
|
|
33
|
+
|
|
34
|
+
if (items.length === 0) {
|
|
35
|
+
info('No transactions yet.');
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const formattedItems = items.map(item => ({
|
|
40
|
+
Type: item.type || 'unknown',
|
|
41
|
+
Amount: item.amount_display,
|
|
42
|
+
Status: item.status ? item.status.charAt(0).toUpperCase() + item.status.slice(1) : '',
|
|
43
|
+
Date: formatDate(item.created_at),
|
|
44
|
+
}));
|
|
45
|
+
|
|
43
46
|
printTable(formattedItems as unknown as Record<string, unknown>[]);
|
|
44
47
|
}
|
|
45
48
|
|
|
@@ -48,13 +51,9 @@ export async function topup(amountStr: string, flags: Record<string, string | bo
|
|
|
48
51
|
info('Usage: myapi billing topup <amount>\n\nAmount is in whole dollars (e.g. "10" charges $10).\nUse --yes to skip confirmation.\nExample: myapi billing topup 10');
|
|
49
52
|
return;
|
|
50
53
|
}
|
|
51
|
-
if (!amountStr) {
|
|
52
|
-
error("Missing amount. Usage: myapi billing topup <amount>\nExample: myapi billing topup 10");
|
|
53
|
-
return;
|
|
54
|
-
}
|
|
55
54
|
const amount = Math.round(parseFloat(amountStr));
|
|
56
|
-
if (isNaN(amount) || amount <= 0) {
|
|
57
|
-
error("
|
|
55
|
+
if (!amountStr || isNaN(amount) || amount <= 0) {
|
|
56
|
+
error("Amount must be a positive whole number of dollars (e.g. myapi billing topup 10)");
|
|
58
57
|
return;
|
|
59
58
|
}
|
|
60
59
|
|
package/src/commands/domain.ts
CHANGED
|
@@ -6,12 +6,13 @@ export async function check(domainArg: string, flags: Record<string, string | bo
|
|
|
6
6
|
const config = requireConfig();
|
|
7
7
|
const orgId = (flags.org as string) || config.default_org;
|
|
8
8
|
const domain = domainArg || (config.default_domain as string);
|
|
9
|
-
if (!orgId || !domain) error("Missing required arguments.\nUsage: myapi domain check <domain> --org <id>\n(Or set defaults via: myapi config set-org <id> / set-domain <domain>)");
|
|
10
|
-
const res = await sdkDomain.checkDomain(config.api_key, orgId, domain);
|
|
9
|
+
if (!orgId || !domain) error("Missing required arguments.\nUsage: myapi domain check <domain> --org <id>\n(Or set defaults via: myapi auth config set-org <id> / set-domain <domain>)");
|
|
10
|
+
const res = await sdkDomain.checkDomain(config.api_key, orgId, domain) as { available: boolean; price_cents: number; price_display?: string; message?: string };
|
|
11
11
|
if (res.available) {
|
|
12
|
-
|
|
12
|
+
const price = res.price_display || `$${(res.price_cents / 100).toFixed(2)}`;
|
|
13
|
+
info(`${domain} — Available ✓ ${price}/yr`);
|
|
13
14
|
} else {
|
|
14
|
-
info(
|
|
15
|
+
info(`${domain} — ${res.message || 'Not available'} ✗`);
|
|
15
16
|
}
|
|
16
17
|
}
|
|
17
18
|
|
|
@@ -19,7 +20,7 @@ export async function register(domainArg: string, flags: Record<string, string |
|
|
|
19
20
|
const config = requireConfig();
|
|
20
21
|
const orgId = (flags.org as string) || config.default_org;
|
|
21
22
|
const domain = domainArg || (config.default_domain as string);
|
|
22
|
-
if (!orgId || !domain) error("Missing required arguments.\nUsage: myapi domain register <domain> --org <id> [--years <num>]\n(Or set defaults via: myapi config set-org <id> / set-domain <domain>)");
|
|
23
|
+
if (!orgId || !domain) error("Missing required arguments.\nUsage: myapi domain register <domain> --org <id> [--years <num>]\n(Or set defaults via: myapi auth config set-org <id> / set-domain <domain>)");
|
|
23
24
|
const years = parseInt(flags.years as string) || 1;
|
|
24
25
|
const res = await sdkDomain.registerDomain(config.api_key, orgId, domain, years);
|
|
25
26
|
success(`Registered ${domain}!\n${JSON.stringify(res, null, 2)}`);
|
|
@@ -29,7 +30,7 @@ export async function importDomain(domainArg: string, flags: Record<string, stri
|
|
|
29
30
|
const config = requireConfig();
|
|
30
31
|
const orgId = (flags.org as string) || config.default_org;
|
|
31
32
|
const domain = domainArg || (config.default_domain as string);
|
|
32
|
-
if (!orgId || !domain) error("Missing required arguments.\nUsage: myapi domain import <domain> --org <id> [--namecheap-user <user> --namecheap-key <key>]\n(Or set defaults via: myapi config set-org <id> / set-domain <domain>)");
|
|
33
|
+
if (!orgId || !domain) error("Missing required arguments.\nUsage: myapi domain import <domain> --org <id> [--namecheap-user <user> --namecheap-key <key>]\n(Or set defaults via: myapi auth config set-org <id> / set-domain <domain>)");
|
|
33
34
|
const payload: { domain: string; namecheap_api_user?: string; namecheap_api_key?: string } = { domain };
|
|
34
35
|
if (flags['namecheap-user']) payload.namecheap_api_user = flags['namecheap-user'] as string;
|
|
35
36
|
if (flags['namecheap-key']) payload.namecheap_api_key = flags['namecheap-key'] as string;
|
|
@@ -40,7 +41,7 @@ export async function importDomain(domainArg: string, flags: Record<string, stri
|
|
|
40
41
|
export async function list(flags: Record<string, string | boolean>) {
|
|
41
42
|
const config = requireConfig();
|
|
42
43
|
const orgId = (flags.org as string) || config.default_org;
|
|
43
|
-
if (!orgId) error("Missing required arguments.\nUsage: myapi domain list --org <id> [--filter=all|unassigned|org]\n(Or set a default org via: myapi config set-org <id>)");
|
|
44
|
+
if (!orgId) error("Missing required arguments.\nUsage: myapi domain list --org <id> [--filter=all|unassigned|org]\n(Or set a default org via: myapi auth config set-org <id>)");
|
|
44
45
|
const filter = flags.filter as 'all' | 'unassigned' | 'org' | undefined;
|
|
45
46
|
const domains = await sdkDomain.listDomains(config.api_key, orgId, filter);
|
|
46
47
|
printTable(domains as unknown as Record<string, unknown>[]);
|
|
@@ -51,8 +52,8 @@ export async function assign(domainArg: string, flags: Record<string, string | b
|
|
|
51
52
|
const orgId = (flags.org as string) || config.default_org;
|
|
52
53
|
const domain = domainArg || (config.default_domain as string);
|
|
53
54
|
const targetOrgId = flags.target as string;
|
|
54
|
-
if (!orgId || !domain || !targetOrgId) error("Missing required arguments.\nUsage: myapi domain assign <domain> --org <id> --target <target_org_id>\n(Or set defaults via: myapi config set-org <id> / set-domain <domain>)");
|
|
55
|
-
|
|
55
|
+
if (!orgId || !domain || !targetOrgId) error("Missing required arguments.\nUsage: myapi domain assign <domain> --org <id> --target <target_org_id>\n(Or set defaults via: myapi auth config set-org <id> / set-domain <domain>)");
|
|
56
|
+
await sdkDomain.assignDomain(config.api_key, orgId, domain, targetOrgId);
|
|
56
57
|
success(`Assigned ${domain} to org ${targetOrgId}`);
|
|
57
58
|
}
|
|
58
59
|
|
|
@@ -60,16 +61,30 @@ export async function unassign(domainArg: string, flags: Record<string, string |
|
|
|
60
61
|
const config = requireConfig();
|
|
61
62
|
const orgId = (flags.org as string) || config.default_org;
|
|
62
63
|
const domain = domainArg || (config.default_domain as string);
|
|
63
|
-
if (!orgId || !domain) error("Missing required arguments.\nUsage: myapi domain unassign <domain> --org <id>\n(Or set defaults via: myapi config set-org <id> / set-domain <domain>)");
|
|
64
|
-
|
|
64
|
+
if (!orgId || !domain) error("Missing required arguments.\nUsage: myapi domain unassign <domain> --org <id>\n(Or set defaults via: myapi auth config set-org <id> / set-domain <domain>)");
|
|
65
|
+
await sdkDomain.unassignDomain(config.api_key, orgId, domain);
|
|
65
66
|
success(`Unassigned ${domain} from org ${orgId}`);
|
|
66
67
|
}
|
|
67
68
|
|
|
69
|
+
export async function status(domainArg: string, flags: Record<string, string | boolean>) {
|
|
70
|
+
const config = requireConfig();
|
|
71
|
+
const orgId = (flags.org as string) || config.default_org;
|
|
72
|
+
const domain = domainArg || (config.default_domain as string);
|
|
73
|
+
if (!orgId || !domain) error("Missing required arguments.\nUsage: myapi domain status <domain> --org <id>\n(Or set defaults via: myapi auth config set-org <id> / set-domain <domain>)");
|
|
74
|
+
const res = await sdkDomain.getDomainStatus(config.api_key, orgId, domain);
|
|
75
|
+
const display: Record<string, unknown> = {
|
|
76
|
+
domain: res.domain,
|
|
77
|
+
status: res.status,
|
|
78
|
+
};
|
|
79
|
+
if (res.expires_at) display.expires_at = res.expires_at;
|
|
80
|
+
printJson(display);
|
|
81
|
+
}
|
|
82
|
+
|
|
68
83
|
export async function settings(domainArg: string, flags: Record<string, string | boolean>) {
|
|
69
84
|
const config = requireConfig();
|
|
70
85
|
const orgId = (flags.org as string) || config.default_org;
|
|
71
86
|
const domain = domainArg || (config.default_domain as string);
|
|
72
|
-
if (!orgId || !domain) error("Missing required arguments.\nUsage: myapi domain settings <domain> --org <id>\n(Or set defaults via: myapi config set-org <id> / set-domain <domain>)");
|
|
87
|
+
if (!orgId || !domain) error("Missing required arguments.\nUsage: myapi domain settings <domain> --org <id>\n(Or set defaults via: myapi auth config set-org <id> / set-domain <domain>)");
|
|
73
88
|
const res = await sdkDomain.getDomainSettings(config.api_key, orgId, domain);
|
|
74
89
|
printJson(res);
|
|
75
90
|
}
|
|
@@ -78,22 +93,22 @@ export async function updateSettings(domainArg: string, flags: Record<string, st
|
|
|
78
93
|
const config = requireConfig();
|
|
79
94
|
const orgId = (flags.org as string) || config.default_org;
|
|
80
95
|
const domain = domainArg || (config.default_domain as string);
|
|
81
|
-
if (!orgId || !domain) error("Missing required arguments.\nUsage: myapi domain update-settings <domain> --org <id> [--security=...] [--browser-check=...] [--purge-cache]\n(Or set defaults via: myapi config set-org <id> / set-domain <domain>)");
|
|
96
|
+
if (!orgId || !domain) error("Missing required arguments.\nUsage: myapi domain update-settings <domain> --org <id> [--security=...] [--browser-check=...] [--purge-cache]\n(Or set defaults via: myapi auth config set-org <id> / set-domain <domain>)");
|
|
82
97
|
const payload: any = {};
|
|
83
98
|
if (flags.security) payload.security_level = flags.security as string;
|
|
84
99
|
if (flags['browser-check']) payload.browser_check = flags['browser-check'] as string;
|
|
85
100
|
if (flags['purge-cache']) payload.purge_cache = true;
|
|
86
|
-
|
|
101
|
+
|
|
87
102
|
const res = await sdkDomain.updateDomainSettings(config.api_key, orgId, domain, payload);
|
|
88
103
|
success(`Updated settings for ${domain}!\n${JSON.stringify(res, null, 2)}`);
|
|
89
104
|
}
|
|
90
105
|
|
|
91
106
|
export async function run(subcommand: string | undefined, args: string[], flags: Record<string, string | boolean>) {
|
|
92
107
|
if (!subcommand || (flags.help && !subcommand)) {
|
|
93
|
-
info('Usage: myapi domain <subcommand>\n\nSubcommands:\n list List domains\n check Check domain availability\n register Register a domain\n import Import an existing domain\n assign Assign domain to org\n unassign Unassign domain from its current org\n settings Get domain settings\n update-settings Update domain settings\n\nNote: All domain commands require the --org <id> flag.');
|
|
108
|
+
info('Usage: myapi domain <subcommand>\n\nSubcommands:\n list List domains\n check Check domain availability\n register Register a domain\n import Import an existing domain\n assign Assign domain to org\n unassign Unassign domain from its current org\n status Get domain status\n settings Get domain settings\n update-settings Update domain settings\n\nNote: All domain commands require the --org <id> flag.');
|
|
94
109
|
return;
|
|
95
110
|
}
|
|
96
|
-
|
|
111
|
+
|
|
97
112
|
if (flags.help) {
|
|
98
113
|
if (subcommand === 'list') info('Usage: myapi domain list --org <id> [--filter=all|unassigned|org]\n\nLists all registered domains in your account.\n --filter=all Lists all domains owned by the account.\n --filter=unassigned Lists domains not assigned to an org.\n --filter=org (Default) Lists domains assigned to the current org.');
|
|
99
114
|
else if (subcommand === 'check') info('Usage: myapi domain check <domain> --org <id>\n\nChecks if a domain name is available for registration.');
|
|
@@ -101,6 +116,7 @@ export async function run(subcommand: string | undefined, args: string[], flags:
|
|
|
101
116
|
else if (subcommand === 'import') info('Usage: myapi domain import <domain> --org <id> --namecheap-user <user> --namecheap-key <key>\n\nImports an existing domain from Namecheap.');
|
|
102
117
|
else if (subcommand === 'assign') info('Usage: myapi domain assign <domain> --org <id> --target <target_org_id>\n\nAssigns a domain to a different organization.');
|
|
103
118
|
else if (subcommand === 'unassign') info('Usage: myapi domain unassign <domain> --org <id>\n\nUnassigns a domain from its current organization.');
|
|
119
|
+
else if (subcommand === 'status') info('Usage: myapi domain status <domain> --org <id>\n\nGets the registration status of a domain.');
|
|
104
120
|
else if (subcommand === 'settings') info('Usage: myapi domain settings <domain> --org <id>\n\nGets the DNS settings and configuration for a domain.');
|
|
105
121
|
else if (subcommand === 'update-settings') info('Usage: myapi domain update-settings <domain> --org <id> [--security=essentially_off|medium|high|under_attack] [--browser-check=on|off] [--purge-cache]\n\nUpdates edge settings for a domain.');
|
|
106
122
|
return;
|
|
@@ -112,6 +128,7 @@ export async function run(subcommand: string | undefined, args: string[], flags:
|
|
|
112
128
|
else if (subcommand === 'import') await importDomain(args[0], flags);
|
|
113
129
|
else if (subcommand === 'assign') await assign(args[0], flags);
|
|
114
130
|
else if (subcommand === 'unassign') await unassign(args[0], flags);
|
|
131
|
+
else if (subcommand === 'status') await status(args[0], flags);
|
|
115
132
|
else if (subcommand === 'settings') await settings(args[0], flags);
|
|
116
133
|
else if (subcommand === 'update-settings') await updateSettings(args[0], flags);
|
|
117
134
|
else error(`Unknown subcommand: ${subcommand}. Run "myapi domain --help" for a list of valid subcommands.`);
|
package/src/commands/org.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { hq } from '@myapihq/sdk';
|
|
2
2
|
import { requireConfig } from '../config.js';
|
|
3
3
|
import { success, error, printTable, printJson, info } from '../output.js';
|
|
4
|
-
import { sleep } from '../utils.js';
|
|
4
|
+
import { sleep, formatDate } from '../utils.js';
|
|
5
5
|
|
|
6
6
|
export async function create(flags: Record<string, string | boolean>) {
|
|
7
7
|
if (flags.help) {
|
|
@@ -18,7 +18,7 @@ export async function create(flags: Record<string, string | boolean>) {
|
|
|
18
18
|
if (flags.description) payload.description = flags.description as string;
|
|
19
19
|
if (flags['business-sector']) payload.business_sector = flags['business-sector'] as string;
|
|
20
20
|
if (flags['logo-url']) payload.logo_url = flags['logo-url'] as string;
|
|
21
|
-
|
|
21
|
+
|
|
22
22
|
const org = await hq.createOrg(config.api_key, payload);
|
|
23
23
|
success(`Org created! ID: ${org.id}, Name: ${org.name}`);
|
|
24
24
|
if (org.preview_subdomain) {
|
|
@@ -28,12 +28,17 @@ export async function create(flags: Record<string, string | boolean>) {
|
|
|
28
28
|
|
|
29
29
|
export async function list(flags: Record<string, string | boolean>) {
|
|
30
30
|
if (flags.help) {
|
|
31
|
-
info('Usage: myapi org list\n\nLists all organizations in your account
|
|
31
|
+
info('Usage: myapi org list\n\nLists all organizations in your account.');
|
|
32
32
|
return;
|
|
33
33
|
}
|
|
34
34
|
const config = requireConfig();
|
|
35
35
|
const orgs = await hq.listOrgs(config.api_key);
|
|
36
|
-
|
|
36
|
+
const rows = orgs.map((o: any) => ({
|
|
37
|
+
id: o.id,
|
|
38
|
+
name: o.name,
|
|
39
|
+
created_at: o.created_at ? formatDate(o.created_at) : '',
|
|
40
|
+
}));
|
|
41
|
+
printTable(rows as unknown as Record<string, unknown>[]);
|
|
37
42
|
}
|
|
38
43
|
|
|
39
44
|
export async function get(id: string, flags: Record<string, string | boolean>) {
|
|
@@ -75,19 +80,19 @@ export async function importOrg(args: string[], flags: Record<string, string | b
|
|
|
75
80
|
const config = requireConfig();
|
|
76
81
|
const domain = args[0] || (config.default_domain as string);
|
|
77
82
|
const orgId = (flags.org as string) || config.default_org;
|
|
78
|
-
|
|
83
|
+
|
|
79
84
|
if (!domain || !orgId) {
|
|
80
85
|
error("Missing required arguments.\nUsage: myapi org import <domain> --org <id>\n(Or set defaults via: myapi config set-org <id> / set-domain <domain>)");
|
|
81
86
|
return;
|
|
82
87
|
}
|
|
83
|
-
|
|
88
|
+
|
|
84
89
|
const result = await hq.importOrg(config.api_key, orgId, domain);
|
|
85
90
|
const importId = result.job_id;
|
|
86
|
-
|
|
91
|
+
|
|
87
92
|
process.stdout.write("Importing ");
|
|
88
93
|
const chars = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
89
94
|
let i = 0;
|
|
90
|
-
|
|
95
|
+
|
|
91
96
|
while (true) {
|
|
92
97
|
const status = await hq.getOrgImportStatus(config.api_key, importId);
|
|
93
98
|
if (status.status === 'awaiting_confirm') {
|
|
@@ -101,7 +106,7 @@ export async function importOrg(args: string[], flags: Record<string, string | b
|
|
|
101
106
|
process.stdout.write(`\rImporting ${chars[i++ % chars.length]}`);
|
|
102
107
|
await sleep(3000);
|
|
103
108
|
}
|
|
104
|
-
|
|
109
|
+
|
|
105
110
|
const org = await hq.confirmOrgImport(config.api_key, importId);
|
|
106
111
|
success(`Import complete! Org ID: ${org.id}`);
|
|
107
112
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
//
|
|
2
|
+
// manually maintained — do not regenerate from scripts/generate-indexes.js
|
|
3
3
|
import { parseArgs } from './utils.js';
|
|
4
4
|
import { error, info, success } from './output.js';
|
|
5
5
|
import { loadConfig } from './config.js';
|
|
@@ -19,18 +19,17 @@ import * as authCmd from './commands/auth.js';
|
|
|
19
19
|
import * as configCmd from './commands/config.js';
|
|
20
20
|
|
|
21
21
|
async function main() {
|
|
22
|
-
|
|
23
|
-
updateCmd.checkForUpdate(pkg.version).catch(() => {});
|
|
22
|
+
const updatePromise = updateCmd.checkForUpdate(pkg.version).catch(() => {});
|
|
24
23
|
|
|
25
24
|
const { args, flags } = parseArgs(process.argv.slice(2));
|
|
26
25
|
|
|
27
26
|
if (flags.version || flags.v) {
|
|
28
|
-
const latest = await updateCmd.latestVersion();
|
|
27
|
+
const [latest] = await Promise.all([updateCmd.latestVersion(), updatePromise]);
|
|
29
28
|
const updateNote = latest && updateCmd.isNewer(latest, pkg.version)
|
|
30
29
|
? ` (update available: ${latest})`
|
|
31
30
|
: '';
|
|
32
31
|
info(`myapi ${pkg.version}${updateNote}`);
|
|
33
|
-
|
|
32
|
+
return;
|
|
34
33
|
}
|
|
35
34
|
|
|
36
35
|
if (args.length === 0) {
|
|
@@ -40,7 +39,8 @@ async function main() {
|
|
|
40
39
|
info('');
|
|
41
40
|
}
|
|
42
41
|
printHelp();
|
|
43
|
-
|
|
42
|
+
await updatePromise;
|
|
43
|
+
return;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
const [command, subcommand, ...restArgs] = args;
|
|
@@ -69,16 +69,6 @@ async function main() {
|
|
|
69
69
|
case 'update':
|
|
70
70
|
await updateCmd.update();
|
|
71
71
|
break;
|
|
72
|
-
case 'keys':
|
|
73
|
-
if (!subcommand || (flags.help && !subcommand)) {
|
|
74
|
-
info('Usage: myapi keys <subcommand>\n\nSubcommands:\n list List your API keys\n create Create a new API key\n revoke Revoke an API key (e.g. myapi keys revoke <id>)');
|
|
75
|
-
break;
|
|
76
|
-
}
|
|
77
|
-
if (subcommand === 'create') await keysCmd.createNew(flags);
|
|
78
|
-
else if (subcommand === 'list') await keysCmd.list(flags);
|
|
79
|
-
else if (subcommand === 'revoke') await keysCmd.revoke(restArgs[0], flags);
|
|
80
|
-
else printHelp();
|
|
81
|
-
break;
|
|
82
72
|
case 'org':
|
|
83
73
|
if (!subcommand || (flags.help && !subcommand)) {
|
|
84
74
|
info('Usage: myapi org <subcommand>\n\nSubcommands:\n list List organizations\n create Create an organization\n get Get details of an organization\n delete Delete an organization\n import Extract org from domain');
|
|
@@ -109,13 +99,12 @@ async function main() {
|
|
|
109
99
|
await funnelCmd.run(subcommand, restArgs, flags);
|
|
110
100
|
break;
|
|
111
101
|
default:
|
|
112
|
-
|
|
113
|
-
process.exit(0);
|
|
102
|
+
error(`Unknown command: ${command}. Run "myapi" for available commands.`);
|
|
114
103
|
}
|
|
115
104
|
} catch (err: any) {
|
|
116
105
|
if (err instanceof MyApiError) {
|
|
117
106
|
if (err.status === 402) error('Insufficient balance. Run: myapi billing topup <amount>');
|
|
118
|
-
else if (err.status === 401) error('Invalid API key. Run: myapi setup');
|
|
107
|
+
else if (err.status === 401) error('Invalid API key. Run: myapi auth setup');
|
|
119
108
|
}
|
|
120
109
|
error(err.message || (typeof err === 'object' ? JSON.stringify(err) : String(err)));
|
|
121
110
|
}
|
|
@@ -128,17 +117,16 @@ function printHelp() {
|
|
|
128
117
|
myapi funnel create
|
|
129
118
|
echo '<h1>Hello!</h1>' | myapi funnel push <funnel_id> /`
|
|
130
119
|
: `Quick start:
|
|
131
|
-
myapi setup`;
|
|
120
|
+
myapi auth setup`;
|
|
132
121
|
info(`myapi - MyAPI command-line interface
|
|
133
122
|
|
|
134
123
|
Usage: myapi <command> [subcommand] [args]
|
|
135
124
|
myapi --version
|
|
136
125
|
|
|
137
126
|
Commands:
|
|
138
|
-
|
|
127
|
+
auth Manage account · setup · whoami · signup
|
|
139
128
|
billing Check balance and manage billing
|
|
140
129
|
org Manage organizations
|
|
141
|
-
setup Configure account · whoami · signup · config · install-skills
|
|
142
130
|
update Update CLI and skills to the latest version
|
|
143
131
|
domain Manage domain configurations
|
|
144
132
|
funnel Manage headless funnels and pages
|
package/src/utils.ts
CHANGED
|
@@ -28,3 +28,14 @@ export function parseArgs(argv: string[]) {
|
|
|
28
28
|
export function sleep(ms: number) {
|
|
29
29
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
30
30
|
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Formats an ISO/Go timestamp string to "YYYY-MM-DD HH:mm" (UTC).
|
|
34
|
+
* Strips Go's " +0000 UTC" suffix before parsing.
|
|
35
|
+
*/
|
|
36
|
+
export function formatDate(str: string): string {
|
|
37
|
+
const clean = str.replace(' +0000 UTC', 'Z');
|
|
38
|
+
const date = new Date(clean);
|
|
39
|
+
if (isNaN(date.getTime())) return str;
|
|
40
|
+
return date.toISOString().replace('T', ' ').slice(0, 16);
|
|
41
|
+
}
|