@myapihq/cli 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/account.d.ts +4 -0
- package/dist/commands/account.js +79 -0
- package/dist/commands/billing.d.ts +4 -0
- package/dist/commands/billing.js +34 -0
- package/dist/commands/domain.d.ts +5 -0
- package/dist/commands/domain.js +56 -0
- package/dist/commands/email.d.ts +8 -0
- package/dist/commands/email.js +95 -0
- package/dist/commands/funnel.d.ts +3 -0
- package/dist/commands/funnel.js +37 -0
- package/dist/commands/image.d.ts +2 -0
- package/dist/commands/image.js +47 -0
- package/dist/commands/org.d.ts +5 -0
- package/dist/commands/org.js +67 -0
- package/dist/commands/storage.d.ts +3 -0
- package/dist/commands/storage.js +27 -0
- package/dist/commands/webhook.d.ts +3 -0
- package/dist/commands/webhook.js +28 -0
- package/dist/commands/workflow.d.ts +5 -0
- package/dist/commands/workflow.js +57 -0
- package/dist/config.d.ts +8 -0
- package/dist/config.js +69 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +105 -0
- package/dist/output.d.ts +5 -0
- package/dist/output.js +42 -0
- package/dist/utils.d.ts +5 -0
- package/dist/utils.js +34 -0
- package/package.json +20 -0
- package/src/commands/account.ts +48 -0
- package/src/commands/billing.ts +31 -0
- package/src/commands/domain.ts +49 -0
- package/src/commands/email.ts +93 -0
- package/src/commands/funnel.ts +37 -0
- package/src/commands/image.ts +45 -0
- package/src/commands/org.ts +64 -0
- package/src/commands/storage.ts +23 -0
- package/src/commands/webhook.ts +25 -0
- package/src/commands/workflow.ts +54 -0
- package/src/config.ts +40 -0
- package/src/index.ts +68 -0
- package/src/output.ts +47 -0
- package/src/utils.ts +30 -0
- package/tsconfig.json +14 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { storage as sdkStorage } from '@myapihq/sdk';
|
|
2
|
+
import { requireConfig } from '../config.js';
|
|
3
|
+
import { success, error, printTable } from '../output.js';
|
|
4
|
+
|
|
5
|
+
export async function list(flags: Record<string, string | boolean>) {
|
|
6
|
+
const config = requireConfig();
|
|
7
|
+
const assets = await sdkStorage.listAssets(config.api_key);
|
|
8
|
+
printTable(assets as unknown as Record<string, unknown>[]);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export async function ingest(url: string, flags: Record<string, string | boolean>) {
|
|
12
|
+
if (!url) error("Missing url");
|
|
13
|
+
const config = requireConfig();
|
|
14
|
+
const res = await sdkStorage.ingestAsset(config.api_key, url, flags.name as string);
|
|
15
|
+
success(`Asset ingested! ID: ${res.asset_id}\nHosted URL: ${res.url}`);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export async function del(id: string, flags: Record<string, string | boolean>) {
|
|
19
|
+
if (!id) error("Missing id");
|
|
20
|
+
const config = requireConfig();
|
|
21
|
+
await sdkStorage.deleteAsset(config.api_key, id);
|
|
22
|
+
success(`Asset ${id} deleted`);
|
|
23
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { webhook as sdkWebhook } from '@myapihq/sdk';
|
|
2
|
+
import { requireConfig } from '../config.js';
|
|
3
|
+
import { success, error, printTable } from '../output.js';
|
|
4
|
+
|
|
5
|
+
export async function list(flags: Record<string, string | boolean>) {
|
|
6
|
+
const config = requireConfig();
|
|
7
|
+
const endpoints = await sdkWebhook.listEndpoints(config.api_key);
|
|
8
|
+
printTable(endpoints as unknown as Record<string, unknown>[]);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export async function create(flags: Record<string, string | boolean>) {
|
|
12
|
+
if (!flags['org-id'] || !flags.name || !flags.description) {
|
|
13
|
+
error("Missing --org-id, --name, or --description flags");
|
|
14
|
+
}
|
|
15
|
+
const config = requireConfig();
|
|
16
|
+
const res = await sdkWebhook.createEndpoint(config.api_key, flags['org-id'] as string, flags.name as string, flags.description as string);
|
|
17
|
+
success(`Webhook created! ID: ${res.id}\nInbound URL: ${res.inbound_url}`);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export async function del(id: string, flags: Record<string, string | boolean>) {
|
|
21
|
+
if (!id) error("Missing id");
|
|
22
|
+
const config = requireConfig();
|
|
23
|
+
await sdkWebhook.deleteEndpoint(config.api_key, id);
|
|
24
|
+
success(`Webhook ${id} deleted`);
|
|
25
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { workflow as sdkWorkflow } from '@myapihq/sdk';
|
|
2
|
+
import { requireConfig } from '../config.js';
|
|
3
|
+
import { success, error, printTable } from '../output.js';
|
|
4
|
+
|
|
5
|
+
export async function list(flags: Record<string, string | boolean>) {
|
|
6
|
+
const config = requireConfig();
|
|
7
|
+
const workflows = await sdkWorkflow.listWorkflows(config.api_key);
|
|
8
|
+
printTable(workflows as unknown as Record<string, unknown>[]);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export async function create(flags: Record<string, string | boolean>) {
|
|
12
|
+
if (!flags['org-id'] || !flags.name || !flags['endpoint-id'] || !flags.steps) {
|
|
13
|
+
error("Missing --org-id, --name, --endpoint-id, or --steps flags");
|
|
14
|
+
}
|
|
15
|
+
const config = requireConfig();
|
|
16
|
+
|
|
17
|
+
let steps;
|
|
18
|
+
try {
|
|
19
|
+
steps = JSON.parse(flags.steps as string);
|
|
20
|
+
} catch (err) {
|
|
21
|
+
error("Invalid JSON for --steps");
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const wf = await sdkWorkflow.createWorkflow(config.api_key, {
|
|
25
|
+
org_id: flags['org-id'] as string,
|
|
26
|
+
name: flags.name as string,
|
|
27
|
+
trigger_config: { endpoint_id: flags['endpoint-id'] as string },
|
|
28
|
+
steps
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
await sdkWorkflow.enableWorkflow(config.api_key, wf.id);
|
|
32
|
+
success(`Workflow created and enabled! ID: ${wf.id}`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export async function enable(id: string, flags: Record<string, string | boolean>) {
|
|
36
|
+
if (!id) error("Missing id");
|
|
37
|
+
const config = requireConfig();
|
|
38
|
+
await sdkWorkflow.enableWorkflow(config.api_key, id);
|
|
39
|
+
success(`Workflow ${id} enabled`);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export async function disable(id: string, flags: Record<string, string | boolean>) {
|
|
43
|
+
if (!id) error("Missing id");
|
|
44
|
+
const config = requireConfig();
|
|
45
|
+
await sdkWorkflow.disableWorkflow(config.api_key, id);
|
|
46
|
+
success(`Workflow ${id} disabled`);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export async function runs(id: string, flags: Record<string, string | boolean>) {
|
|
50
|
+
if (!id) error("Missing id");
|
|
51
|
+
const config = requireConfig();
|
|
52
|
+
const runs = await sdkWorkflow.listWorkflowRuns(config.api_key, id);
|
|
53
|
+
printTable(runs as unknown as Record<string, unknown>[]);
|
|
54
|
+
}
|
package/src/config.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import * as os from 'os';
|
|
4
|
+
|
|
5
|
+
export interface Config {
|
|
6
|
+
api_key: string;
|
|
7
|
+
account_id: string;
|
|
8
|
+
pin: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const CONFIG_DIR = path.join(os.homedir(), '.myapi');
|
|
12
|
+
const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
|
|
13
|
+
|
|
14
|
+
export function loadConfig(): Config | null {
|
|
15
|
+
try {
|
|
16
|
+
if (!fs.existsSync(CONFIG_FILE)) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
const data = fs.readFileSync(CONFIG_FILE, 'utf-8');
|
|
20
|
+
return JSON.parse(data) as Config;
|
|
21
|
+
} catch (err) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function saveConfig(config: Config): void {
|
|
27
|
+
if (!fs.existsSync(CONFIG_DIR)) {
|
|
28
|
+
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
29
|
+
}
|
|
30
|
+
fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), { mode: 0o600 });
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function requireConfig(): Config {
|
|
34
|
+
const config = loadConfig();
|
|
35
|
+
if (!config || !config.api_key) {
|
|
36
|
+
console.error("No API key found. Run: myapi account create");
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
return config;
|
|
40
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { parseArgs } from './utils.js';
|
|
4
|
+
import { error, info } from './output.js';
|
|
5
|
+
import { MyApiError } from '@myapihq/sdk';
|
|
6
|
+
|
|
7
|
+
import * as accountCmd from './commands/account.js';
|
|
8
|
+
import * as billingCmd from './commands/billing.js';
|
|
9
|
+
|
|
10
|
+
async function main() {
|
|
11
|
+
const { args, flags } = parseArgs(process.argv.slice(2));
|
|
12
|
+
|
|
13
|
+
if (args.length === 0) {
|
|
14
|
+
printHelp();
|
|
15
|
+
process.exit(0);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const [command, subcommand, ...restArgs] = args;
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
switch (command) {
|
|
22
|
+
case 'account':
|
|
23
|
+
if (subcommand === 'create') await accountCmd.create();
|
|
24
|
+
else if (subcommand === 'token') await accountCmd.token(flags);
|
|
25
|
+
else if (subcommand === 'keys') await accountCmd.listKeys(flags);
|
|
26
|
+
else if (subcommand === 'revoke') await accountCmd.revokeKey(restArgs[0], flags);
|
|
27
|
+
else printHelp();
|
|
28
|
+
break;
|
|
29
|
+
|
|
30
|
+
case 'billing':
|
|
31
|
+
if (subcommand === 'balance') await billingCmd.balance(flags);
|
|
32
|
+
else if (subcommand === 'history') await billingCmd.history(flags);
|
|
33
|
+
else if (subcommand === 'topup') await billingCmd.topup(restArgs[0], flags);
|
|
34
|
+
else if (subcommand === 'setup') await billingCmd.setup(flags);
|
|
35
|
+
else printHelp();
|
|
36
|
+
break;
|
|
37
|
+
|
|
38
|
+
default:
|
|
39
|
+
printHelp();
|
|
40
|
+
process.exit(0);
|
|
41
|
+
}
|
|
42
|
+
} catch (err: any) {
|
|
43
|
+
if (err instanceof MyApiError) {
|
|
44
|
+
if (err.status === 402) {
|
|
45
|
+
error("Insufficient balance. Run: myapi billing topup <amount>");
|
|
46
|
+
} else if (err.status === 401) {
|
|
47
|
+
error("Invalid API key. Run: myapi account create");
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
error(err.message || String(err));
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function printHelp() {
|
|
55
|
+
info(`myapi - MyAPI command-line interface
|
|
56
|
+
|
|
57
|
+
Usage: myapi <command> [subcommand] [args]
|
|
58
|
+
|
|
59
|
+
Commands:
|
|
60
|
+
account Manage your account and API keys
|
|
61
|
+
billing Check balance and top up
|
|
62
|
+
|
|
63
|
+
Run "myapi <command>" for subcommand help.`);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
main().catch(err => {
|
|
67
|
+
error(err.message || String(err));
|
|
68
|
+
});
|
package/src/output.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export function success(message: string): void {
|
|
2
|
+
console.log(`\x1b[32m✓\x1b[0m ${message}`);
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export function error(message: string): never {
|
|
6
|
+
console.error(`\x1b[31m✗\x1b[0m ${message}`);
|
|
7
|
+
process.exit(1);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function info(message: string): void {
|
|
11
|
+
console.log(message);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function printJson(data: unknown): void {
|
|
15
|
+
console.log(JSON.stringify(data, null, 2));
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function printTable(rows: Record<string, unknown>[]): void {
|
|
19
|
+
if (process.argv.includes('--json')) {
|
|
20
|
+
printJson(rows);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (rows.length === 0) {
|
|
25
|
+
console.log("No data found.");
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const columns = Object.keys(rows[0]);
|
|
30
|
+
const colWidths = columns.map(col => {
|
|
31
|
+
return Math.max(
|
|
32
|
+
col.length,
|
|
33
|
+
...rows.map(row => String(row[col] ?? '').length)
|
|
34
|
+
);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const printRow = (row: string[]) => {
|
|
38
|
+
console.log(row.map((cell, i) => cell.padEnd(colWidths[i] + 2)).join(''));
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
printRow(columns);
|
|
42
|
+
console.log(colWidths.map(w => '-'.repeat(w + 2)).join(''));
|
|
43
|
+
|
|
44
|
+
for (const row of rows) {
|
|
45
|
+
printRow(columns.map(col => String(row[col] ?? '')));
|
|
46
|
+
}
|
|
47
|
+
}
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
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.startsWith('--')) {
|
|
8
|
+
if (arg.includes('=')) {
|
|
9
|
+
const [key, value] = arg.slice(2).split('=', 2);
|
|
10
|
+
flags[key] = value;
|
|
11
|
+
} else {
|
|
12
|
+
const next = argv[i + 1];
|
|
13
|
+
if (next && !next.startsWith('--')) {
|
|
14
|
+
flags[arg.slice(2)] = next;
|
|
15
|
+
i++;
|
|
16
|
+
} else {
|
|
17
|
+
flags[arg.slice(2)] = true;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
} else {
|
|
21
|
+
args.push(arg);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return { args, flags };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function sleep(ms: number) {
|
|
29
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
30
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"declaration": true,
|
|
7
|
+
"outDir": "./dist",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"forceConsistentCasingInFileNames": true
|
|
12
|
+
},
|
|
13
|
+
"include": ["src/**/*"]
|
|
14
|
+
}
|