@batadata/cli 0.1.17 → 0.2.1
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/README.md +42 -0
- package/dist/commands/compute.d.ts +13 -0
- package/dist/commands/compute.js +131 -1
- package/dist/commands/import.d.ts +197 -0
- package/dist/commands/import.js +1316 -0
- package/dist/commands/projects.d.ts +17 -1
- package/dist/commands/projects.js +82 -3
- package/dist/index.js +14 -2
- package/dist/pricing.d.ts +35 -0
- package/dist/pricing.js +44 -0
- package/package.json +5 -3
package/README.md
CHANGED
|
@@ -87,6 +87,7 @@ flag always wins**, so linking never silently overrides an intentional request:
|
|
|
87
87
|
| Command | Description |
|
|
88
88
|
|---------|-------------|
|
|
89
89
|
| `create <name>` | Create a project and wait for it to be ready |
|
|
90
|
+
| `import --source <uri>` | Migrate a Postgres/Neon database into BataDB (see [Migrate from Neon](#migrate-from-neon)) |
|
|
90
91
|
| `connect <name>` | Open `psql` to a project (auto-wakes if suspended) |
|
|
91
92
|
| `status` | Show all projects and their status |
|
|
92
93
|
| `usage` | Show per-dimension cost (compute, storage, transfer) for the current period |
|
|
@@ -115,6 +116,47 @@ safety.
|
|
|
115
116
|
|
|
116
117
|
Run `bata --help` for the full, authoritative command list, or `bata --version`.
|
|
117
118
|
|
|
119
|
+
## Migrate from Neon
|
|
120
|
+
|
|
121
|
+
`bata import` moves an existing Postgres database — Neon or anything else — into a
|
|
122
|
+
fresh BataDB project in one command. It shells out to the standard `pg_dump` /
|
|
123
|
+
`psql` client tools (nothing proprietary), streams the dump straight through, and
|
|
124
|
+
verifies the result.
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
bata import --source "postgresql://…@ep-x.neon.tech/neondb" # → a new project named `neondb`
|
|
128
|
+
bata import --source "$NEON_URL" --name my-app # name the new project
|
|
129
|
+
bata import --source "$NEON_URL" --project proj_abc123 --yes # into an existing project
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
**Prerequisite:** local `pg_dump` **and** `psql` whose major version is **≥ the
|
|
133
|
+
source server's** (`pg_dump 16` cannot dump a PostgreSQL 17 server). Neon defaults
|
|
134
|
+
to PostgreSQL 17, so install matching client tools:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
brew install libpq # macOS (or: brew install postgresql@17)
|
|
138
|
+
sudo apt install postgresql-client-17 # Ubuntu
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
What it does, in order: inspects the source, checks your client tools, creates (or
|
|
142
|
+
resolves) the target project, waits for its compute, **preflights extensions** (any
|
|
143
|
+
source extension the target can't provide hard-fails *before* the restore starts,
|
|
144
|
+
rather than dying mid-restore at `CREATE EXTENSION` and half-importing), streams
|
|
145
|
+
`pg_dump … --encoding=UTF8 | psql` (the `--encoding=UTF8` guarantees a valid-UTF-8
|
|
146
|
+
stream so non-UTF-8 source databases aren't corrupted in transit), then verifies
|
|
147
|
+
every table's row count and every sequence's value on both sides. It exits non-zero
|
|
148
|
+
on any mismatch. Importing into an existing `--project` that already holds user
|
|
149
|
+
objects requires `--yes`. `--json` emits a machine-readable result for agents.
|
|
150
|
+
|
|
151
|
+
**PostgreSQL 16 vs 17 (honest caveat).** BataDB runs PostgreSQL **16** today; Neon
|
|
152
|
+
defaults to **17**. Standard schemas migrate cleanly — `bata import` transparently
|
|
153
|
+
strips the one PG17-only line `pg_dump` emits (`SET transaction_timeout = 0;`) that
|
|
154
|
+
PG16 would reject. But genuinely **PG17-only** schema features (a data type, syntax,
|
|
155
|
+
or option that only exists in 17) **will fail loudly during restore** — the command
|
|
156
|
+
surfaces the exact `psql` errors and exits non-zero rather than pretending the
|
|
157
|
+
migration succeeded. See [docs/migrate-from-neon.md](../../docs/migrate-from-neon.md)
|
|
158
|
+
for the full guide and the manual `pg_dump | psql` fallback.
|
|
159
|
+
|
|
118
160
|
## Point-in-time restore (PITR)
|
|
119
161
|
|
|
120
162
|
Recover a branch to an earlier point in time. Restore is **non-destructive**: it
|
|
@@ -19,6 +19,19 @@ interface ComputeSetFlags {
|
|
|
19
19
|
*/
|
|
20
20
|
export declare function parseComputeSetFlags(args: string[]): ComputeSetFlags;
|
|
21
21
|
export declare function computeSet(args: string[]): Promise<void>;
|
|
22
|
+
interface ComputeRefFlags {
|
|
23
|
+
projectId?: string;
|
|
24
|
+
branchRef?: string;
|
|
25
|
+
limit?: number;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Parse args for `compute restart` / `compute logs`. The branch is a positional
|
|
29
|
+
* `<id|name>` (or `--branch`, matching `compute set`); `--project` overrides the
|
|
30
|
+
* linked default; `--limit <n>` (logs only) bounds the line count.
|
|
31
|
+
*/
|
|
32
|
+
export declare function parseComputeRefArgs(args: string[]): ComputeRefFlags;
|
|
33
|
+
export declare function computeRestart(args: string[]): Promise<void>;
|
|
34
|
+
export declare function computeLogs(args: string[]): Promise<void>;
|
|
22
35
|
export declare function computeStatus(args: string[]): Promise<void>;
|
|
23
36
|
export declare function handleCompute(args: string[]): Promise<void>;
|
|
24
37
|
export {};
|
package/dist/commands/compute.js
CHANGED
|
@@ -133,6 +133,128 @@ export async function computeSet(args) {
|
|
|
133
133
|
}
|
|
134
134
|
log();
|
|
135
135
|
}
|
|
136
|
+
/**
|
|
137
|
+
* Parse args for `compute restart` / `compute logs`. The branch is a positional
|
|
138
|
+
* `<id|name>` (or `--branch`, matching `compute set`); `--project` overrides the
|
|
139
|
+
* linked default; `--limit <n>` (logs only) bounds the line count.
|
|
140
|
+
*/
|
|
141
|
+
export function parseComputeRefArgs(args) {
|
|
142
|
+
const flags = {};
|
|
143
|
+
for (let i = 0; i < args.length; i++) {
|
|
144
|
+
const arg = args[i];
|
|
145
|
+
if (arg === "--project")
|
|
146
|
+
flags.projectId = args[++i];
|
|
147
|
+
else if (arg.startsWith("--project="))
|
|
148
|
+
flags.projectId = arg.slice("--project=".length);
|
|
149
|
+
else if (arg === "--branch")
|
|
150
|
+
flags.branchRef = args[++i];
|
|
151
|
+
else if (arg.startsWith("--branch="))
|
|
152
|
+
flags.branchRef = arg.slice("--branch=".length);
|
|
153
|
+
else if (arg === "--limit")
|
|
154
|
+
flags.limit = Number(args[++i]);
|
|
155
|
+
else if (arg.startsWith("--limit="))
|
|
156
|
+
flags.limit = Number(arg.slice("--limit=".length));
|
|
157
|
+
else if (!arg.startsWith("-") && flags.branchRef === undefined)
|
|
158
|
+
flags.branchRef = arg;
|
|
159
|
+
}
|
|
160
|
+
return flags;
|
|
161
|
+
}
|
|
162
|
+
/** Map an API status to the CLI error-code contract (see utils/errors.ts). */
|
|
163
|
+
function computeErrorCode(status) {
|
|
164
|
+
if (status === 401 || status === 403)
|
|
165
|
+
return "INVALID_KEY";
|
|
166
|
+
if (status === 404)
|
|
167
|
+
return "NOT_FOUND";
|
|
168
|
+
if (status === 501)
|
|
169
|
+
return "NOT_IMPLEMENTED";
|
|
170
|
+
if (status >= 500 || status === 0)
|
|
171
|
+
return "API_UNAVAILABLE";
|
|
172
|
+
return "CLI_ERROR";
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Resolve a branch's compute from a `<id|name>` ref, shared by restart/logs.
|
|
176
|
+
* Emits (and exits) on any failure; returns the resolved handles on success.
|
|
177
|
+
*/
|
|
178
|
+
async function resolveBranchCompute(flags, jsonMode) {
|
|
179
|
+
if (!flags.branchRef) {
|
|
180
|
+
emitError("MISSING_ARG", "A branch is required.", "Pass a branch name or id, e.g. bata compute restart main.");
|
|
181
|
+
}
|
|
182
|
+
const token = requireToken();
|
|
183
|
+
const projectId = resolveProjectId(flags.projectId).projectId;
|
|
184
|
+
if (!projectId) {
|
|
185
|
+
emitError("NO_PROJECT", "No project.", "Pass --project <id>, or run `bata link <project>` to set a default.");
|
|
186
|
+
}
|
|
187
|
+
const teamId = await resolveTeamId(token);
|
|
188
|
+
const s = jsonMode ? null : spinner(`Resolving branch ${colors.cyan(flags.branchRef)}`);
|
|
189
|
+
const project = await fetchProject(projectId, token, teamId);
|
|
190
|
+
if (!project) {
|
|
191
|
+
s?.stop();
|
|
192
|
+
emitError("API_UNAVAILABLE", "Failed to fetch project.", "");
|
|
193
|
+
}
|
|
194
|
+
const branch = findBranch(project, flags.branchRef);
|
|
195
|
+
if (!branch) {
|
|
196
|
+
s?.stop();
|
|
197
|
+
emitError("BRANCH_NOT_FOUND", `Branch "${flags.branchRef}" not found in this project.`, "List branches with: bata db branches --json");
|
|
198
|
+
}
|
|
199
|
+
const compute = branchCompute(branch);
|
|
200
|
+
if (!compute) {
|
|
201
|
+
s?.stop();
|
|
202
|
+
emitError("NOT_FOUND", `Branch "${branch.name}" has no compute yet.`, "Wait for the branch to finish provisioning, then retry.");
|
|
203
|
+
}
|
|
204
|
+
s?.stop();
|
|
205
|
+
return { token, teamId, projectId: projectId, branch: branch, compute: compute };
|
|
206
|
+
}
|
|
207
|
+
export async function computeRestart(args) {
|
|
208
|
+
const jsonMode = isJsonMode();
|
|
209
|
+
const flags = parseComputeRefArgs(args);
|
|
210
|
+
const { token, branch, compute } = await resolveBranchCompute(flags, jsonMode);
|
|
211
|
+
const res = await api.post(`/v1/computes/${compute.id}/restart`, {}, token);
|
|
212
|
+
if (!res.ok) {
|
|
213
|
+
emitError(computeErrorCode(res.status), apiError(res, "Failed to restart compute"), "");
|
|
214
|
+
}
|
|
215
|
+
if (jsonMode) {
|
|
216
|
+
json({
|
|
217
|
+
compute: {
|
|
218
|
+
id: compute.id,
|
|
219
|
+
branch: branch.name,
|
|
220
|
+
status: res.data.status ?? null,
|
|
221
|
+
restarted: res.data.restarted ?? true,
|
|
222
|
+
},
|
|
223
|
+
});
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
log();
|
|
227
|
+
log(` ${colors.green(">")} Compute for branch ${colors.cyan(branch.name)} restarted`);
|
|
228
|
+
log();
|
|
229
|
+
}
|
|
230
|
+
export async function computeLogs(args) {
|
|
231
|
+
const jsonMode = isJsonMode();
|
|
232
|
+
const flags = parseComputeRefArgs(args);
|
|
233
|
+
if (flags.limit !== undefined && (!Number.isInteger(flags.limit) || flags.limit < 1)) {
|
|
234
|
+
emitError("INVALID_FLAG", `Invalid --limit ${flags.limit}.`, "Pass a positive integer (max 500).");
|
|
235
|
+
}
|
|
236
|
+
const { token, branch, compute } = await resolveBranchCompute(flags, jsonMode);
|
|
237
|
+
const query = flags.limit !== undefined ? { limit: String(Math.min(flags.limit, 500)) } : undefined;
|
|
238
|
+
const res = await api.get(`/v1/computes/${compute.id}/logs`, token, query);
|
|
239
|
+
if (!res.ok) {
|
|
240
|
+
emitError(computeErrorCode(res.status), apiError(res, "Failed to fetch compute logs"), "");
|
|
241
|
+
}
|
|
242
|
+
const lines = res.data.lines ?? [];
|
|
243
|
+
if (jsonMode) {
|
|
244
|
+
json({ compute_id: compute.id, branch: branch.name, source: res.data.source, lines });
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
heading(`Logs — ${branch.name} ${colors.dim(`(${res.data.source})`)}`);
|
|
248
|
+
if (lines.length === 0) {
|
|
249
|
+
log(` ${colors.dim("No recent log lines.")}`);
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
for (const line of lines) {
|
|
253
|
+
log(` ${colors.dim(line.ts)} ${line.message}`);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
log();
|
|
257
|
+
}
|
|
136
258
|
export async function computeStatus(args) {
|
|
137
259
|
const jsonMode = isJsonMode();
|
|
138
260
|
const flags = parseComputeSetFlags(args); // reuse --project/--branch parsing
|
|
@@ -190,13 +312,17 @@ function computeHelp() {
|
|
|
190
312
|
log();
|
|
191
313
|
log(` ${colors.cyan("bata compute status [--project <id>] [--branch <name-or-id>]")}`);
|
|
192
314
|
log(` ${colors.cyan("bata compute set --branch <name-or-id> [--always-on|--no-always-on] [--size <cu>]")}`);
|
|
315
|
+
log(` ${colors.cyan("bata compute restart <name-or-id> [--project <id>]")}`);
|
|
316
|
+
log(` ${colors.cyan("bata compute logs <name-or-id> [--limit <n>] [--project <id>]")}`);
|
|
193
317
|
log();
|
|
194
318
|
log(` ${colors.dim("--always-on / --no-always-on")} Dedicated always-on primary (no cold starts; flat bill)`);
|
|
195
319
|
log(` ${colors.dim("--size <cu>")} Fixed size: ${DEDICATED_SIZE_CU.join(", ")} CU (512MB, 1GB, 2GB, 4GB, 8GB)`);
|
|
320
|
+
log(` ${colors.dim("--limit <n>")} Log lines to fetch (default 100, max 500)`);
|
|
196
321
|
log(` ${colors.dim("--project <id>")} Target project (else the linked/default project)`);
|
|
197
322
|
log(` ${colors.dim("--branch <name-or-id>")} Target branch by name OR id`);
|
|
198
323
|
log();
|
|
199
324
|
log(` ${colors.dim("Changing --size restarts the compute briefly to apply it.")}`);
|
|
325
|
+
log(` ${colors.dim("restart gracefully bounces an active compute in place (stop → start).")}`);
|
|
200
326
|
log();
|
|
201
327
|
}
|
|
202
328
|
export async function handleCompute(args) {
|
|
@@ -211,7 +337,11 @@ export async function handleCompute(args) {
|
|
|
211
337
|
case "status":
|
|
212
338
|
case "info":
|
|
213
339
|
return computeStatus(args.slice(1));
|
|
340
|
+
case "restart":
|
|
341
|
+
return computeRestart(args.slice(1));
|
|
342
|
+
case "logs":
|
|
343
|
+
return computeLogs(args.slice(1));
|
|
214
344
|
default:
|
|
215
|
-
emitError("INVALID_FLAG", `Unknown subcommand: compute ${sub}`, "Available: set, status");
|
|
345
|
+
emitError("INVALID_FLAG", `Unknown subcommand: compute ${sub}`, "Available: set, status, restart, logs");
|
|
216
346
|
}
|
|
217
347
|
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* bata import — Neon (or any Postgres) → BataDB migration.
|
|
3
|
+
*
|
|
4
|
+
* bata import --source <postgres-uri> [--project <id> | --name <name>] [--pg <major>] [--yes] [--json]
|
|
5
|
+
*
|
|
6
|
+
* Agent-native: shells out to the standard `pg_dump` / `psql` client tools
|
|
7
|
+
* (zero runtime deps) and streams a dump straight into a fresh BataDB project.
|
|
8
|
+
*
|
|
9
|
+
* BataDB runs PostgreSQL 16 today; Neon defaults to 17. A PG17 → PG16
|
|
10
|
+
* dump/restore is clean for standard schemas EXCEPT that pg_dump 17 emits
|
|
11
|
+
* `SET transaction_timeout = 0;` — a GUC PG16 doesn't know — into the dump
|
|
12
|
+
* preamble. We strip that one line (and any future target-unknown GUC SETs)
|
|
13
|
+
* out of the stream. Genuinely PG17-only schema features still fail loudly at
|
|
14
|
+
* restore time, and we surface those errors honestly rather than pretending
|
|
15
|
+
* the migration succeeded.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* GUC SET statements pg_dump emits that a BataDB (PG16) target rejects. Kept as
|
|
19
|
+
* an extensible list so a future target-unknown GUC is a one-line addition.
|
|
20
|
+
* `transaction_timeout` is new in PG17 and is the only one seen in practice.
|
|
21
|
+
*/
|
|
22
|
+
export declare const TARGET_UNKNOWN_GUCS: string[];
|
|
23
|
+
/**
|
|
24
|
+
* A streaming line filter that drops target-unknown GUC `SET` statements from a
|
|
25
|
+
* pg_dump stream. It buffers a partial trailing line across chunk boundaries so
|
|
26
|
+
* a `SET transaction_timeout = 0;` split across two reads is still recognised
|
|
27
|
+
* and removed. `push()` returns the text to forward to psql for that chunk;
|
|
28
|
+
* `flush()` returns any buffered final line (a dump without a trailing newline).
|
|
29
|
+
*
|
|
30
|
+
* PREAMBLE-ONLY: pg_dump emits the target-unknown GUCs ONLY in the initial
|
|
31
|
+
* connection preamble (the block of `SET …;` / `SELECT pg_catalog.set_config(…)`
|
|
32
|
+
* statements at the very top). Filtering the whole stream is unsafe: a dumped
|
|
33
|
+
* function/procedure body can contain a standalone line `SET transaction_timeout
|
|
34
|
+
* = 0;` inside its dollar-quoted text, and a COPY data row can be literally
|
|
35
|
+
* anything — mutating those would silently corrupt the restore. So we only strip
|
|
36
|
+
* inside the preamble: the first line that is NOT one of {empty, a `--` comment,
|
|
37
|
+
* `SET …;`, `SELECT pg_catalog.set_config(…);`} permanently ends the preamble,
|
|
38
|
+
* after which every line passes through verbatim. A GUC-looking SET after the
|
|
39
|
+
* preamble is therefore NOT stripped — which is correct: transaction_timeout only
|
|
40
|
+
* ever appears in the preamble; were a future pg_dump to emit it mid-dump, the
|
|
41
|
+
* restore would fail loudly rather than be silently altered.
|
|
42
|
+
*/
|
|
43
|
+
export declare function makeGucLineFilter(gucs?: string[]): {
|
|
44
|
+
push: (chunk: string) => string;
|
|
45
|
+
flush: () => string;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Extract a PostgreSQL major version from any of the shapes we encounter:
|
|
49
|
+
* - `server_version_num` (e.g. "170002", "160003", "90603")
|
|
50
|
+
* - dotted `server_version` (e.g. "17.2", "16.3 (Ubuntu 16.3-1.pgdg…)")
|
|
51
|
+
* - `pg_dump --version` output ("pg_dump (PostgreSQL) 16.3")
|
|
52
|
+
* Returns the integer major, or null if none can be found.
|
|
53
|
+
*/
|
|
54
|
+
export declare function parsePgMajor(v: string): number | null;
|
|
55
|
+
/** A client tool must be at least the source major (pg_dump can't dump a newer
|
|
56
|
+
* server than itself; psql can't parse a newer pg_dump's meta-commands). */
|
|
57
|
+
export declare function toolMajorSatisfies(toolMajor: number, sourceMajor: number): boolean;
|
|
58
|
+
/** Clear, actionable message when a local client tool is too old for the source. */
|
|
59
|
+
export declare function toolVersionErrorMessage(tool: string, toolMajor: number, sourceMajor: number): string;
|
|
60
|
+
/** Message when psql can't restore the stream THIS pg_dump produces. */
|
|
61
|
+
export declare function psqlVsDumpErrorMessage(psqlMajor: number, dumpMajor: number): string;
|
|
62
|
+
/**
|
|
63
|
+
* Verdict on whether the local client tools can migrate a source of `sourceMajor`
|
|
64
|
+
* (null when the source version couldn't be parsed). Rules:
|
|
65
|
+
* - pg_dump must be ≥ source (can't dump a newer server than itself)
|
|
66
|
+
* - psql must be ≥ source AND ≥ pg_dump — the restore stream is produced by the
|
|
67
|
+
* LOCAL pg_dump, and pg_dump 17 emits \restrict/\unrestrict regardless of the
|
|
68
|
+
* source version, so psql 16 + pg_dump 17 fails even against a PG16 source.
|
|
69
|
+
* Effectively psql must satisfy max(sourceMajor, dumpMajor). Returns the install
|
|
70
|
+
* target so the caller can point the user at the right client package.
|
|
71
|
+
*/
|
|
72
|
+
export declare function checkClientVersions(dumpMajor: number, psqlMajor: number, sourceMajor: number | null): {
|
|
73
|
+
ok: true;
|
|
74
|
+
} | {
|
|
75
|
+
ok: false;
|
|
76
|
+
message: string;
|
|
77
|
+
needMajor: number;
|
|
78
|
+
};
|
|
79
|
+
/** Pull the first meaningful line out of a psql connection error for the user. */
|
|
80
|
+
export declare function sourcePreflightErrorMessage(stderr: string): string;
|
|
81
|
+
/** Default target project name = the source database name, else the URI path. */
|
|
82
|
+
export declare function defaultProjectName(preflightDb: string | undefined, sourceUri: string): string;
|
|
83
|
+
export interface CountRow {
|
|
84
|
+
name: string;
|
|
85
|
+
source: string;
|
|
86
|
+
target: string;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Compare two name→value maps (table row counts, or sequence last_values) and
|
|
90
|
+
* return only the mismatches. A name present on one side but not the other is a
|
|
91
|
+
* mismatch too (rendered as ∅). Deterministically sorted by name.
|
|
92
|
+
*/
|
|
93
|
+
export declare function diffCounts(source: Map<string, string>, target: Map<string, string>): CountRow[];
|
|
94
|
+
/** Build the `table()` rows for a verify mismatch report (tables + sequences). */
|
|
95
|
+
export declare function mismatchRows(tableRows: CountRow[], seqRows: CountRow[]): string[][];
|
|
96
|
+
/** Double-quote a SQL identifier (escaping embedded quotes). */
|
|
97
|
+
export declare function quoteIdent(id: string): string;
|
|
98
|
+
/**
|
|
99
|
+
* Map a child process 'close' `(code, signal)` to the numeric exit used for the
|
|
100
|
+
* migration verdict. A signal death (`code === null`, e.g. OOM-killer or an
|
|
101
|
+
* operator `kill`) is a FAILURE — it must never read as success just because its
|
|
102
|
+
* peer exited cleanly. The one exception: when WE deliberately SIGTERM'd the dump
|
|
103
|
+
* after a restore failure (`intentionalKill`), that path already has a nonzero
|
|
104
|
+
* restoreCode so the overall verdict is false regardless; we normalize to 0 to
|
|
105
|
+
* avoid a redundant, confusing error line.
|
|
106
|
+
*/
|
|
107
|
+
export declare function resolveChildExit(code: number | null, signal: string | null, opts?: {
|
|
108
|
+
intentionalKill?: boolean;
|
|
109
|
+
}): {
|
|
110
|
+
code: number;
|
|
111
|
+
error?: string;
|
|
112
|
+
};
|
|
113
|
+
/**
|
|
114
|
+
* Source extensions the target can't satisfy = source extensions not in the
|
|
115
|
+
* target's available set. `plpgsql` is built into every PostgreSQL and always
|
|
116
|
+
* present, so it's excluded — it can never be a real gap even though it shows up
|
|
117
|
+
* in pg_extension. Used both for the pre-restore availability gate (against
|
|
118
|
+
* `pg_available_extensions`) and the residual post-restore warning (against the
|
|
119
|
+
* target's installed `pg_extension`).
|
|
120
|
+
*/
|
|
121
|
+
export declare function missingExtensions(sourceExts: string[], targetHasExts: string[]): string[];
|
|
122
|
+
/**
|
|
123
|
+
* Objects BataDB's provisioning seeds into EVERY new project — platform furniture,
|
|
124
|
+
* not user data. Because a freshly created target ALWAYS contains these, they must
|
|
125
|
+
* be excluded from all TARGET-side "unexpected object" accounting: the
|
|
126
|
+
* created-project hard-fail, the existing-target leftover warnings/JSON, and the
|
|
127
|
+
* `--yes` non-empty guard (a target holding ONLY these is effectively empty). They
|
|
128
|
+
* are NEVER excluded on the SOURCE side — a source `public.health_check` (or a
|
|
129
|
+
* source `neon_migration` schema, e.g. a migration FROM another BataDB) is treated
|
|
130
|
+
* as real data and must verify normally.
|
|
131
|
+
*
|
|
132
|
+
* Two flavours:
|
|
133
|
+
* - Named objects: `public.health_check` (+ its sequence) — the data-path
|
|
134
|
+
* health-check row/table seeded on provision.
|
|
135
|
+
* - Whole schemas: `neon_migration` — our Neon-derived compute engine's
|
|
136
|
+
* compute_ctl records applied internal SQL migrations here (table
|
|
137
|
+
* `neon_migration.migration_id`) on EVERY compute startup. Real Neon hides this
|
|
138
|
+
* schema from customer `pg_tables`; our compute exposes it, so ANY object under
|
|
139
|
+
* `neon_migration.*` is platform furniture, never user data.
|
|
140
|
+
*/
|
|
141
|
+
export declare const PLATFORM_SCAFFOLDING_TABLES: string[];
|
|
142
|
+
export declare const PLATFORM_SCAFFOLDING_SEQUENCES: string[];
|
|
143
|
+
/** Schemas whose ENTIRE contents are platform furniture (any `<schema>.*` object). */
|
|
144
|
+
export declare const PLATFORM_SCAFFOLDING_SCHEMAS: string[];
|
|
145
|
+
/**
|
|
146
|
+
* Merge the server-published scaffolding list (GET /v1/platform/import-scaffolding)
|
|
147
|
+
* into the baked-in defaults above. The server is the source of truth going
|
|
148
|
+
* forward — if provisioning grows new furniture, an already-installed CLI keeps
|
|
149
|
+
* verifying correctly instead of false-failing on it. Union (never replace): the
|
|
150
|
+
* baked defaults still apply against an older control plane, and a partial or
|
|
151
|
+
* malformed server response can only ever ADD exclusions it explicitly names.
|
|
152
|
+
* The exported const arrays are extended in place so every existing reference
|
|
153
|
+
* (the --yes guard, the created-target check, verify) sees the merged lists.
|
|
154
|
+
*/
|
|
155
|
+
export declare function applyServerScaffolding(server: {
|
|
156
|
+
tables?: unknown;
|
|
157
|
+
sequences?: unknown;
|
|
158
|
+
schemas?: unknown;
|
|
159
|
+
}): void;
|
|
160
|
+
/** Is this qualified name one of BataDB's seeded platform-scaffolding objects —
|
|
161
|
+
* either an exact named object, or anything inside a scaffolding schema? */
|
|
162
|
+
export declare function isPlatformScaffolding(qualifiedName: string): boolean;
|
|
163
|
+
/** Drop platform-scaffolding names — applied ONLY to TARGET-side object lists,
|
|
164
|
+
* never to source accounting. */
|
|
165
|
+
export declare function excludeScaffolding(names: string[]): string[];
|
|
166
|
+
/**
|
|
167
|
+
* Scaffolding names that appear in a SOURCE object list — i.e. a user table that
|
|
168
|
+
* shares a name with BataDB's seeded platform table. On restore that `CREATE
|
|
169
|
+
* TABLE` clashes with the scaffolding already present on the target: with
|
|
170
|
+
* ON_ERROR_STOP the restore fails ("relation already exists" → RESTORE_FAILED),
|
|
171
|
+
* or, if the schemas happen to be compatible, rows append and the row-count verify
|
|
172
|
+
* catches the drift. Either way verify stays honest — the source name is NOT
|
|
173
|
+
* excluded from source accounting; we only warn the user up front.
|
|
174
|
+
*/
|
|
175
|
+
export declare function scaffoldingCollisions(sourceQualifiedNames: string[]): string[];
|
|
176
|
+
/**
|
|
177
|
+
* Qualified names present on the TARGET but absent from the source — used for both
|
|
178
|
+
* tables and sequences. Verification only enumerates SOURCE objects, so on a
|
|
179
|
+
* `--project --yes` import into a non-empty target these are invisible to the
|
|
180
|
+
* count/value checks: they were left untouched and aren't covered by verify.
|
|
181
|
+
* Surfaced honestly (a warning for an existing target; unexpected for a freshly
|
|
182
|
+
* created one). Sorted, deduped by set.
|
|
183
|
+
*/
|
|
184
|
+
export declare function targetOnlyNames(sourceQualified: string[], targetQualified: string[]): string[];
|
|
185
|
+
export declare function parseImportArgs(args: string[]): {
|
|
186
|
+
source?: string;
|
|
187
|
+
projectId?: string;
|
|
188
|
+
name?: string;
|
|
189
|
+
pg?: string;
|
|
190
|
+
help: boolean;
|
|
191
|
+
} | {
|
|
192
|
+
error: string;
|
|
193
|
+
};
|
|
194
|
+
/** Default target major for a new project: match the source so features survive,
|
|
195
|
+
* capped at what BataDB ships (a PG18 source → 17, a PG16 or older source → 16). */
|
|
196
|
+
export declare function defaultTargetPg(sourceMajor: number): string;
|
|
197
|
+
export declare function importDb(args: string[]): Promise<void>;
|