@myapihq/cli 1.0.6 → 1.0.8
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/billing.js +49 -6
- package/dist/commands/keys.d.ts +3 -0
- package/dist/commands/keys.js +98 -0
- package/dist/commands/org.d.ts +1 -1
- package/dist/commands/org.js +45 -11
- package/dist/index.js +18 -14
- package/package.json +1 -1
- package/src/commands/billing.ts +57 -5
- package/src/commands/keys.ts +69 -0
- package/src/commands/org.ts +45 -8
- package/src/index.ts +14 -12
- package/src/commands/account.ts +0 -49
package/dist/commands/billing.js
CHANGED
|
@@ -8,26 +8,69 @@ const sdk_1 = require("@myapihq/sdk");
|
|
|
8
8
|
const config_js_1 = require("../config.js");
|
|
9
9
|
const output_js_1 = require("../output.js");
|
|
10
10
|
async function balance(flags) {
|
|
11
|
+
if (flags.help) {
|
|
12
|
+
(0, output_js_1.info)('Usage: myapi billing balance\n\nShows your current account balance, credits, and payment method status.');
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
11
15
|
const config = (0, config_js_1.requireConfig)();
|
|
12
16
|
const result = await sdk_1.hq.getBalance(config.api_key);
|
|
13
|
-
|
|
17
|
+
const bal = result.balance_display || `$${(result.balance_cents / 100).toFixed(2)}`;
|
|
18
|
+
const cred = result.credits_display || `$${((result.credits_cents || 0) / 100).toFixed(2)}`;
|
|
19
|
+
const pm = result.has_payment_method ? 'yes' : 'no';
|
|
20
|
+
(0, output_js_1.info)(`Balance: ${bal} | Credits: ${cred} | Payment method: ${pm}`);
|
|
14
21
|
}
|
|
15
22
|
async function history(flags) {
|
|
23
|
+
if (flags.help) {
|
|
24
|
+
(0, output_js_1.info)('Usage: myapi billing history [--json]\n\nShows your recent billing transactions and top-ups.');
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
16
27
|
const config = (0, config_js_1.requireConfig)();
|
|
17
28
|
const items = await sdk_1.hq.getBillingHistory(config.api_key);
|
|
18
|
-
(
|
|
29
|
+
if (flags.json) {
|
|
30
|
+
(0, output_js_1.printJson)(items);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const formattedItems = items.map(item => {
|
|
34
|
+
// Attempt to parse the date cleanly (handling Go's "+0000 UTC" suffix)
|
|
35
|
+
const cleanDate = item.created_at.replace(' +0000 UTC', 'Z');
|
|
36
|
+
const date = new Date(cleanDate);
|
|
37
|
+
const dateStr = isNaN(date.getTime()) ? item.created_at : date.toLocaleString();
|
|
38
|
+
// Format amount
|
|
39
|
+
const isNegative = item.amount_cents < 0;
|
|
40
|
+
const absAmount = Math.abs(item.amount_cents) / 100;
|
|
41
|
+
const amountStr = `${isNegative ? '-' : ''}$${absAmount.toFixed(2)}`;
|
|
42
|
+
return {
|
|
43
|
+
Type: item.type || 'unknown',
|
|
44
|
+
Amount: amountStr,
|
|
45
|
+
Status: item.status ? item.status.charAt(0).toUpperCase() + item.status.slice(1) : '',
|
|
46
|
+
Date: dateStr
|
|
47
|
+
};
|
|
48
|
+
});
|
|
49
|
+
(0, output_js_1.printTable)(formattedItems);
|
|
19
50
|
}
|
|
20
51
|
async function topup(amountStr, flags) {
|
|
21
|
-
if (
|
|
22
|
-
(0, output_js_1.
|
|
52
|
+
if (flags.help) {
|
|
53
|
+
(0, output_js_1.info)('Usage: myapi billing topup <amount_in_dollars>\n\nAdds funds to your account balance using your saved payment method.\nExample: myapi billing topup 10.00');
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (!amountStr) {
|
|
57
|
+
(0, output_js_1.error)("Missing amount. Usage: myapi billing topup <amount_in_dollars>");
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
23
60
|
const amount = parseFloat(amountStr);
|
|
24
|
-
if (isNaN(amount))
|
|
25
|
-
(0, output_js_1.error)("Invalid amount");
|
|
61
|
+
if (isNaN(amount)) {
|
|
62
|
+
(0, output_js_1.error)("Invalid amount. Must be a number in dollars (e.g., 10.00)");
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
26
65
|
const config = (0, config_js_1.requireConfig)();
|
|
27
66
|
const result = await sdk_1.hq.topUp(config.api_key, Math.round(amount * 100));
|
|
28
67
|
(0, output_js_1.success)(`Top up successful! New balance: $${(result.new_balance_cents / 100).toFixed(2)}`);
|
|
29
68
|
}
|
|
30
69
|
async function setup(flags) {
|
|
70
|
+
if (flags.help) {
|
|
71
|
+
(0, output_js_1.info)('Usage: myapi billing setup\n\nGenerates a secure Stripe Checkout link to add or update your payment method.');
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
31
74
|
const config = (0, config_js_1.requireConfig)();
|
|
32
75
|
const result = await sdk_1.hq.setupPayment(config.api_key);
|
|
33
76
|
(0, output_js_1.success)(`Open this URL in your browser to set up payment:\n${result.url}`);
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export declare function createNew(flags: Record<string, string | boolean>): Promise<void>;
|
|
2
|
+
export declare function list(flags: Record<string, string | boolean>): Promise<void>;
|
|
3
|
+
export declare function revoke(id: string, flags: Record<string, string | boolean>): Promise<void>;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.createNew = createNew;
|
|
37
|
+
exports.list = list;
|
|
38
|
+
exports.revoke = revoke;
|
|
39
|
+
const sdk_1 = require("@myapihq/sdk");
|
|
40
|
+
const config_js_1 = require("../config.js");
|
|
41
|
+
const output_js_1 = require("../output.js");
|
|
42
|
+
const readline = __importStar(require("readline"));
|
|
43
|
+
async function createNew(flags) {
|
|
44
|
+
if (flags.help) {
|
|
45
|
+
(0, output_js_1.info)('Usage: myapi keys create\n\nCreates a new API key. You will be prompted to enter a name for the key.');
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const config = (0, config_js_1.requireConfig)();
|
|
49
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
50
|
+
const name = await new Promise(resolve => rl.question('Enter a name for the new key: ', resolve));
|
|
51
|
+
rl.close();
|
|
52
|
+
if (!name.trim()) {
|
|
53
|
+
(0, output_js_1.error)('Key name cannot be empty.');
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const keyInfo = await sdk_1.hq.createApiKey(config.api_key, name.trim());
|
|
57
|
+
(0, output_js_1.success)(`New API key created!\n\nName: ${keyInfo.prefix}...\nKey: ${keyInfo.api_key}\n\nMake sure to copy your new API key now. You won't be able to see it again!`);
|
|
58
|
+
}
|
|
59
|
+
async function list(flags) {
|
|
60
|
+
if (flags.help) {
|
|
61
|
+
(0, output_js_1.info)('Usage: myapi keys list\n\nLists all API keys associated with your account.');
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const config = (0, config_js_1.requireConfig)();
|
|
65
|
+
const keysList = await sdk_1.hq.listApiKeys(config.api_key);
|
|
66
|
+
const formattedKeys = keysList.map(k => {
|
|
67
|
+
// Format creation date
|
|
68
|
+
const createdDate = new Date(k.created_at);
|
|
69
|
+
const createdStr = isNaN(createdDate.getTime()) ? k.created_at : createdDate.toLocaleString();
|
|
70
|
+
// Format last used date
|
|
71
|
+
let lastUsedStr = 'Never';
|
|
72
|
+
if (k.last_used_at) {
|
|
73
|
+
const lastUsedDate = new Date(k.last_used_at);
|
|
74
|
+
lastUsedStr = isNaN(lastUsedDate.getTime()) ? k.last_used_at : lastUsedDate.toLocaleString();
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
Name: k.name || 'Unnamed',
|
|
78
|
+
Prefix: k.prefix,
|
|
79
|
+
ID: k.id,
|
|
80
|
+
'Created At': createdStr,
|
|
81
|
+
'Last Used': lastUsedStr
|
|
82
|
+
};
|
|
83
|
+
});
|
|
84
|
+
(0, output_js_1.printTable)(formattedKeys);
|
|
85
|
+
}
|
|
86
|
+
async function revoke(id, flags) {
|
|
87
|
+
if (flags.help) {
|
|
88
|
+
(0, output_js_1.info)('Usage: myapi keys revoke <id>\n\nRevokes an API key permanently.');
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (!id) {
|
|
92
|
+
(0, output_js_1.error)("Missing key ID. Usage: myapi keys revoke <id>");
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const config = (0, config_js_1.requireConfig)();
|
|
96
|
+
await sdk_1.hq.revokeApiKey(config.api_key, id);
|
|
97
|
+
(0, output_js_1.success)(`Key ${id} revoked successfully.`);
|
|
98
|
+
}
|
package/dist/commands/org.d.ts
CHANGED
|
@@ -2,4 +2,4 @@ export declare function create(flags: Record<string, string | boolean>): Promise
|
|
|
2
2
|
export declare function list(flags: Record<string, string | boolean>): Promise<void>;
|
|
3
3
|
export declare function get(id: string, flags: Record<string, string | boolean>): Promise<void>;
|
|
4
4
|
export declare function del(id: string, flags: Record<string, string | boolean>): Promise<void>;
|
|
5
|
-
export declare function importOrg(
|
|
5
|
+
export declare function importOrg(args: string[], flags: Record<string, string | boolean>): Promise<void>;
|
package/dist/commands/org.js
CHANGED
|
@@ -10,41 +10,75 @@ const config_js_1 = require("../config.js");
|
|
|
10
10
|
const output_js_1 = require("../output.js");
|
|
11
11
|
const utils_js_1 = require("../utils.js");
|
|
12
12
|
async function create(flags) {
|
|
13
|
-
if (
|
|
14
|
-
(0, output_js_1.
|
|
13
|
+
if (flags.help) {
|
|
14
|
+
(0, output_js_1.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');
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
if (!flags.name) {
|
|
18
|
+
(0, output_js_1.error)("Missing --name flag. Run 'myapi org create --help' for details.");
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
15
21
|
const config = (0, config_js_1.requireConfig)();
|
|
16
22
|
const payload = { name: flags.name };
|
|
17
23
|
if (flags.tagline)
|
|
18
24
|
payload.tagline = flags.tagline;
|
|
19
25
|
if (flags.description)
|
|
20
26
|
payload.description = flags.description;
|
|
27
|
+
if (flags['business-sector'])
|
|
28
|
+
payload.business_sector = flags['business-sector'];
|
|
29
|
+
if (flags['logo-url'])
|
|
30
|
+
payload.logo_url = flags['logo-url'];
|
|
21
31
|
const org = await sdk_1.hq.createOrg(config.api_key, payload);
|
|
22
32
|
(0, output_js_1.success)(`Org created! ID: ${org.id}, Name: ${org.name}`);
|
|
23
33
|
}
|
|
24
34
|
async function list(flags) {
|
|
35
|
+
if (flags.help) {
|
|
36
|
+
(0, output_js_1.info)('Usage: myapi org list\n\nLists all organizations in your account as JSON.');
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
25
39
|
const config = (0, config_js_1.requireConfig)();
|
|
26
40
|
const orgs = await sdk_1.hq.listOrgs(config.api_key);
|
|
27
|
-
(0, output_js_1.
|
|
41
|
+
(0, output_js_1.printJson)(orgs);
|
|
28
42
|
}
|
|
29
43
|
async function get(id, flags) {
|
|
30
|
-
if (
|
|
31
|
-
(0, output_js_1.
|
|
44
|
+
if (flags.help) {
|
|
45
|
+
(0, output_js_1.info)('Usage: myapi org get <id>\n\nFetches details of a specific organization.');
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
if (!id) {
|
|
49
|
+
(0, output_js_1.error)("Missing org id. Usage: myapi org get <id>");
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
32
52
|
const config = (0, config_js_1.requireConfig)();
|
|
33
53
|
const org = await sdk_1.hq.getOrg(config.api_key, id);
|
|
34
54
|
(0, output_js_1.printJson)(org);
|
|
35
55
|
}
|
|
36
56
|
async function del(id, flags) {
|
|
37
|
-
if (
|
|
38
|
-
(0, output_js_1.
|
|
57
|
+
if (flags.help) {
|
|
58
|
+
(0, output_js_1.info)('Usage: myapi org delete <id>\n\nDeletes an organization.');
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
if (!id) {
|
|
62
|
+
(0, output_js_1.error)("Missing org id. Usage: myapi org delete <id>");
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
39
65
|
const config = (0, config_js_1.requireConfig)();
|
|
40
66
|
await sdk_1.hq.deleteOrg(config.api_key, id);
|
|
41
67
|
(0, output_js_1.success)(`Org ${id} deleted`);
|
|
42
68
|
}
|
|
43
|
-
async function importOrg(
|
|
44
|
-
if (
|
|
45
|
-
(0, output_js_1.
|
|
69
|
+
async function importOrg(args, flags) {
|
|
70
|
+
if (flags.help) {
|
|
71
|
+
(0, output_js_1.info)('Usage: myapi org import <org_id> <domain>\n\nAutomatically extracts brand info from an existing website and updates the organization.\n\nNote: You must create a placeholder organization first using `myapi org create` to get an org_id.');
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const orgId = args[0];
|
|
75
|
+
const domain = args[1];
|
|
76
|
+
if (!orgId || !domain) {
|
|
77
|
+
(0, output_js_1.error)("Missing arguments. Usage: myapi org import <org_id> <domain>");
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
46
80
|
const config = (0, config_js_1.requireConfig)();
|
|
47
|
-
const result = await sdk_1.hq.importOrg(config.api_key, domain);
|
|
81
|
+
const result = await sdk_1.hq.importOrg(config.api_key, orgId, domain);
|
|
48
82
|
const importId = result.job_id;
|
|
49
83
|
process.stdout.write("Importing ");
|
|
50
84
|
const chars = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
package/dist/index.js
CHANGED
|
@@ -38,7 +38,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
38
38
|
const utils_js_1 = require("./utils.js");
|
|
39
39
|
const output_js_1 = require("./output.js");
|
|
40
40
|
const sdk_1 = require("@myapihq/sdk");
|
|
41
|
-
const
|
|
41
|
+
const keysCmd = __importStar(require("./commands/keys.js"));
|
|
42
42
|
const billingCmd = __importStar(require("./commands/billing.js"));
|
|
43
43
|
const orgCmd = __importStar(require("./commands/org.js"));
|
|
44
44
|
const setupCmd = __importStar(require("./commands/setup.js"));
|
|
@@ -58,36 +58,40 @@ async function main() {
|
|
|
58
58
|
}
|
|
59
59
|
await setupCmd.setup();
|
|
60
60
|
break;
|
|
61
|
-
case '
|
|
62
|
-
if (flags.help
|
|
63
|
-
(0, output_js_1.info)('Usage: myapi
|
|
61
|
+
case 'keys':
|
|
62
|
+
if (!subcommand || (flags.help && !subcommand)) {
|
|
63
|
+
(0, output_js_1.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>)');
|
|
64
64
|
break;
|
|
65
65
|
}
|
|
66
66
|
if (subcommand === 'create')
|
|
67
|
-
await
|
|
68
|
-
else if (subcommand === '
|
|
69
|
-
await
|
|
70
|
-
else if (subcommand === 'keys')
|
|
71
|
-
await accountCmd.listKeys(flags);
|
|
67
|
+
await keysCmd.createNew(flags);
|
|
68
|
+
else if (subcommand === 'list')
|
|
69
|
+
await keysCmd.list(flags);
|
|
72
70
|
else if (subcommand === 'revoke')
|
|
73
|
-
await
|
|
71
|
+
await keysCmd.revoke(restArgs[0], flags);
|
|
74
72
|
else
|
|
75
73
|
printHelp();
|
|
76
74
|
break;
|
|
77
75
|
case 'org':
|
|
78
|
-
if (flags.help
|
|
79
|
-
(0, output_js_1.info)('Usage: myapi org <subcommand>\n\nSubcommands:\n list List organizations\n create Create an organization');
|
|
76
|
+
if (!subcommand || (flags.help && !subcommand)) {
|
|
77
|
+
(0, output_js_1.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');
|
|
80
78
|
break;
|
|
81
79
|
}
|
|
82
80
|
if (subcommand === 'list')
|
|
83
81
|
await orgCmd.list(flags);
|
|
84
82
|
else if (subcommand === 'create')
|
|
85
83
|
await orgCmd.create(flags);
|
|
84
|
+
else if (subcommand === 'get')
|
|
85
|
+
await orgCmd.get(restArgs[0], flags);
|
|
86
|
+
else if (subcommand === 'delete')
|
|
87
|
+
await orgCmd.del(restArgs[0], flags);
|
|
88
|
+
else if (subcommand === 'import')
|
|
89
|
+
await orgCmd.importOrg(restArgs, flags);
|
|
86
90
|
else
|
|
87
91
|
printHelp();
|
|
88
92
|
break;
|
|
89
93
|
case 'billing':
|
|
90
|
-
if (flags.help
|
|
94
|
+
if (!subcommand || (flags.help && !subcommand)) {
|
|
91
95
|
(0, output_js_1.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');
|
|
92
96
|
break;
|
|
93
97
|
}
|
|
@@ -123,7 +127,7 @@ function printHelp() {
|
|
|
123
127
|
Usage: myapi <command> [subcommand] [args]
|
|
124
128
|
|
|
125
129
|
Commands:
|
|
126
|
-
|
|
130
|
+
keys Manage API keys
|
|
127
131
|
billing Check balance and manage billing
|
|
128
132
|
org Manage organizations
|
|
129
133
|
setup Setup CLI credentials and view integration instructions
|
package/package.json
CHANGED
package/src/commands/billing.ts
CHANGED
|
@@ -1,23 +1,71 @@
|
|
|
1
1
|
import { hq } from '@myapihq/sdk';
|
|
2
2
|
import { requireConfig } from '../config.js';
|
|
3
|
-
import { success, error, printTable, info } from '../output.js';
|
|
3
|
+
import { success, error, printTable, info, printJson } from '../output.js';
|
|
4
4
|
|
|
5
5
|
export async function balance(flags: Record<string, string | boolean>) {
|
|
6
|
+
if (flags.help) {
|
|
7
|
+
info('Usage: myapi billing balance\n\nShows your current account balance, credits, and payment method status.');
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
6
10
|
const config = requireConfig();
|
|
7
11
|
const result = await hq.getBalance(config.api_key);
|
|
8
|
-
|
|
12
|
+
|
|
13
|
+
const bal = result.balance_display || `$${(result.balance_cents / 100).toFixed(2)}`;
|
|
14
|
+
const cred = result.credits_display || `$${((result.credits_cents || 0) / 100).toFixed(2)}`;
|
|
15
|
+
const pm = result.has_payment_method ? 'yes' : 'no';
|
|
16
|
+
|
|
17
|
+
info(`Balance: ${bal} | Credits: ${cred} | Payment method: ${pm}`);
|
|
9
18
|
}
|
|
10
19
|
|
|
11
20
|
export async function history(flags: Record<string, string | boolean>) {
|
|
21
|
+
if (flags.help) {
|
|
22
|
+
info('Usage: myapi billing history [--json]\n\nShows your recent billing transactions and top-ups.');
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
12
25
|
const config = requireConfig();
|
|
13
26
|
const items = await hq.getBillingHistory(config.api_key);
|
|
14
|
-
|
|
27
|
+
|
|
28
|
+
if (flags.json) {
|
|
29
|
+
printJson(items);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const formattedItems = items.map(item => {
|
|
34
|
+
// Attempt to parse the date cleanly (handling Go's "+0000 UTC" suffix)
|
|
35
|
+
const cleanDate = item.created_at.replace(' +0000 UTC', 'Z');
|
|
36
|
+
const date = new Date(cleanDate);
|
|
37
|
+
const dateStr = isNaN(date.getTime()) ? item.created_at : date.toLocaleString();
|
|
38
|
+
|
|
39
|
+
// Format amount
|
|
40
|
+
const isNegative = item.amount_cents < 0;
|
|
41
|
+
const absAmount = Math.abs(item.amount_cents) / 100;
|
|
42
|
+
const amountStr = `${isNegative ? '-' : ''}$${absAmount.toFixed(2)}`;
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
Type: item.type || 'unknown',
|
|
46
|
+
Amount: amountStr,
|
|
47
|
+
Status: item.status ? item.status.charAt(0).toUpperCase() + item.status.slice(1) : '',
|
|
48
|
+
Date: dateStr
|
|
49
|
+
};
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
printTable(formattedItems as unknown as Record<string, unknown>[]);
|
|
15
53
|
}
|
|
16
54
|
|
|
17
55
|
export async function topup(amountStr: string, flags: Record<string, string | boolean>) {
|
|
18
|
-
if (
|
|
56
|
+
if (flags.help) {
|
|
57
|
+
info('Usage: myapi billing topup <amount_in_dollars>\n\nAdds funds to your account balance using your saved payment method.\nExample: myapi billing topup 10.00');
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (!amountStr) {
|
|
61
|
+
error("Missing amount. Usage: myapi billing topup <amount_in_dollars>");
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
19
64
|
const amount = parseFloat(amountStr);
|
|
20
|
-
if (isNaN(amount))
|
|
65
|
+
if (isNaN(amount)) {
|
|
66
|
+
error("Invalid amount. Must be a number in dollars (e.g., 10.00)");
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
21
69
|
|
|
22
70
|
const config = requireConfig();
|
|
23
71
|
const result = await hq.topUp(config.api_key, Math.round(amount * 100));
|
|
@@ -25,6 +73,10 @@ export async function topup(amountStr: string, flags: Record<string, string | bo
|
|
|
25
73
|
}
|
|
26
74
|
|
|
27
75
|
export async function setup(flags: Record<string, string | boolean>) {
|
|
76
|
+
if (flags.help) {
|
|
77
|
+
info('Usage: myapi billing setup\n\nGenerates a secure Stripe Checkout link to add or update your payment method.');
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
28
80
|
const config = requireConfig();
|
|
29
81
|
const result = await hq.setupPayment(config.api_key);
|
|
30
82
|
success(`Open this URL in your browser to set up payment:\n${result.url}`);
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { hq } from '@myapihq/sdk';
|
|
2
|
+
import { requireConfig } from '../config.js';
|
|
3
|
+
import { success, error, printTable, info } from '../output.js';
|
|
4
|
+
import * as readline from 'readline';
|
|
5
|
+
|
|
6
|
+
export async function createNew(flags: Record<string, string | boolean>) {
|
|
7
|
+
if (flags.help) {
|
|
8
|
+
info('Usage: myapi keys create\n\nCreates a new API key. You will be prompted to enter a name for the key.');
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
const config = requireConfig();
|
|
12
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
13
|
+
const name = await new Promise<string>(resolve => rl.question('Enter a name for the new key: ', resolve));
|
|
14
|
+
rl.close();
|
|
15
|
+
|
|
16
|
+
if (!name.trim()) {
|
|
17
|
+
error('Key name cannot be empty.');
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const keyInfo = await hq.createApiKey(config.api_key, name.trim());
|
|
22
|
+
success(`New API key created!\n\nName: ${keyInfo.prefix}...\nKey: ${keyInfo.api_key}\n\nMake sure to copy your new API key now. You won't be able to see it again!`);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export async function list(flags: Record<string, string | boolean>) {
|
|
26
|
+
if (flags.help) {
|
|
27
|
+
info('Usage: myapi keys list\n\nLists all API keys associated with your account.');
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const config = requireConfig();
|
|
31
|
+
const keysList = await hq.listApiKeys(config.api_key);
|
|
32
|
+
|
|
33
|
+
const formattedKeys = keysList.map(k => {
|
|
34
|
+
// Format creation date
|
|
35
|
+
const createdDate = new Date(k.created_at);
|
|
36
|
+
const createdStr = isNaN(createdDate.getTime()) ? k.created_at : createdDate.toLocaleString();
|
|
37
|
+
|
|
38
|
+
// Format last used date
|
|
39
|
+
let lastUsedStr = 'Never';
|
|
40
|
+
if (k.last_used_at) {
|
|
41
|
+
const lastUsedDate = new Date(k.last_used_at);
|
|
42
|
+
lastUsedStr = isNaN(lastUsedDate.getTime()) ? k.last_used_at : lastUsedDate.toLocaleString();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
Name: k.name || 'Unnamed',
|
|
47
|
+
Prefix: k.prefix,
|
|
48
|
+
ID: k.id,
|
|
49
|
+
'Created At': createdStr,
|
|
50
|
+
'Last Used': lastUsedStr
|
|
51
|
+
};
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
printTable(formattedKeys as unknown as Record<string, unknown>[]);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export async function revoke(id: string, flags: Record<string, string | boolean>) {
|
|
58
|
+
if (flags.help) {
|
|
59
|
+
info('Usage: myapi keys revoke <id>\n\nRevokes an API key permanently.');
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (!id) {
|
|
63
|
+
error("Missing key ID. Usage: myapi keys revoke <id>");
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const config = requireConfig();
|
|
67
|
+
await hq.revokeApiKey(config.api_key, id);
|
|
68
|
+
success(`Key ${id} revoked successfully.`);
|
|
69
|
+
}
|
package/src/commands/org.ts
CHANGED
|
@@ -1,44 +1,81 @@
|
|
|
1
1
|
import { hq } from '@myapihq/sdk';
|
|
2
2
|
import { requireConfig } from '../config.js';
|
|
3
|
-
import { success, error, printTable, printJson } from '../output.js';
|
|
3
|
+
import { success, error, printTable, printJson, info } from '../output.js';
|
|
4
4
|
import { sleep } from '../utils.js';
|
|
5
5
|
|
|
6
6
|
export async function create(flags: Record<string, string | boolean>) {
|
|
7
|
-
if (
|
|
7
|
+
if (flags.help) {
|
|
8
|
+
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');
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
if (!flags.name) {
|
|
12
|
+
error("Missing --name flag. Run 'myapi org create --help' for details.");
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
8
15
|
const config = requireConfig();
|
|
9
16
|
const payload: any = { name: flags.name as string };
|
|
10
17
|
if (flags.tagline) payload.tagline = flags.tagline as string;
|
|
11
18
|
if (flags.description) payload.description = flags.description as string;
|
|
19
|
+
if (flags['business-sector']) payload.business_sector = flags['business-sector'] as string;
|
|
20
|
+
if (flags['logo-url']) payload.logo_url = flags['logo-url'] as string;
|
|
12
21
|
|
|
13
22
|
const org = await hq.createOrg(config.api_key, payload);
|
|
14
23
|
success(`Org created! ID: ${org.id}, Name: ${org.name}`);
|
|
15
24
|
}
|
|
16
25
|
|
|
17
26
|
export async function list(flags: Record<string, string | boolean>) {
|
|
27
|
+
if (flags.help) {
|
|
28
|
+
info('Usage: myapi org list\n\nLists all organizations in your account as JSON.');
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
18
31
|
const config = requireConfig();
|
|
19
32
|
const orgs = await hq.listOrgs(config.api_key);
|
|
20
|
-
|
|
33
|
+
printJson(orgs);
|
|
21
34
|
}
|
|
22
35
|
|
|
23
36
|
export async function get(id: string, flags: Record<string, string | boolean>) {
|
|
24
|
-
if (
|
|
37
|
+
if (flags.help) {
|
|
38
|
+
info('Usage: myapi org get <id>\n\nFetches details of a specific organization.');
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
if (!id) {
|
|
42
|
+
error("Missing org id. Usage: myapi org get <id>");
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
25
45
|
const config = requireConfig();
|
|
26
46
|
const org = await hq.getOrg(config.api_key, id);
|
|
27
47
|
printJson(org);
|
|
28
48
|
}
|
|
29
49
|
|
|
30
50
|
export async function del(id: string, flags: Record<string, string | boolean>) {
|
|
31
|
-
if (
|
|
51
|
+
if (flags.help) {
|
|
52
|
+
info('Usage: myapi org delete <id>\n\nDeletes an organization.');
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
if (!id) {
|
|
56
|
+
error("Missing org id. Usage: myapi org delete <id>");
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
32
59
|
const config = requireConfig();
|
|
33
60
|
await hq.deleteOrg(config.api_key, id);
|
|
34
61
|
success(`Org ${id} deleted`);
|
|
35
62
|
}
|
|
36
63
|
|
|
37
|
-
export async function importOrg(
|
|
38
|
-
if (
|
|
64
|
+
export async function importOrg(args: string[], flags: Record<string, string | boolean>) {
|
|
65
|
+
if (flags.help) {
|
|
66
|
+
info('Usage: myapi org import <org_id> <domain>\n\nAutomatically extracts brand info from an existing website and updates the organization.\n\nNote: You must create a placeholder organization first using `myapi org create` to get an org_id.');
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const orgId = args[0];
|
|
70
|
+
const domain = args[1];
|
|
71
|
+
|
|
72
|
+
if (!orgId || !domain) {
|
|
73
|
+
error("Missing arguments. Usage: myapi org import <org_id> <domain>");
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
39
76
|
const config = requireConfig();
|
|
40
77
|
|
|
41
|
-
const result = await hq.importOrg(config.api_key, domain);
|
|
78
|
+
const result = await hq.importOrg(config.api_key, orgId, domain);
|
|
42
79
|
const importId = result.job_id;
|
|
43
80
|
|
|
44
81
|
process.stdout.write("Importing ");
|
package/src/index.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { parseArgs } from './utils.js';
|
|
4
4
|
import { error, info } from './output.js';
|
|
5
5
|
import { MyApiError } from '@myapihq/sdk';
|
|
6
|
-
import * as
|
|
6
|
+
import * as keysCmd from './commands/keys.js';
|
|
7
7
|
import * as billingCmd from './commands/billing.js';
|
|
8
8
|
import * as orgCmd from './commands/org.js';
|
|
9
9
|
import * as setupCmd from './commands/setup.js';
|
|
@@ -21,28 +21,30 @@ async function main() {
|
|
|
21
21
|
}
|
|
22
22
|
await setupCmd.setup();
|
|
23
23
|
break;
|
|
24
|
-
case '
|
|
25
|
-
if (flags.help
|
|
26
|
-
info('Usage: myapi
|
|
24
|
+
case 'keys':
|
|
25
|
+
if (!subcommand || (flags.help && !subcommand)) {
|
|
26
|
+
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>)');
|
|
27
27
|
break;
|
|
28
28
|
}
|
|
29
|
-
if (subcommand === 'create') await
|
|
30
|
-
else if (subcommand === '
|
|
31
|
-
else if (subcommand === '
|
|
32
|
-
else if (subcommand === 'revoke') await accountCmd.revokeKey(restArgs[0], flags);
|
|
29
|
+
if (subcommand === 'create') await keysCmd.createNew(flags);
|
|
30
|
+
else if (subcommand === 'list') await keysCmd.list(flags);
|
|
31
|
+
else if (subcommand === 'revoke') await keysCmd.revoke(restArgs[0], flags);
|
|
33
32
|
else printHelp();
|
|
34
33
|
break;
|
|
35
34
|
case 'org':
|
|
36
|
-
if (flags.help
|
|
37
|
-
info('Usage: myapi org <subcommand>\n\nSubcommands:\n list List organizations\n create Create an organization');
|
|
35
|
+
if (!subcommand || (flags.help && !subcommand)) {
|
|
36
|
+
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');
|
|
38
37
|
break;
|
|
39
38
|
}
|
|
40
39
|
if (subcommand === 'list') await orgCmd.list(flags);
|
|
41
40
|
else if (subcommand === 'create') await orgCmd.create(flags);
|
|
41
|
+
else if (subcommand === 'get') await orgCmd.get(restArgs[0], flags);
|
|
42
|
+
else if (subcommand === 'delete') await orgCmd.del(restArgs[0], flags);
|
|
43
|
+
else if (subcommand === 'import') await orgCmd.importOrg(restArgs, flags);
|
|
42
44
|
else printHelp();
|
|
43
45
|
break;
|
|
44
46
|
case 'billing':
|
|
45
|
-
if (flags.help
|
|
47
|
+
if (!subcommand || (flags.help && !subcommand)) {
|
|
46
48
|
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');
|
|
47
49
|
break;
|
|
48
50
|
}
|
|
@@ -71,7 +73,7 @@ function printHelp() {
|
|
|
71
73
|
Usage: myapi <command> [subcommand] [args]
|
|
72
74
|
|
|
73
75
|
Commands:
|
|
74
|
-
|
|
76
|
+
keys Manage API keys
|
|
75
77
|
billing Check balance and manage billing
|
|
76
78
|
org Manage organizations
|
|
77
79
|
setup Setup CLI credentials and view integration instructions
|
package/src/commands/account.ts
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { hq } from '@myapihq/sdk';
|
|
2
|
-
import { saveConfig, requireConfig } from '../config.js';
|
|
3
|
-
import { success, error, printTable } from '../output.js';
|
|
4
|
-
import * as readline from 'readline';
|
|
5
|
-
|
|
6
|
-
export async function create() {
|
|
7
|
-
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
8
|
-
const key = await new Promise<string>(resolve => rl.question('Paste your API key (get it from https://myapihq.com): ', resolve));
|
|
9
|
-
rl.close();
|
|
10
|
-
|
|
11
|
-
if (!key.trim()) {
|
|
12
|
-
error('API key cannot be empty.');
|
|
13
|
-
return;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
saveConfig({ api_key: key.trim(), account_id: '', pin: '' });
|
|
17
|
-
success(`API key saved to ~/.myapi/config.json`);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export async function token(flags: Record<string, string | boolean>) {
|
|
21
|
-
let pin = flags.pin as string;
|
|
22
|
-
if (!pin) {
|
|
23
|
-
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
24
|
-
pin = await new Promise<string>(resolve => rl.question('Enter PIN: ', resolve));
|
|
25
|
-
rl.close();
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const result = await hq.recoverAgentToken(pin);
|
|
29
|
-
const keyInfo = await hq.createApiKey(result.token, 'recovered');
|
|
30
|
-
|
|
31
|
-
const config = requireConfig();
|
|
32
|
-
config.api_key = keyInfo.api_key;
|
|
33
|
-
saveConfig(config);
|
|
34
|
-
|
|
35
|
-
success(`Token recovered! New API Key: ${keyInfo.api_key}`);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export async function listKeys(flags: Record<string, string | boolean>) {
|
|
39
|
-
const config = requireConfig();
|
|
40
|
-
const keys = await hq.listApiKeys(config.api_key);
|
|
41
|
-
printTable(keys as unknown as Record<string, unknown>[]);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export async function revokeKey(id: string, flags: Record<string, string | boolean>) {
|
|
45
|
-
if (!id) error("Missing key id");
|
|
46
|
-
const config = requireConfig();
|
|
47
|
-
await hq.revokeApiKey(config.api_key, id);
|
|
48
|
-
success(`Key ${id} revoked`);
|
|
49
|
-
}
|