@batadata/cli 0.1.15 → 0.1.17
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/claim.d.ts +7 -5
- package/dist/commands/claim.js +9 -6
- package/dist/commands/compute.d.ts +24 -0
- package/dist/commands/compute.js +217 -0
- package/dist/commands/new.d.ts +12 -8
- package/dist/commands/new.js +41 -36
- package/dist/index.js +11 -2
- package/package.json +1 -1
package/dist/commands/claim.d.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* bata claim <token> — redeem a
|
|
2
|
+
* bata claim <token> — redeem a legacy claim token into your team.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* LEGACY: the anonymous, no-signup flow that issued claim tokens is gone —
|
|
5
|
+
* `bata new` now creates a database directly in your team. This command remains
|
|
6
|
+
* only to redeem a token from that retired flow. Authed. Resolves the team
|
|
7
|
+
* (like `bata create`), calls POST /v1/claim/redeem { claim_token, team_id },
|
|
8
|
+
* and on success the project becomes a permanent member of your team (its TTL
|
|
9
|
+
* is cleared). Typed errors for unknown / expired / already-claimed tokens.
|
|
8
10
|
*/
|
|
9
11
|
export interface ClaimArgs {
|
|
10
12
|
token?: string;
|
package/dist/commands/claim.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* bata claim <token> — redeem a
|
|
2
|
+
* bata claim <token> — redeem a legacy claim token into your team.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* LEGACY: the anonymous, no-signup flow that issued claim tokens is gone —
|
|
5
|
+
* `bata new` now creates a database directly in your team. This command remains
|
|
6
|
+
* only to redeem a token from that retired flow. Authed. Resolves the team
|
|
7
|
+
* (like `bata create`), calls POST /v1/claim/redeem { claim_token, team_id },
|
|
8
|
+
* and on success the project becomes a permanent member of your team (its TTL
|
|
9
|
+
* is cleared). Typed errors for unknown / expired / already-claimed tokens.
|
|
8
10
|
*/
|
|
9
11
|
import { api, apiError, resolveTeamId } from "../api.js";
|
|
10
12
|
import { requireToken, saveConfig, isJsonMode } from "../config.js";
|
|
@@ -25,7 +27,8 @@ function printHelp() {
|
|
|
25
27
|
log();
|
|
26
28
|
log(` ${colors.bold("bata claim")} ${colors.dim("<token>")}`);
|
|
27
29
|
log();
|
|
28
|
-
log(`
|
|
30
|
+
log(` ${colors.yellow("Legacy:")} redeem a claim token from the retired anonymous flow.`);
|
|
31
|
+
log(` ${colors.cyan("bata new")} now creates a database directly in your team — no token to claim.`);
|
|
29
32
|
log(` Requires login — pass ${colors.cyan("--api-key")}, set ${colors.cyan("BATA_API_KEY")}, or run ${colors.cyan("bata login")}.`);
|
|
30
33
|
log();
|
|
31
34
|
log(` ${colors.bold("Examples")}`);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* bata compute — inspect and configure a branch's compute.
|
|
3
|
+
*
|
|
4
|
+
* `bata compute set` toggles the dedicated always-on tier and/or picks a fixed
|
|
5
|
+
* size for a branch's compute; `bata compute status` surfaces each branch's
|
|
6
|
+
* size + always-on state. Both resolve the compute via the branch (a branch has
|
|
7
|
+
* one compute today) so agents never handle raw compute IDs.
|
|
8
|
+
*/
|
|
9
|
+
interface ComputeSetFlags {
|
|
10
|
+
projectId?: string;
|
|
11
|
+
branch?: string;
|
|
12
|
+
alwaysOn?: boolean;
|
|
13
|
+
size?: number;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Parse `compute set` flags. `--always-on`/`--no-always-on` are valueless
|
|
17
|
+
* booleans; `--size <cu>` (and `--size=<cu>`) takes a number. `--project` /
|
|
18
|
+
* `--branch` accept both spaced and `=` forms, matching the other commands.
|
|
19
|
+
*/
|
|
20
|
+
export declare function parseComputeSetFlags(args: string[]): ComputeSetFlags;
|
|
21
|
+
export declare function computeSet(args: string[]): Promise<void>;
|
|
22
|
+
export declare function computeStatus(args: string[]): Promise<void>;
|
|
23
|
+
export declare function handleCompute(args: string[]): Promise<void>;
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* bata compute — inspect and configure a branch's compute.
|
|
3
|
+
*
|
|
4
|
+
* `bata compute set` toggles the dedicated always-on tier and/or picks a fixed
|
|
5
|
+
* size for a branch's compute; `bata compute status` surfaces each branch's
|
|
6
|
+
* size + always-on state. Both resolve the compute via the branch (a branch has
|
|
7
|
+
* one compute today) so agents never handle raw compute IDs.
|
|
8
|
+
*/
|
|
9
|
+
import { api, apiError, resolveTeamId } from "../api.js";
|
|
10
|
+
import { requireToken, isJsonMode } from "../config.js";
|
|
11
|
+
import { colors, log, json, spinner, table, heading } from "../utils/logger.js";
|
|
12
|
+
import { emitError } from "../utils/errors.js";
|
|
13
|
+
import { resolveProjectId } from "../link.js";
|
|
14
|
+
// Fixed dedicated sizes: 1 CU = 512MB / 0.25 vCPU, so {1,2,4,8,16} = 512MB→8GB.
|
|
15
|
+
// Mirrors DEDICATED_SIZE_CU in control-plane/src/routes/computes.ts.
|
|
16
|
+
const DEDICATED_SIZE_CU = [1, 2, 4, 8, 16];
|
|
17
|
+
/**
|
|
18
|
+
* Parse `compute set` flags. `--always-on`/`--no-always-on` are valueless
|
|
19
|
+
* booleans; `--size <cu>` (and `--size=<cu>`) takes a number. `--project` /
|
|
20
|
+
* `--branch` accept both spaced and `=` forms, matching the other commands.
|
|
21
|
+
*/
|
|
22
|
+
export function parseComputeSetFlags(args) {
|
|
23
|
+
const flags = {};
|
|
24
|
+
for (let i = 0; i < args.length; i++) {
|
|
25
|
+
const arg = args[i];
|
|
26
|
+
if (arg === "--project")
|
|
27
|
+
flags.projectId = args[++i];
|
|
28
|
+
else if (arg.startsWith("--project="))
|
|
29
|
+
flags.projectId = arg.slice("--project=".length);
|
|
30
|
+
else if (arg === "--branch")
|
|
31
|
+
flags.branch = args[++i];
|
|
32
|
+
else if (arg.startsWith("--branch="))
|
|
33
|
+
flags.branch = arg.slice("--branch=".length);
|
|
34
|
+
else if (arg === "--always-on")
|
|
35
|
+
flags.alwaysOn = true;
|
|
36
|
+
else if (arg === "--no-always-on")
|
|
37
|
+
flags.alwaysOn = false;
|
|
38
|
+
else if (arg === "--size")
|
|
39
|
+
flags.size = Number(args[++i]);
|
|
40
|
+
else if (arg.startsWith("--size="))
|
|
41
|
+
flags.size = Number(arg.slice("--size=".length));
|
|
42
|
+
}
|
|
43
|
+
return flags;
|
|
44
|
+
}
|
|
45
|
+
/** Fetch the project (branches enriched with their computes). Null on failure. */
|
|
46
|
+
async function fetchProject(projectId, token, teamId) {
|
|
47
|
+
const query = {};
|
|
48
|
+
if (teamId)
|
|
49
|
+
query.team_id = teamId;
|
|
50
|
+
const res = await api.get(`/v1/projects/${projectId}`, token, query);
|
|
51
|
+
return res.ok ? res.data : null;
|
|
52
|
+
}
|
|
53
|
+
/** Resolve a branch by id OR name, else null. */
|
|
54
|
+
function findBranch(project, ref) {
|
|
55
|
+
return project.branches?.find((b) => b.id === ref || b.name === ref) ?? null;
|
|
56
|
+
}
|
|
57
|
+
/** The compute serving a branch (a branch has one today); prefer an active one. */
|
|
58
|
+
function branchCompute(branch) {
|
|
59
|
+
const computes = branch.computes ?? [];
|
|
60
|
+
return computes.find((comp) => comp.status === "active") ?? computes[0] ?? null;
|
|
61
|
+
}
|
|
62
|
+
export async function computeSet(args) {
|
|
63
|
+
const jsonMode = isJsonMode();
|
|
64
|
+
const flags = parseComputeSetFlags(args);
|
|
65
|
+
if (flags.alwaysOn === undefined && flags.size === undefined) {
|
|
66
|
+
emitError("MISSING_ARG", "Nothing to change.", "Pass --always-on/--no-always-on and/or --size <cu>.");
|
|
67
|
+
}
|
|
68
|
+
if (flags.size !== undefined && !DEDICATED_SIZE_CU.includes(flags.size)) {
|
|
69
|
+
emitError("INVALID_FLAG", `Invalid --size ${flags.size}. Allowed: ${DEDICATED_SIZE_CU.join(", ")} (512MB, 1GB, 2GB, 4GB, 8GB).`, "Example: bata compute set --branch main --size 8");
|
|
70
|
+
}
|
|
71
|
+
if (!flags.branch) {
|
|
72
|
+
emitError("MISSING_ARG", "A branch is required.", "Pass --branch <name-or-id>.");
|
|
73
|
+
}
|
|
74
|
+
const token = requireToken();
|
|
75
|
+
const projectId = resolveProjectId(flags.projectId).projectId;
|
|
76
|
+
if (!projectId) {
|
|
77
|
+
emitError("NO_PROJECT", "No project.", "Pass --project <id>, or run `bata link <project>` to set a default.");
|
|
78
|
+
}
|
|
79
|
+
const teamId = await resolveTeamId(token);
|
|
80
|
+
const s = jsonMode ? null : spinner(`Resolving branch ${colors.cyan(flags.branch)}`);
|
|
81
|
+
const project = await fetchProject(projectId, token, teamId);
|
|
82
|
+
if (!project) {
|
|
83
|
+
s?.stop();
|
|
84
|
+
emitError("API_UNAVAILABLE", "Failed to fetch project.", "");
|
|
85
|
+
}
|
|
86
|
+
const branch = findBranch(project, flags.branch);
|
|
87
|
+
if (!branch) {
|
|
88
|
+
s?.stop();
|
|
89
|
+
emitError("BRANCH_NOT_FOUND", `Branch "${flags.branch}" not found in this project.`, "List branches with: bata db branches --json");
|
|
90
|
+
}
|
|
91
|
+
const compute = branchCompute(branch);
|
|
92
|
+
if (!compute) {
|
|
93
|
+
s?.stop();
|
|
94
|
+
emitError("NOT_FOUND", `Branch "${branch.name}" has no compute yet.`, "Wait for the branch to finish provisioning, then retry.");
|
|
95
|
+
}
|
|
96
|
+
const body = {};
|
|
97
|
+
if (flags.alwaysOn !== undefined)
|
|
98
|
+
body.always_on = flags.alwaysOn;
|
|
99
|
+
if (flags.size !== undefined)
|
|
100
|
+
body.size_cu = flags.size;
|
|
101
|
+
const res = await api.patch(`/v1/computes/${compute.id}`, body, token);
|
|
102
|
+
s?.stop();
|
|
103
|
+
if (!res.ok) {
|
|
104
|
+
emitError(res.status === 401 || res.status === 403 ? "INVALID_KEY"
|
|
105
|
+
: res.status === 404 ? "NOT_FOUND"
|
|
106
|
+
: res.status >= 500 || res.status === 0 ? "API_UNAVAILABLE"
|
|
107
|
+
: "CLI_ERROR", apiError(res, "Failed to update compute"), "");
|
|
108
|
+
}
|
|
109
|
+
if (jsonMode) {
|
|
110
|
+
json({
|
|
111
|
+
compute: {
|
|
112
|
+
id: res.data.id,
|
|
113
|
+
branch: branch.name,
|
|
114
|
+
project_id: projectId,
|
|
115
|
+
always_on: res.data.alwaysOn ?? null,
|
|
116
|
+
size_cu: res.data.sizeCu ?? null,
|
|
117
|
+
status: res.data.status ?? null,
|
|
118
|
+
},
|
|
119
|
+
notes: res.data.notes ?? [],
|
|
120
|
+
});
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
log();
|
|
124
|
+
log(` ${colors.green(">")} Compute for branch ${colors.cyan(branch.name)} updated`);
|
|
125
|
+
if (flags.alwaysOn !== undefined) {
|
|
126
|
+
log(` ${colors.dim("Always-on:")} ${res.data.alwaysOn ? colors.green("on") : "off"}`);
|
|
127
|
+
}
|
|
128
|
+
if (flags.size !== undefined) {
|
|
129
|
+
log(` ${colors.dim("Size:")} ${res.data.sizeCu ?? flags.size} CU`);
|
|
130
|
+
}
|
|
131
|
+
for (const note of res.data.notes ?? []) {
|
|
132
|
+
log(` ${colors.yellow("note:")} ${colors.dim(note)}`);
|
|
133
|
+
}
|
|
134
|
+
log();
|
|
135
|
+
}
|
|
136
|
+
export async function computeStatus(args) {
|
|
137
|
+
const jsonMode = isJsonMode();
|
|
138
|
+
const flags = parseComputeSetFlags(args); // reuse --project/--branch parsing
|
|
139
|
+
const token = requireToken();
|
|
140
|
+
const projectId = resolveProjectId(flags.projectId).projectId;
|
|
141
|
+
if (!projectId) {
|
|
142
|
+
emitError("NO_PROJECT", "No project.", "Pass --project <id>, or run `bata link <project>` to set a default.");
|
|
143
|
+
}
|
|
144
|
+
const teamId = await resolveTeamId(token);
|
|
145
|
+
const s = jsonMode ? null : spinner("Fetching computes");
|
|
146
|
+
const project = await fetchProject(projectId, token, teamId);
|
|
147
|
+
s?.stop();
|
|
148
|
+
if (!project) {
|
|
149
|
+
emitError("API_UNAVAILABLE", "Failed to fetch project.", "");
|
|
150
|
+
}
|
|
151
|
+
let branchList = project.branches ?? [];
|
|
152
|
+
if (flags.branch) {
|
|
153
|
+
const b = findBranch(project, flags.branch);
|
|
154
|
+
if (!b) {
|
|
155
|
+
emitError("BRANCH_NOT_FOUND", `Branch "${flags.branch}" not found in this project.`, "List branches with: bata db branches --json");
|
|
156
|
+
}
|
|
157
|
+
branchList = [b];
|
|
158
|
+
}
|
|
159
|
+
const rows = branchList.map((b) => {
|
|
160
|
+
const compute = branchCompute(b);
|
|
161
|
+
return {
|
|
162
|
+
branch: b.name,
|
|
163
|
+
compute_id: compute?.id ?? null,
|
|
164
|
+
status: compute?.status ?? null,
|
|
165
|
+
size_cu: compute?.sizeCu ?? null,
|
|
166
|
+
always_on: compute?.alwaysOn ?? false,
|
|
167
|
+
};
|
|
168
|
+
});
|
|
169
|
+
if (jsonMode) {
|
|
170
|
+
json({ project_id: projectId, computes: rows });
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
heading(`Computes — ${project.name}`);
|
|
174
|
+
if (rows.length === 0) {
|
|
175
|
+
log(` ${colors.dim("No branches found.")}`);
|
|
176
|
+
log();
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
table(["BRANCH", "STATUS", "SIZE (CU)", "ALWAYS-ON"], rows.map((r) => [
|
|
180
|
+
r.branch,
|
|
181
|
+
r.status ?? "-",
|
|
182
|
+
r.size_cu != null ? String(r.size_cu) : "-",
|
|
183
|
+
r.always_on ? colors.green("on") : "-",
|
|
184
|
+
]));
|
|
185
|
+
log();
|
|
186
|
+
}
|
|
187
|
+
function computeHelp() {
|
|
188
|
+
log();
|
|
189
|
+
log(` ${colors.bold("bata compute")} — inspect and configure branch compute`);
|
|
190
|
+
log();
|
|
191
|
+
log(` ${colors.cyan("bata compute status [--project <id>] [--branch <name-or-id>]")}`);
|
|
192
|
+
log(` ${colors.cyan("bata compute set --branch <name-or-id> [--always-on|--no-always-on] [--size <cu>]")}`);
|
|
193
|
+
log();
|
|
194
|
+
log(` ${colors.dim("--always-on / --no-always-on")} Dedicated always-on primary (no cold starts; flat bill)`);
|
|
195
|
+
log(` ${colors.dim("--size <cu>")} Fixed size: ${DEDICATED_SIZE_CU.join(", ")} CU (512MB, 1GB, 2GB, 4GB, 8GB)`);
|
|
196
|
+
log(` ${colors.dim("--project <id>")} Target project (else the linked/default project)`);
|
|
197
|
+
log(` ${colors.dim("--branch <name-or-id>")} Target branch by name OR id`);
|
|
198
|
+
log();
|
|
199
|
+
log(` ${colors.dim("Changing --size restarts the compute briefly to apply it.")}`);
|
|
200
|
+
log();
|
|
201
|
+
}
|
|
202
|
+
export async function handleCompute(args) {
|
|
203
|
+
const sub = args[0];
|
|
204
|
+
if (!sub || sub === "--help" || sub === "-h" || sub === "help") {
|
|
205
|
+
computeHelp();
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
switch (sub) {
|
|
209
|
+
case "set":
|
|
210
|
+
return computeSet(args.slice(1));
|
|
211
|
+
case "status":
|
|
212
|
+
case "info":
|
|
213
|
+
return computeStatus(args.slice(1));
|
|
214
|
+
default:
|
|
215
|
+
emitError("INVALID_FLAG", `Unknown subcommand: compute ${sub}`, "Available: set, status");
|
|
216
|
+
}
|
|
217
|
+
}
|
package/dist/commands/new.d.ts
CHANGED
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* bata new — instant
|
|
2
|
+
* bata new — instant Postgres in your team (one call, zero config).
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* Authed (like every other command): requires a credential. Calls
|
|
5
|
+
* POST /v1/claim/new, which creates a REAL project directly in your team —
|
|
6
|
+
* owned, billed, and quota'd like any other — and prints the connection string.
|
|
7
|
+
* No name or region to pick; the compute is the smallest box and scales to zero.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
9
|
+
* `--team <id>` targets a specific team (else your resolved/default team).
|
|
10
|
+
* `--json` emits the full payload for agents.
|
|
11
|
+
*
|
|
12
|
+
* (The old anonymous, no-signup flow with claim tokens is gone.)
|
|
10
13
|
*/
|
|
11
14
|
export interface NewArgs {
|
|
15
|
+
team?: string;
|
|
12
16
|
help: boolean;
|
|
13
17
|
}
|
|
14
|
-
/** Parse `bata new` args
|
|
15
|
-
*
|
|
18
|
+
/** Parse `bata new` args: optional `--team <id>` and `--help` (global flags
|
|
19
|
+
* like --json are stripped upstream in index.ts). Exported for tests. */
|
|
16
20
|
export declare function parseNewArgs(args: string[]): NewArgs;
|
|
17
21
|
export declare function newDb(args: string[]): Promise<void>;
|
package/dist/commands/new.js
CHANGED
|
@@ -1,41 +1,45 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* bata new — instant
|
|
2
|
+
* bata new — instant Postgres in your team (one call, zero config).
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* Authed (like every other command): requires a credential. Calls
|
|
5
|
+
* POST /v1/claim/new, which creates a REAL project directly in your team —
|
|
6
|
+
* owned, billed, and quota'd like any other — and prints the connection string.
|
|
7
|
+
* No name or region to pick; the compute is the smallest box and scales to zero.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
9
|
+
* `--team <id>` targets a specific team (else your resolved/default team).
|
|
10
|
+
* `--json` emits the full payload for agents.
|
|
11
|
+
*
|
|
12
|
+
* (The old anonymous, no-signup flow with claim tokens is gone.)
|
|
10
13
|
*/
|
|
11
|
-
import { api, apiError } from "../api.js";
|
|
12
|
-
import { isJsonMode } from "../config.js";
|
|
14
|
+
import { api, apiError, resolveTeamId } from "../api.js";
|
|
15
|
+
import { requireToken, isJsonMode, saveConfig } from "../config.js";
|
|
13
16
|
import { colors, log, json, success, kvList } from "../utils/logger.js";
|
|
14
17
|
import { emitError } from "../utils/errors.js";
|
|
15
|
-
/** Parse `bata new` args
|
|
16
|
-
*
|
|
18
|
+
/** Parse `bata new` args: optional `--team <id>` and `--help` (global flags
|
|
19
|
+
* like --json are stripped upstream in index.ts). Exported for tests. */
|
|
17
20
|
export function parseNewArgs(args) {
|
|
18
|
-
|
|
21
|
+
let team;
|
|
22
|
+
for (let i = 0; i < args.length; i++) {
|
|
23
|
+
const arg = args[i];
|
|
19
24
|
if (arg === "--help" || arg === "-h")
|
|
20
|
-
return { help: true };
|
|
25
|
+
return { team, help: true };
|
|
26
|
+
if (arg === "--team" && args[i + 1])
|
|
27
|
+
team = args[++i];
|
|
21
28
|
}
|
|
22
|
-
return { help: false };
|
|
29
|
+
return { team, help: false };
|
|
23
30
|
}
|
|
24
31
|
function printHelp() {
|
|
25
32
|
log();
|
|
26
33
|
log(` ${colors.bold("bata new")}`);
|
|
27
34
|
log();
|
|
28
|
-
log(` Create an instant
|
|
29
|
-
log(`
|
|
30
|
-
log();
|
|
31
|
-
log(` ${colors.bold("Claim it later")}`);
|
|
32
|
-
log(` ${colors.cyan("bata claim <token>")} Move the database into your team (clears the expiry)`);
|
|
33
|
-
log();
|
|
34
|
-
log(` ${colors.yellow("Unclaimed databases are permanently DELETED at their expiry.")}`);
|
|
35
|
+
log(` Create an instant Postgres database in your team and print how to connect.`);
|
|
36
|
+
log(` One call, zero config — you get a connection string immediately.`);
|
|
37
|
+
log(` Requires login — pass ${colors.cyan("--api-key")}, set ${colors.cyan("BATA_API_KEY")}, or run ${colors.cyan("bata login")}.`);
|
|
35
38
|
log();
|
|
36
39
|
log(` ${colors.bold("Options")}`);
|
|
37
|
-
log(` ${colors.dim("--
|
|
38
|
-
log(` ${colors.dim("--
|
|
40
|
+
log(` ${colors.dim("--team <id>")} Team to create the database in (default: your team)`);
|
|
41
|
+
log(` ${colors.dim("--json")} Machine-readable output`);
|
|
42
|
+
log(` ${colors.dim("--help, -h")} Show this help`);
|
|
39
43
|
log();
|
|
40
44
|
}
|
|
41
45
|
export async function newDb(args) {
|
|
@@ -44,33 +48,38 @@ export async function newDb(args) {
|
|
|
44
48
|
printHelp();
|
|
45
49
|
return;
|
|
46
50
|
}
|
|
47
|
-
//
|
|
48
|
-
const
|
|
51
|
+
// Authed like every other command. Exits 4 NO_CREDENTIALS when absent.
|
|
52
|
+
const token = requireToken();
|
|
53
|
+
// Resolve the team unless one was passed explicitly. The server verifies
|
|
54
|
+
// membership either way.
|
|
55
|
+
const teamId = parsed.team ?? (await resolveTeamId(token));
|
|
56
|
+
const body = {};
|
|
57
|
+
if (teamId)
|
|
58
|
+
body.team_id = teamId;
|
|
59
|
+
const res = await api.post("/v1/claim/new", body, token);
|
|
49
60
|
if (!res.ok) {
|
|
50
61
|
const data = res.data;
|
|
51
62
|
const code = data?.code;
|
|
52
63
|
if (res.status === 404 && code === "CLAIMABLE_DISABLED") {
|
|
53
|
-
emitError("NOT_FOUND", "Instant databases (bata
|
|
54
|
-
}
|
|
55
|
-
if (res.status === 503 || code === "CLAIM_POOL_EXHAUSTED") {
|
|
56
|
-
emitError("API_UNAVAILABLE", "The free database pool is full right now. Try again shortly.", "This is transient — retry in a minute.");
|
|
64
|
+
emitError("NOT_FOUND", "Instant databases (bata new) are not enabled on this server.", "Create a project with `bata create <name>` instead.");
|
|
57
65
|
}
|
|
58
66
|
if (res.status === 429) {
|
|
59
|
-
emitError("API_UNAVAILABLE", "Rate limit reached for instant databases from this network.", "Wait a bit before creating another
|
|
67
|
+
emitError("API_UNAVAILABLE", "Rate limit reached for instant databases from this network.", "Wait a bit before creating another.");
|
|
60
68
|
}
|
|
61
69
|
emitError("CLI_ERROR", apiError(res, "Failed to create instant database"));
|
|
62
70
|
}
|
|
63
71
|
const db = res.data;
|
|
72
|
+
saveConfig({ defaultProject: db.project_id });
|
|
64
73
|
if (isJsonMode()) {
|
|
65
74
|
json(db);
|
|
66
75
|
return;
|
|
67
76
|
}
|
|
68
77
|
log();
|
|
69
|
-
success("Your instant database is ready
|
|
78
|
+
success("Your instant database is ready!");
|
|
70
79
|
log();
|
|
71
80
|
kvList([
|
|
72
81
|
["Project ID", colors.dim(db.project_id)],
|
|
73
|
-
["
|
|
82
|
+
["Team", colors.dim(db.team_id)],
|
|
74
83
|
]);
|
|
75
84
|
log();
|
|
76
85
|
log(` ${colors.bold("Connection")}`);
|
|
@@ -80,11 +89,7 @@ export async function newDb(args) {
|
|
|
80
89
|
["Pooled", colors.dim(db.connection.pooled)],
|
|
81
90
|
]);
|
|
82
91
|
log();
|
|
83
|
-
log(` ${colors.
|
|
84
|
-
log(` ${colors.cyan(db.claim_token)}`);
|
|
85
|
-
log();
|
|
86
|
-
log(` ${colors.dim("Claim it into your team:")} ${colors.cyan(`bata claim ${db.claim_token}`)}`);
|
|
87
|
-
log(` ${colors.yellow("Unclaimed databases are permanently DELETED at expiry.")}`);
|
|
92
|
+
log(` ${colors.dim("Connect:")} ${colors.cyan("bata db url")}`);
|
|
88
93
|
log(` ${colors.dim("First connection may take a few seconds while the compute wakes.")}`);
|
|
89
94
|
log();
|
|
90
95
|
}
|
package/dist/index.js
CHANGED
|
@@ -13,6 +13,7 @@ import { claim } from "./commands/claim.js";
|
|
|
13
13
|
import { status } from "./commands/status.js";
|
|
14
14
|
import { connect } from "./commands/connect.js";
|
|
15
15
|
import { usage } from "./commands/usage.js";
|
|
16
|
+
import { handleCompute } from "./commands/compute.js";
|
|
16
17
|
import { handleRestore } from "./commands/restore.js";
|
|
17
18
|
import { handlePowdb } from "./commands/powdb.js";
|
|
18
19
|
import { link, unlink } from "./commands/link.js";
|
|
@@ -27,8 +28,8 @@ function help() {
|
|
|
27
28
|
log(` ${colors.cyan("bata")} ${colors.dim("<command>")} ${colors.dim("[options]")}`);
|
|
28
29
|
log();
|
|
29
30
|
log(` ${colors.bold("Quick Start")}`);
|
|
30
|
-
log(` ${colors.cyan("new")} Instant
|
|
31
|
-
log(` ${colors.cyan("claim <token>")}
|
|
31
|
+
log(` ${colors.cyan("new")} Instant database in your team ${colors.dim("(one call, zero config)")}`);
|
|
32
|
+
log(` ${colors.cyan("claim <token>")} ${colors.dim("Legacy: redeem a claim token from the retired anonymous flow")}`);
|
|
32
33
|
log(` ${colors.cyan("create <name>")} Create a project and wait for it to be ready`);
|
|
33
34
|
log(` ${colors.cyan("connect <name>")} Open psql to a project (auto-wakes if suspended)`);
|
|
34
35
|
log(` ${colors.cyan("status")} Show all projects and their status`);
|
|
@@ -59,6 +60,10 @@ function help() {
|
|
|
59
60
|
log(` ${colors.cyan("db studio")} Open table browser in browser`);
|
|
60
61
|
log(` ${colors.cyan("db query")} Run a SQL query ${colors.dim("(--branch <id> to target a branch)")}`);
|
|
61
62
|
log();
|
|
63
|
+
log(` ${colors.bold("Compute")}`);
|
|
64
|
+
log(` ${colors.cyan("compute status")} Show each branch's compute size + always-on state`);
|
|
65
|
+
log(` ${colors.cyan("compute set")} Dedicated always-on tier / fixed size ${colors.dim("(--always-on, --size <cu>)")}`);
|
|
66
|
+
log();
|
|
62
67
|
log(` ${colors.bold("Restore (PITR)")}`);
|
|
63
68
|
log(` ${colors.cyan("restore points")} List recovery points + the PITR window`);
|
|
64
69
|
log(` ${colors.cyan("restore create")} Restore a branch to a timestamp/LSN ${colors.dim("(creates a NEW branch)")}`);
|
|
@@ -179,6 +184,10 @@ async function main() {
|
|
|
179
184
|
case "db":
|
|
180
185
|
await handleDb(rest);
|
|
181
186
|
break;
|
|
187
|
+
// Compute (dedicated always-on tier + size picker)
|
|
188
|
+
case "compute":
|
|
189
|
+
await handleCompute(rest);
|
|
190
|
+
break;
|
|
182
191
|
// Restore (PITR)
|
|
183
192
|
case "restore":
|
|
184
193
|
await handleRestore(rest);
|