@batadata/cli 0.1.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/api.d.ts +28 -0
- package/dist/api.js +115 -0
- package/dist/api.js.map +1 -0
- package/dist/args.d.ts +20 -0
- package/dist/args.js +42 -0
- package/dist/args.js.map +1 -0
- package/dist/commands/api-keys.d.ts +11 -0
- package/dist/commands/api-keys.js +223 -0
- package/dist/commands/api-keys.js.map +1 -0
- package/dist/commands/auth.d.ts +3 -0
- package/dist/commands/auth.js +133 -0
- package/dist/commands/auth.js.map +1 -0
- package/dist/commands/connect.d.ts +7 -0
- package/dist/commands/connect.js +103 -0
- package/dist/commands/connect.js.map +1 -0
- package/dist/commands/create.d.ts +7 -0
- package/dist/commands/create.js +197 -0
- package/dist/commands/create.js.map +1 -0
- package/dist/commands/db.d.ts +8 -0
- package/dist/commands/db.js +316 -0
- package/dist/commands/db.js.map +1 -0
- package/dist/commands/dev.d.ts +1 -0
- package/dist/commands/dev.js +28 -0
- package/dist/commands/dev.js.map +1 -0
- package/dist/commands/generate.d.ts +1 -0
- package/dist/commands/generate.js +83 -0
- package/dist/commands/generate.js.map +1 -0
- package/dist/commands/migrate.d.ts +1 -0
- package/dist/commands/migrate.js +38 -0
- package/dist/commands/migrate.js.map +1 -0
- package/dist/commands/projects.d.ts +5 -0
- package/dist/commands/projects.js +259 -0
- package/dist/commands/projects.js.map +1 -0
- package/dist/commands/schema.d.ts +1 -0
- package/dist/commands/schema.js +38 -0
- package/dist/commands/schema.js.map +1 -0
- package/dist/commands/status.d.ts +7 -0
- package/dist/commands/status.js +106 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/config.d.ts +45 -0
- package/dist/config.js +96 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +169 -0
- package/dist/index.js.map +1 -0
- package/dist/utils/logger.d.ts +26 -0
- package/dist/utils/logger.js +130 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/open.d.ts +1 -0
- package/dist/utils/open.js +20 -0
- package/dist/utils/open.js.map +1 -0
- package/dist/utils/prompts.d.ts +7 -0
- package/dist/utils/prompts.js +92 -0
- package/dist/utils/prompts.js.map +1 -0
- package/package.json +39 -0
package/dist/api.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export interface ApiResponse<T = unknown> {
|
|
2
|
+
ok: boolean;
|
|
3
|
+
status: number;
|
|
4
|
+
data: T;
|
|
5
|
+
}
|
|
6
|
+
export declare function request<T = unknown>(method: string, path: string, options?: {
|
|
7
|
+
token?: string;
|
|
8
|
+
body?: Record<string, unknown>;
|
|
9
|
+
query?: Record<string, string>;
|
|
10
|
+
}): Promise<ApiResponse<T>>;
|
|
11
|
+
/**
|
|
12
|
+
* Extract a human-readable error message from a failed API response.
|
|
13
|
+
* Surfaces the real server error (e.g. "Invalid API key") instead of a
|
|
14
|
+
* generic placeholder so agents see what actually went wrong.
|
|
15
|
+
*/
|
|
16
|
+
export declare function apiError(res: ApiResponse, fallback?: string): string;
|
|
17
|
+
export declare function resolveTeamId(token: string): Promise<string | undefined>;
|
|
18
|
+
/**
|
|
19
|
+
* List endpoints return `{ data: [...], pagination }` (not a bare array).
|
|
20
|
+
* Older/other endpoints may return a bare array or `{ projects: [...] }`.
|
|
21
|
+
* Normalize all of them to a plain array.
|
|
22
|
+
*/
|
|
23
|
+
export declare function asList<T = unknown>(data: unknown): T[];
|
|
24
|
+
export declare const api: {
|
|
25
|
+
get: <T = unknown>(path: string, token?: string, query?: Record<string, string>) => Promise<ApiResponse<T>>;
|
|
26
|
+
post: <T = unknown>(path: string, body: Record<string, unknown>, token?: string) => Promise<ApiResponse<T>>;
|
|
27
|
+
del: <T = unknown>(path: string, token?: string, query?: Record<string, string>) => Promise<ApiResponse<T>>;
|
|
28
|
+
};
|
package/dist/api.js
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import * as https from "node:https";
|
|
2
|
+
import * as http from "node:http";
|
|
3
|
+
import { URL } from "node:url";
|
|
4
|
+
import { getApiUrl, loadConfig } from "./config.js";
|
|
5
|
+
export async function request(method, path, options = {}) {
|
|
6
|
+
const baseUrl = getApiUrl();
|
|
7
|
+
const url = new URL(path, baseUrl);
|
|
8
|
+
if (options.query) {
|
|
9
|
+
for (const [key, value] of Object.entries(options.query)) {
|
|
10
|
+
if (value !== undefined) {
|
|
11
|
+
url.searchParams.set(key, value);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
const headers = {
|
|
16
|
+
"Content-Type": "application/json",
|
|
17
|
+
"User-Agent": "@batadata/cli 0.1.0",
|
|
18
|
+
};
|
|
19
|
+
if (options.token) {
|
|
20
|
+
headers["Authorization"] = `Bearer ${options.token}`;
|
|
21
|
+
}
|
|
22
|
+
const bodyStr = options.body ? JSON.stringify(options.body) : undefined;
|
|
23
|
+
return new Promise((resolve, reject) => {
|
|
24
|
+
const transport = url.protocol === "https:" ? https : http;
|
|
25
|
+
const req = transport.request(url, {
|
|
26
|
+
method,
|
|
27
|
+
headers,
|
|
28
|
+
}, (res) => {
|
|
29
|
+
let data = "";
|
|
30
|
+
res.on("data", (chunk) => (data += chunk));
|
|
31
|
+
res.on("end", () => {
|
|
32
|
+
try {
|
|
33
|
+
const parsed = data ? JSON.parse(data) : {};
|
|
34
|
+
resolve({
|
|
35
|
+
ok: (res.statusCode || 0) >= 200 && (res.statusCode || 0) < 300,
|
|
36
|
+
status: res.statusCode || 0,
|
|
37
|
+
data: parsed,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
resolve({
|
|
42
|
+
ok: false,
|
|
43
|
+
status: res.statusCode || 0,
|
|
44
|
+
data: { error: data },
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
req.on("error", reject);
|
|
50
|
+
req.setTimeout(30000, () => {
|
|
51
|
+
req.destroy();
|
|
52
|
+
reject(new Error("Request timed out"));
|
|
53
|
+
});
|
|
54
|
+
if (bodyStr) {
|
|
55
|
+
req.write(bodyStr);
|
|
56
|
+
}
|
|
57
|
+
req.end();
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Extract a human-readable error message from a failed API response.
|
|
62
|
+
* Surfaces the real server error (e.g. "Invalid API key") instead of a
|
|
63
|
+
* generic placeholder so agents see what actually went wrong.
|
|
64
|
+
*/
|
|
65
|
+
export function apiError(res, fallback = "Request failed") {
|
|
66
|
+
const data = res.data;
|
|
67
|
+
const msg = data && typeof data.error === "string" ? data.error : undefined;
|
|
68
|
+
const code = data && typeof data.code === "string" ? ` (${data.code})` : "";
|
|
69
|
+
if (msg)
|
|
70
|
+
return `${msg}${code}`;
|
|
71
|
+
return `${fallback} (HTTP ${res.status || "?"})`;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Resolve the team id to operate on. Headless agents (just BATA_API_KEY, no
|
|
75
|
+
* prior `bata login`) have no saved defaultTeam, and the API requires a team
|
|
76
|
+
* for project list/create. So fall back to the user's first team. Cached for
|
|
77
|
+
* the process lifetime. Returns undefined only if the user has no teams.
|
|
78
|
+
*/
|
|
79
|
+
let _cachedTeamId;
|
|
80
|
+
export async function resolveTeamId(token) {
|
|
81
|
+
const saved = loadConfig().defaultTeam;
|
|
82
|
+
if (saved)
|
|
83
|
+
return saved;
|
|
84
|
+
if (_cachedTeamId)
|
|
85
|
+
return _cachedTeamId;
|
|
86
|
+
const res = await request("GET", "/v1/teams", { token });
|
|
87
|
+
if (!res.ok)
|
|
88
|
+
return undefined;
|
|
89
|
+
const data = res.data;
|
|
90
|
+
const teams = Array.isArray(data) ? data : data?.teams ?? [];
|
|
91
|
+
_cachedTeamId = teams[0]?.id;
|
|
92
|
+
return _cachedTeamId;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* List endpoints return `{ data: [...], pagination }` (not a bare array).
|
|
96
|
+
* Older/other endpoints may return a bare array or `{ projects: [...] }`.
|
|
97
|
+
* Normalize all of them to a plain array.
|
|
98
|
+
*/
|
|
99
|
+
export function asList(data) {
|
|
100
|
+
if (Array.isArray(data))
|
|
101
|
+
return data;
|
|
102
|
+
const d = data;
|
|
103
|
+
if (d && Array.isArray(d.data))
|
|
104
|
+
return d.data;
|
|
105
|
+
if (d && Array.isArray(d.projects))
|
|
106
|
+
return d.projects;
|
|
107
|
+
return [];
|
|
108
|
+
}
|
|
109
|
+
// Convenience methods
|
|
110
|
+
export const api = {
|
|
111
|
+
get: (path, token, query) => request("GET", path, { token, query }),
|
|
112
|
+
post: (path, body, token) => request("POST", path, { token, body }),
|
|
113
|
+
del: (path, token, query) => request("DELETE", path, { token, query }),
|
|
114
|
+
};
|
|
115
|
+
//# sourceMappingURL=api.js.map
|
package/dist/api.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
|
package/dist/args.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface GlobalFlags {
|
|
2
|
+
json: boolean;
|
|
3
|
+
apiKey?: string;
|
|
4
|
+
apiUrl?: string;
|
|
5
|
+
yes: boolean;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Extract global flags from anywhere in argv, install them into the runtime
|
|
9
|
+
* context, and return the remaining (non-global) args plus the parsed flags.
|
|
10
|
+
*
|
|
11
|
+
* Recognized global flags (work in any position):
|
|
12
|
+
* --json emit machine-readable JSON for read commands
|
|
13
|
+
* --api-key <key> credential (overrides BATA_API_KEY / saved token)
|
|
14
|
+
* --api-url <url> API base URL (overrides BATA_API_URL / saved / default)
|
|
15
|
+
* --yes, -y skip interactive confirmations
|
|
16
|
+
*/
|
|
17
|
+
export declare function parseGlobalFlags(argv: string[]): {
|
|
18
|
+
rest: string[];
|
|
19
|
+
flags: GlobalFlags;
|
|
20
|
+
};
|
package/dist/args.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { setRuntime } from "./config.js";
|
|
2
|
+
/**
|
|
3
|
+
* Extract global flags from anywhere in argv, install them into the runtime
|
|
4
|
+
* context, and return the remaining (non-global) args plus the parsed flags.
|
|
5
|
+
*
|
|
6
|
+
* Recognized global flags (work in any position):
|
|
7
|
+
* --json emit machine-readable JSON for read commands
|
|
8
|
+
* --api-key <key> credential (overrides BATA_API_KEY / saved token)
|
|
9
|
+
* --api-url <url> API base URL (overrides BATA_API_URL / saved / default)
|
|
10
|
+
* --yes, -y skip interactive confirmations
|
|
11
|
+
*/
|
|
12
|
+
export function parseGlobalFlags(argv) {
|
|
13
|
+
const flags = { json: false, yes: false };
|
|
14
|
+
const rest = [];
|
|
15
|
+
for (let i = 0; i < argv.length; i++) {
|
|
16
|
+
const arg = argv[i];
|
|
17
|
+
if (arg === "--json") {
|
|
18
|
+
flags.json = true;
|
|
19
|
+
}
|
|
20
|
+
else if (arg === "--yes" || arg === "-y") {
|
|
21
|
+
flags.yes = true;
|
|
22
|
+
}
|
|
23
|
+
else if (arg === "--api-key") {
|
|
24
|
+
flags.apiKey = argv[++i];
|
|
25
|
+
}
|
|
26
|
+
else if (arg.startsWith("--api-key=")) {
|
|
27
|
+
flags.apiKey = arg.slice("--api-key=".length);
|
|
28
|
+
}
|
|
29
|
+
else if (arg === "--api-url") {
|
|
30
|
+
flags.apiUrl = argv[++i];
|
|
31
|
+
}
|
|
32
|
+
else if (arg.startsWith("--api-url=")) {
|
|
33
|
+
flags.apiUrl = arg.slice("--api-url=".length);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
rest.push(arg);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
setRuntime({ json: flags.json, apiKey: flags.apiKey, apiUrl: flags.apiUrl });
|
|
40
|
+
return { rest, flags };
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=args.js.map
|
package/dist/args.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"args.js","sourceRoot":"","sources":["../src/args.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AASzC;;;;;;;;;GASG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAc;IAC7C,MAAM,KAAK,GAAgB,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;IACvD,MAAM,IAAI,GAAa,EAAE,CAAC;IAE1B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,IAAI,GAAG,KAAK,QAAQ,EAAE,CAAC;YACrB,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC;QACpB,CAAC;aAAM,IAAI,GAAG,KAAK,OAAO,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YAC3C,KAAK,CAAC,GAAG,GAAG,IAAI,CAAC;QACnB,CAAC;aAAM,IAAI,GAAG,KAAK,WAAW,EAAE,CAAC;YAC/B,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;QAC3B,CAAC;aAAM,IAAI,GAAG,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;YACxC,KAAK,CAAC,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;QAChD,CAAC;aAAM,IAAI,GAAG,KAAK,WAAW,EAAE,CAAC;YAC/B,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;QAC3B,CAAC;aAAM,IAAI,GAAG,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;YACxC,KAAK,CAAC,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;QAChD,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACjB,CAAC;IACH,CAAC;IAED,UAAU,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;IAC7E,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;AACzB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* bata api-keys — Manage API keys for headless / agent access.
|
|
3
|
+
*
|
|
4
|
+
* Subcommands:
|
|
5
|
+
* create [--name <n>] Generate a new key (shown ONCE).
|
|
6
|
+
* list List active (non-revoked) keys.
|
|
7
|
+
* revoke <id> [--yes] Revoke a key.
|
|
8
|
+
*
|
|
9
|
+
* Honors --json, --api-key / BATA_API_KEY, --api-url / BATA_API_URL.
|
|
10
|
+
*/
|
|
11
|
+
export declare function handleApiKeys(args: string[]): Promise<void>;
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* bata api-keys — Manage API keys for headless / agent access.
|
|
3
|
+
*
|
|
4
|
+
* Subcommands:
|
|
5
|
+
* create [--name <n>] Generate a new key (shown ONCE).
|
|
6
|
+
* list List active (non-revoked) keys.
|
|
7
|
+
* revoke <id> [--yes] Revoke a key.
|
|
8
|
+
*
|
|
9
|
+
* Honors --json, --api-key / BATA_API_KEY, --api-url / BATA_API_URL.
|
|
10
|
+
*/
|
|
11
|
+
import { api, apiError } from "../api.js";
|
|
12
|
+
import { requireToken, isJsonMode } from "../config.js";
|
|
13
|
+
import { colors, log, json, success, error, warn, spinner, table, kvList, heading } from "../utils/logger.js";
|
|
14
|
+
import { prompt, confirm } from "../utils/prompts.js";
|
|
15
|
+
function parseFlag(args, name) {
|
|
16
|
+
for (let i = 0; i < args.length; i++) {
|
|
17
|
+
if (args[i] === name && args[i + 1])
|
|
18
|
+
return args[i + 1];
|
|
19
|
+
if (args[i].startsWith(`${name}=`))
|
|
20
|
+
return args[i].slice(name.length + 1);
|
|
21
|
+
}
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
function positional(args) {
|
|
25
|
+
const out = [];
|
|
26
|
+
for (let i = 0; i < args.length; i++) {
|
|
27
|
+
const a = args[i];
|
|
28
|
+
if (a === "--name") {
|
|
29
|
+
i++; // skip value
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
if (a.startsWith("--"))
|
|
33
|
+
continue;
|
|
34
|
+
out.push(a);
|
|
35
|
+
}
|
|
36
|
+
return out;
|
|
37
|
+
}
|
|
38
|
+
function formatDate(iso) {
|
|
39
|
+
if (!iso)
|
|
40
|
+
return "-";
|
|
41
|
+
const d = new Date(iso);
|
|
42
|
+
if (isNaN(d.getTime()))
|
|
43
|
+
return "-";
|
|
44
|
+
return d.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" });
|
|
45
|
+
}
|
|
46
|
+
async function create(args) {
|
|
47
|
+
const token = requireToken();
|
|
48
|
+
const jsonMode = isJsonMode();
|
|
49
|
+
let name = parseFlag(args, "--name");
|
|
50
|
+
if (!name) {
|
|
51
|
+
if (jsonMode || !process.stdin.isTTY) {
|
|
52
|
+
// Headless: default a sensible name rather than block on a prompt.
|
|
53
|
+
name = `cli-${new Date().toISOString().slice(0, 10)}`;
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
name = await prompt("Key name", `cli-${new Date().toISOString().slice(0, 10)}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const s = jsonMode ? null : spinner("Creating API key");
|
|
60
|
+
const res = await api.post("/v1/api-keys", { name }, token);
|
|
61
|
+
s?.stop();
|
|
62
|
+
if (!res.ok) {
|
|
63
|
+
if (jsonMode) {
|
|
64
|
+
json({ error: apiError(res, "Failed to create API key") });
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
error(apiError(res, "Failed to create API key"));
|
|
68
|
+
}
|
|
69
|
+
process.exit(1);
|
|
70
|
+
}
|
|
71
|
+
const k = res.data;
|
|
72
|
+
if (jsonMode) {
|
|
73
|
+
json({
|
|
74
|
+
id: k.id,
|
|
75
|
+
name: k.name,
|
|
76
|
+
key: k.key,
|
|
77
|
+
prefix: k.prefix,
|
|
78
|
+
scopes: k.scopes,
|
|
79
|
+
max_lifetime_days: k.max_lifetime_days,
|
|
80
|
+
expires_at: k.expires_at,
|
|
81
|
+
created_at: k.created_at,
|
|
82
|
+
});
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
heading("API key created");
|
|
86
|
+
kvList([
|
|
87
|
+
["ID", colors.dim(k.id)],
|
|
88
|
+
["Name", k.name],
|
|
89
|
+
["Expires", formatDate(k.expires_at)],
|
|
90
|
+
]);
|
|
91
|
+
log();
|
|
92
|
+
warn(colors.bold("Save this key now — it will NOT be shown again:"));
|
|
93
|
+
log();
|
|
94
|
+
log(` ${colors.green(k.key)}`);
|
|
95
|
+
log();
|
|
96
|
+
log(` ${colors.dim("Use it headless with:")} ${colors.cyan(`BATA_API_KEY=${k.prefix}... bata status`)}`);
|
|
97
|
+
log();
|
|
98
|
+
}
|
|
99
|
+
async function list(args) {
|
|
100
|
+
void args;
|
|
101
|
+
const token = requireToken();
|
|
102
|
+
const jsonMode = isJsonMode();
|
|
103
|
+
const s = jsonMode ? null : spinner("Fetching API keys");
|
|
104
|
+
const res = await api.get("/v1/api-keys", token);
|
|
105
|
+
s?.stop();
|
|
106
|
+
if (!res.ok) {
|
|
107
|
+
if (jsonMode) {
|
|
108
|
+
json({ error: apiError(res, "Failed to list API keys") });
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
error(apiError(res, "Failed to list API keys"));
|
|
112
|
+
}
|
|
113
|
+
process.exit(1);
|
|
114
|
+
}
|
|
115
|
+
const keys = Array.isArray(res.data) ? res.data : [];
|
|
116
|
+
if (jsonMode) {
|
|
117
|
+
json(keys.map((k) => ({
|
|
118
|
+
id: k.id,
|
|
119
|
+
name: k.name,
|
|
120
|
+
prefix: k.keyPrefix,
|
|
121
|
+
scopes: k.scopes,
|
|
122
|
+
expires_at: k.expiresAt,
|
|
123
|
+
last_used_at: k.lastUsedAt,
|
|
124
|
+
created_at: k.createdAt,
|
|
125
|
+
})));
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
heading("API Keys");
|
|
129
|
+
if (keys.length === 0) {
|
|
130
|
+
log(` ${colors.dim("No active API keys.")} Run ${colors.cyan("bata api-keys create")} to make one.`);
|
|
131
|
+
log();
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
table(["ID", "NAME", "PREFIX", "LAST USED", "EXPIRES"], keys.map((k) => [
|
|
135
|
+
k.id,
|
|
136
|
+
k.name,
|
|
137
|
+
k.keyPrefix,
|
|
138
|
+
formatDate(k.lastUsedAt),
|
|
139
|
+
formatDate(k.expiresAt),
|
|
140
|
+
]));
|
|
141
|
+
log();
|
|
142
|
+
log(` ${colors.dim(`${keys.length} active key(s)`)}`);
|
|
143
|
+
log();
|
|
144
|
+
}
|
|
145
|
+
async function revoke(args) {
|
|
146
|
+
const token = requireToken();
|
|
147
|
+
const jsonMode = isJsonMode();
|
|
148
|
+
const skipConfirm = args.includes("--yes") || args.includes("-y");
|
|
149
|
+
const id = positional(args)[0];
|
|
150
|
+
if (!id) {
|
|
151
|
+
const msg = "API key ID is required. Usage: bata api-keys revoke <id> [--yes]";
|
|
152
|
+
if (jsonMode)
|
|
153
|
+
json({ error: msg });
|
|
154
|
+
else
|
|
155
|
+
error(msg);
|
|
156
|
+
process.exit(1);
|
|
157
|
+
}
|
|
158
|
+
if (!skipConfirm && !jsonMode && process.stdin.isTTY) {
|
|
159
|
+
const ok = await confirm(`Revoke API key ${colors.cyan(id)}? This cannot be undone.`, false);
|
|
160
|
+
if (!ok) {
|
|
161
|
+
log(" Aborted.");
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
const s = jsonMode ? null : spinner("Revoking API key");
|
|
166
|
+
const res = await api.del(`/v1/api-keys/${id}`, token);
|
|
167
|
+
s?.stop();
|
|
168
|
+
if (!res.ok) {
|
|
169
|
+
if (jsonMode)
|
|
170
|
+
json({ error: apiError(res, "Failed to revoke API key") });
|
|
171
|
+
else
|
|
172
|
+
error(apiError(res, "Failed to revoke API key"));
|
|
173
|
+
process.exit(1);
|
|
174
|
+
}
|
|
175
|
+
if (jsonMode) {
|
|
176
|
+
json({ id, revoked: true });
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
log();
|
|
180
|
+
success(`API key ${colors.cyan(id)} revoked.`);
|
|
181
|
+
log();
|
|
182
|
+
}
|
|
183
|
+
function printHelp() {
|
|
184
|
+
log();
|
|
185
|
+
log(` ${colors.bold("bata api-keys")} ${colors.dim("— manage API keys for headless / agent access")}`);
|
|
186
|
+
log();
|
|
187
|
+
log(` ${colors.bold("Subcommands")}`);
|
|
188
|
+
log(` ${colors.cyan("create")} ${colors.dim("[--name <n>] [--json]")} Generate a new key (shown once)`);
|
|
189
|
+
log(` ${colors.cyan("list")} ${colors.dim("[--json]")} List active keys`);
|
|
190
|
+
log(` ${colors.cyan("revoke <id>")} ${colors.dim("[--yes]")} Revoke a key`);
|
|
191
|
+
log();
|
|
192
|
+
log(` ${colors.bold("Auth")} ${colors.dim("(any subcommand)")}`);
|
|
193
|
+
log(` ${colors.dim("--api-key <key>")} Credential (else BATA_API_KEY, else saved login)`);
|
|
194
|
+
log(` ${colors.dim("--api-url <url>")} API base URL (else BATA_API_URL, else config/default)`);
|
|
195
|
+
log();
|
|
196
|
+
log(` ${colors.bold("Examples")}`);
|
|
197
|
+
log(` ${colors.cyan("bata api-keys create --name ci --json")}`);
|
|
198
|
+
log(` ${colors.cyan("BATA_API_KEY=bata_xxx bata api-keys list --json")}`);
|
|
199
|
+
log(` ${colors.cyan("bata api-keys revoke akey_123 --yes")}`);
|
|
200
|
+
log();
|
|
201
|
+
}
|
|
202
|
+
export async function handleApiKeys(args) {
|
|
203
|
+
const sub = args[0];
|
|
204
|
+
const rest = args.slice(1);
|
|
205
|
+
if (sub === "--help" || sub === "-h" || sub === "help") {
|
|
206
|
+
printHelp();
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
switch (sub) {
|
|
210
|
+
case "create":
|
|
211
|
+
return create(rest);
|
|
212
|
+
case "list":
|
|
213
|
+
case undefined:
|
|
214
|
+
return list(rest);
|
|
215
|
+
case "revoke":
|
|
216
|
+
return revoke(rest);
|
|
217
|
+
default:
|
|
218
|
+
error(`Unknown subcommand: api-keys ${sub}`);
|
|
219
|
+
log(` ${colors.dim("Available:")} create, list, revoke`);
|
|
220
|
+
process.exit(1);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
//# sourceMappingURL=api-keys.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-keys.js","sourceRoot":"","sources":["../../src/commands/api-keys.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { api, apiError } from "../api.js";
|
|
2
|
+
import { saveConfig, clearConfig, requireToken, loadConfig, isJsonMode } from "../config.js";
|
|
3
|
+
import { colors, log, json, success, error, spinner, kvList, heading } from "../utils/logger.js";
|
|
4
|
+
import { prompt, promptSecret } from "../utils/prompts.js";
|
|
5
|
+
export async function login() {
|
|
6
|
+
heading("Log in to BataDB");
|
|
7
|
+
const email = await prompt("Email");
|
|
8
|
+
if (!email) {
|
|
9
|
+
error("Email is required.");
|
|
10
|
+
process.exit(1);
|
|
11
|
+
}
|
|
12
|
+
const password = await promptSecret("Password");
|
|
13
|
+
if (!password) {
|
|
14
|
+
error("Password is required.");
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
|
17
|
+
const s = spinner("Authenticating");
|
|
18
|
+
const res = await api.post("/auth/login", { email, password });
|
|
19
|
+
if (!res.ok) {
|
|
20
|
+
s.stop();
|
|
21
|
+
error(apiError(res, "Login failed"));
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
const { token, user, teams } = res.data;
|
|
25
|
+
// Save token and default team
|
|
26
|
+
const config = { token };
|
|
27
|
+
if (teams && teams.length > 0) {
|
|
28
|
+
config.defaultTeam = teams[0].id;
|
|
29
|
+
}
|
|
30
|
+
saveConfig(config);
|
|
31
|
+
s.stop();
|
|
32
|
+
log();
|
|
33
|
+
success("Logged in successfully");
|
|
34
|
+
log();
|
|
35
|
+
kvList([
|
|
36
|
+
["User", colors.white(user.name || user.email)],
|
|
37
|
+
["Email", user.email],
|
|
38
|
+
...(teams && teams.length > 0
|
|
39
|
+
? [["Team", colors.cyan(teams[0].name)]]
|
|
40
|
+
: []),
|
|
41
|
+
]);
|
|
42
|
+
log();
|
|
43
|
+
}
|
|
44
|
+
export async function logout() {
|
|
45
|
+
clearConfig();
|
|
46
|
+
log();
|
|
47
|
+
success("Logged out. Token cleared from ~/.batarc");
|
|
48
|
+
log();
|
|
49
|
+
}
|
|
50
|
+
export async function whoami() {
|
|
51
|
+
const token = requireToken();
|
|
52
|
+
const jsonMode = isJsonMode();
|
|
53
|
+
const s = jsonMode ? null : spinner("Fetching user info");
|
|
54
|
+
// /auth/me only accepts a JWT session token. When authenticating with an
|
|
55
|
+
// API key (the agent/headless path), fall back to /v1/teams which the auth
|
|
56
|
+
// middleware accepts with `Bearer bata_...`.
|
|
57
|
+
const meRes = await api.get("/auth/me", token);
|
|
58
|
+
if (meRes.ok) {
|
|
59
|
+
s?.stop();
|
|
60
|
+
const { user, teams } = meRes.data;
|
|
61
|
+
if (jsonMode) {
|
|
62
|
+
json({
|
|
63
|
+
auth: "session",
|
|
64
|
+
user: { id: user.id, email: user.email, name: user.name },
|
|
65
|
+
teams: teams ?? [],
|
|
66
|
+
default_project: loadConfig().defaultProject ?? null,
|
|
67
|
+
});
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
heading("Current User");
|
|
71
|
+
kvList([
|
|
72
|
+
["Name", colors.white(user.name || "-")],
|
|
73
|
+
["Email", user.email],
|
|
74
|
+
["User ID", colors.dim(user.id)],
|
|
75
|
+
]);
|
|
76
|
+
if (teams && teams.length > 0) {
|
|
77
|
+
log();
|
|
78
|
+
log(` ${colors.dim("Teams")}`);
|
|
79
|
+
for (const team of teams) {
|
|
80
|
+
log(` ${colors.cyan(">")} ${team.name} ${colors.dim(`(${team.slug})`)}`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
const config = loadConfig();
|
|
84
|
+
if (config.defaultProject) {
|
|
85
|
+
log();
|
|
86
|
+
log(` ${colors.dim("Default project:")} ${config.defaultProject}`);
|
|
87
|
+
}
|
|
88
|
+
log();
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
// Fall back to API-key identity via /v1/teams.
|
|
92
|
+
const teamsRes = await api.get("/v1/teams", token);
|
|
93
|
+
s?.stop();
|
|
94
|
+
if (!teamsRes.ok) {
|
|
95
|
+
if (jsonMode) {
|
|
96
|
+
json({ error: apiError(teamsRes, "Could not fetch identity") });
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
error(apiError(teamsRes, "Could not fetch identity"));
|
|
100
|
+
}
|
|
101
|
+
process.exit(1);
|
|
102
|
+
}
|
|
103
|
+
const teams = Array.isArray(teamsRes.data) ? teamsRes.data : [];
|
|
104
|
+
if (jsonMode) {
|
|
105
|
+
json({
|
|
106
|
+
auth: "api_key",
|
|
107
|
+
user: null,
|
|
108
|
+
teams,
|
|
109
|
+
default_project: loadConfig().defaultProject ?? null,
|
|
110
|
+
});
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
heading("Current Identity");
|
|
114
|
+
log(` ${colors.dim("Authenticated via API key.")}`);
|
|
115
|
+
log();
|
|
116
|
+
if (teams.length > 0) {
|
|
117
|
+
log(` ${colors.dim("Teams")}`);
|
|
118
|
+
for (const team of teams) {
|
|
119
|
+
const role = team.role ? colors.dim(` [${team.role}]`) : "";
|
|
120
|
+
log(` ${colors.cyan(">")} ${team.name} ${colors.dim(`(${team.slug})`)}${role}`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
log(` ${colors.dim("No teams found for this key.")}`);
|
|
125
|
+
}
|
|
126
|
+
const config = loadConfig();
|
|
127
|
+
if (config.defaultProject) {
|
|
128
|
+
log();
|
|
129
|
+
log(` ${colors.dim("Default project:")} ${config.defaultProject}`);
|
|
130
|
+
}
|
|
131
|
+
log();
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":"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"}
|