ardent-cli 0.0.24 → 0.0.26
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/index.js +151 -70
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,19 +1,84 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import { readFileSync as readFileSync5 } from "fs";
|
|
5
4
|
import { Command as Command8 } from "commander";
|
|
6
5
|
|
|
7
6
|
// src/commands/branch/index.ts
|
|
8
7
|
import { Command } from "commander";
|
|
9
8
|
|
|
10
|
-
// src/lib/api.ts
|
|
11
|
-
import { readFileSync as readFileSync2 } from "fs";
|
|
12
|
-
|
|
13
9
|
// src/lib/config.ts
|
|
14
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync } from "fs";
|
|
10
|
+
import { existsSync, mkdirSync, readFileSync as readFileSync2, writeFileSync, unlinkSync } from "fs";
|
|
15
11
|
import { homedir } from "os";
|
|
16
12
|
import { join } from "path";
|
|
13
|
+
|
|
14
|
+
// src/lib/api_errors.ts
|
|
15
|
+
function formatErrorDetail(detail) {
|
|
16
|
+
if (typeof detail === "string") return detail;
|
|
17
|
+
if (Array.isArray(detail)) {
|
|
18
|
+
return detail.map((entry) => {
|
|
19
|
+
const location = Array.isArray(entry.loc) ? entry.loc.join(" \u2192 ") : "";
|
|
20
|
+
const message = entry.msg ?? "unknown error";
|
|
21
|
+
return location ? `${location}: ${message}` : String(message);
|
|
22
|
+
}).join("; ");
|
|
23
|
+
}
|
|
24
|
+
return JSON.stringify(detail);
|
|
25
|
+
}
|
|
26
|
+
function formatUpgradeRequiredMessage(text) {
|
|
27
|
+
try {
|
|
28
|
+
const json = JSON.parse(text);
|
|
29
|
+
if (json.detail) {
|
|
30
|
+
const detail = formatErrorDetail(json.detail);
|
|
31
|
+
if (detail.includes("npm install -g ardent-cli@latest")) {
|
|
32
|
+
return detail;
|
|
33
|
+
}
|
|
34
|
+
return `${detail}
|
|
35
|
+
|
|
36
|
+
npm install -g ardent-cli@latest`;
|
|
37
|
+
}
|
|
38
|
+
} catch {
|
|
39
|
+
}
|
|
40
|
+
return "Your CLI is outdated. Please update:\n\n npm install -g ardent-cli@latest";
|
|
41
|
+
}
|
|
42
|
+
function parseApiError(status, text) {
|
|
43
|
+
if (status === 426) {
|
|
44
|
+
return formatUpgradeRequiredMessage(text);
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
const json = JSON.parse(text);
|
|
48
|
+
if (json.detail) return `API error ${status}: ${formatErrorDetail(json.detail)}`;
|
|
49
|
+
} catch {
|
|
50
|
+
}
|
|
51
|
+
return `API error ${status}: ${text}`;
|
|
52
|
+
}
|
|
53
|
+
function exitWithUpgradeRequiredMessage(text) {
|
|
54
|
+
console.error(`
|
|
55
|
+
\u2717 ${formatUpgradeRequiredMessage(text)}
|
|
56
|
+
`);
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
async function exitIfUpgradeRequired(response) {
|
|
60
|
+
if (response.status !== 426) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const text = await response.text();
|
|
64
|
+
exitWithUpgradeRequiredMessage(text);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// src/lib/cli_version.ts
|
|
68
|
+
import { readFileSync } from "fs";
|
|
69
|
+
function getCliVersion() {
|
|
70
|
+
try {
|
|
71
|
+
const packageUrl = new URL("../package.json", import.meta.url);
|
|
72
|
+
const raw = readFileSync(packageUrl, "utf-8");
|
|
73
|
+
const parsed = JSON.parse(raw);
|
|
74
|
+
return parsed.version ?? "unknown";
|
|
75
|
+
} catch {
|
|
76
|
+
return "unknown";
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
var CLI_VERSION = getCliVersion();
|
|
80
|
+
|
|
81
|
+
// src/lib/config.ts
|
|
17
82
|
var CONFIG_DIR = join(homedir(), ".ardent");
|
|
18
83
|
var CONFIG_FILE = join(CONFIG_DIR, "config.json");
|
|
19
84
|
function ensureConfigDir() {
|
|
@@ -24,7 +89,7 @@ function ensureConfigDir() {
|
|
|
24
89
|
function loadConfig() {
|
|
25
90
|
try {
|
|
26
91
|
if (existsSync(CONFIG_FILE)) {
|
|
27
|
-
return JSON.parse(
|
|
92
|
+
return JSON.parse(readFileSync2(CONFIG_FILE, "utf-8"));
|
|
28
93
|
}
|
|
29
94
|
} catch {
|
|
30
95
|
}
|
|
@@ -144,9 +209,11 @@ async function bootstrapCache() {
|
|
|
144
209
|
const apiUrl = getApiUrl();
|
|
145
210
|
const headers = {
|
|
146
211
|
"Content-Type": "application/json",
|
|
147
|
-
"Authorization": `Bearer ${token}
|
|
212
|
+
"Authorization": `Bearer ${token}`,
|
|
213
|
+
"X-CLI-Version": CLI_VERSION
|
|
148
214
|
};
|
|
149
215
|
const userInfoResponse = await fetch(`${apiUrl}/v1/cli/me`, { headers });
|
|
216
|
+
await exitIfUpgradeRequired(userInfoResponse);
|
|
150
217
|
if (!userInfoResponse.ok) {
|
|
151
218
|
throw new Error("Failed to fetch user info");
|
|
152
219
|
}
|
|
@@ -157,6 +224,7 @@ async function bootstrapCache() {
|
|
|
157
224
|
return bootstrap;
|
|
158
225
|
}
|
|
159
226
|
const projectsResponse = await fetch(`${apiUrl}/v1/projects?org_id=${user.org_id}`, { headers });
|
|
227
|
+
await exitIfUpgradeRequired(projectsResponse);
|
|
160
228
|
if (projectsResponse.ok) {
|
|
161
229
|
const projectsPayload = await projectsResponse.json();
|
|
162
230
|
if (!Array.isArray(projectsPayload.projects)) {
|
|
@@ -176,6 +244,7 @@ async function bootstrapCache() {
|
|
|
176
244
|
`${apiUrl}/v1/cli/connectors?project_id=${currentProjectId}`,
|
|
177
245
|
{ headers }
|
|
178
246
|
);
|
|
247
|
+
await exitIfUpgradeRequired(connectorsResponse);
|
|
179
248
|
if (connectorsResponse.ok) {
|
|
180
249
|
const connectorsPayload = await connectorsResponse.json();
|
|
181
250
|
if (!Array.isArray(connectorsPayload.connectors)) {
|
|
@@ -196,6 +265,7 @@ async function bootstrapCache() {
|
|
|
196
265
|
`${apiUrl}/v1/cli/branches?connector_id=${currentConnectorId}`,
|
|
197
266
|
{ headers }
|
|
198
267
|
);
|
|
268
|
+
await exitIfUpgradeRequired(branchesResponse);
|
|
199
269
|
if (branchesResponse.ok) {
|
|
200
270
|
const branchesPayload = await branchesResponse.json();
|
|
201
271
|
if (!Array.isArray(branchesPayload.branches)) {
|
|
@@ -209,49 +279,8 @@ async function bootstrapCache() {
|
|
|
209
279
|
}
|
|
210
280
|
|
|
211
281
|
// src/lib/api.ts
|
|
212
|
-
function getCliVersion() {
|
|
213
|
-
try {
|
|
214
|
-
const packageUrl = new URL("../package.json", import.meta.url);
|
|
215
|
-
const raw = readFileSync2(packageUrl, "utf-8");
|
|
216
|
-
const parsed = JSON.parse(raw);
|
|
217
|
-
return parsed.version ?? "unknown";
|
|
218
|
-
} catch {
|
|
219
|
-
return "unknown";
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
var CLI_VERSION = getCliVersion();
|
|
223
|
-
function formatErrorDetail(detail) {
|
|
224
|
-
if (typeof detail === "string") return detail;
|
|
225
|
-
if (Array.isArray(detail)) {
|
|
226
|
-
return detail.map((entry) => {
|
|
227
|
-
const location = Array.isArray(entry.loc) ? entry.loc.join(" \u2192 ") : "";
|
|
228
|
-
const message = entry.msg ?? "unknown error";
|
|
229
|
-
return location ? `${location}: ${message}` : String(message);
|
|
230
|
-
}).join("; ");
|
|
231
|
-
}
|
|
232
|
-
return JSON.stringify(detail);
|
|
233
|
-
}
|
|
234
|
-
function parseApiError(status, text) {
|
|
235
|
-
try {
|
|
236
|
-
const json = JSON.parse(text);
|
|
237
|
-
if (json.detail) return `API error ${status}: ${formatErrorDetail(json.detail)}`;
|
|
238
|
-
} catch {
|
|
239
|
-
}
|
|
240
|
-
return `API error ${status}: ${text}`;
|
|
241
|
-
}
|
|
242
282
|
function handleUpgradeRequired(text) {
|
|
243
|
-
|
|
244
|
-
const json = JSON.parse(text);
|
|
245
|
-
if (json.detail) {
|
|
246
|
-
console.error(`
|
|
247
|
-
\u2717 ${json.detail}
|
|
248
|
-
`);
|
|
249
|
-
}
|
|
250
|
-
} catch {
|
|
251
|
-
console.error("\n\u2717 Your CLI is outdated. Please update:\n");
|
|
252
|
-
}
|
|
253
|
-
console.error(" npm install -g ardent-cli@latest\n");
|
|
254
|
-
process.exit(1);
|
|
283
|
+
exitWithUpgradeRequiredMessage(text);
|
|
255
284
|
}
|
|
256
285
|
var ApiClient = class {
|
|
257
286
|
getHeaders() {
|
|
@@ -347,6 +376,69 @@ function isGatewayTimeoutError(err) {
|
|
|
347
376
|
return isNetworkError(err);
|
|
348
377
|
}
|
|
349
378
|
|
|
379
|
+
// src/lib/connector_selection.ts
|
|
380
|
+
function clearSelectedConnector() {
|
|
381
|
+
setConfig("currentConnectorId", void 0);
|
|
382
|
+
setConfig("currentConnectorName", void 0);
|
|
383
|
+
clearCurrentBranch();
|
|
384
|
+
}
|
|
385
|
+
function findConnectorById(connectors, connectorId) {
|
|
386
|
+
for (const connector of connectors) {
|
|
387
|
+
if (connector.id === connectorId) {
|
|
388
|
+
return connector;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
return void 0;
|
|
392
|
+
}
|
|
393
|
+
function reconcileSelectedConnector(connectors) {
|
|
394
|
+
const currentConnectorId = getConfig("currentConnectorId");
|
|
395
|
+
if (currentConnectorId) {
|
|
396
|
+
const selectedConnector = findConnectorById(connectors, currentConnectorId);
|
|
397
|
+
if (selectedConnector) {
|
|
398
|
+
setConfig("currentConnectorName", selectedConnector.name);
|
|
399
|
+
return selectedConnector;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
clearSelectedConnector();
|
|
403
|
+
if (connectors.length === 1) {
|
|
404
|
+
const onlyConnector = connectors[0];
|
|
405
|
+
setConfig("currentConnectorId", onlyConnector.id);
|
|
406
|
+
setConfig("currentConnectorName", onlyConnector.name);
|
|
407
|
+
return onlyConnector;
|
|
408
|
+
}
|
|
409
|
+
return void 0;
|
|
410
|
+
}
|
|
411
|
+
async function requireCurrentConnectorId() {
|
|
412
|
+
const currentProjectId = getConfig("currentProjectId");
|
|
413
|
+
if (!currentProjectId) {
|
|
414
|
+
console.error("\u2717 No current project set. Switch to a project first:");
|
|
415
|
+
console.error(" ardent project list");
|
|
416
|
+
console.error(" ardent project switch <name>");
|
|
417
|
+
process.exit(1);
|
|
418
|
+
}
|
|
419
|
+
const result = await api.get(
|
|
420
|
+
`/v1/cli/connectors?project_id=${currentProjectId}`
|
|
421
|
+
);
|
|
422
|
+
if (!result.connectors) {
|
|
423
|
+
throw new Error("API returned invalid response: missing connectors array");
|
|
424
|
+
}
|
|
425
|
+
setCacheEntry("connectors", result.connectors);
|
|
426
|
+
const selectedConnector = reconcileSelectedConnector(result.connectors);
|
|
427
|
+
if (selectedConnector) {
|
|
428
|
+
return selectedConnector.id;
|
|
429
|
+
}
|
|
430
|
+
if (result.connectors.length === 0) {
|
|
431
|
+
console.error("\u2717 No connectors found.");
|
|
432
|
+
console.error(" Create one with: ardent connector create postgresql <url>");
|
|
433
|
+
} else {
|
|
434
|
+
console.error("\u2717 Previously selected connector is no longer available.");
|
|
435
|
+
console.error(" Select one of your current connectors:");
|
|
436
|
+
console.error(" ardent connector list");
|
|
437
|
+
console.error(" ardent connector switch <name>");
|
|
438
|
+
}
|
|
439
|
+
process.exit(1);
|
|
440
|
+
}
|
|
441
|
+
|
|
350
442
|
// src/lib/telemetry.ts
|
|
351
443
|
import { randomUUID } from "crypto";
|
|
352
444
|
function getAnonymousId() {
|
|
@@ -400,11 +492,7 @@ function identifyUser(userId, personProperties = {}) {
|
|
|
400
492
|
async function createAction(name, options) {
|
|
401
493
|
try {
|
|
402
494
|
const startTime = performance.now();
|
|
403
|
-
const connectorId =
|
|
404
|
-
if (!connectorId) {
|
|
405
|
-
console.error("\u2717 No connector selected. Run 'ardent connector switch' first.");
|
|
406
|
-
process.exit(1);
|
|
407
|
-
}
|
|
495
|
+
const connectorId = await requireCurrentConnectorId();
|
|
408
496
|
await api.post("/v1/branch/create", {
|
|
409
497
|
connector_id: connectorId,
|
|
410
498
|
service_type: options.service,
|
|
@@ -1105,7 +1193,8 @@ async function listAction2() {
|
|
|
1105
1193
|
console.log(`${green3} Create one with: ardent connector create postgresql <url>${reset3}`);
|
|
1106
1194
|
return;
|
|
1107
1195
|
}
|
|
1108
|
-
const
|
|
1196
|
+
const selectedConnector = fromCache ? void 0 : reconcileSelectedConnector(connectors);
|
|
1197
|
+
const currentConnectorId = selectedConnector?.id ?? getConfig("currentConnectorId");
|
|
1109
1198
|
const green2 = "\x1B[32m";
|
|
1110
1199
|
const dim2 = "\x1B[2m";
|
|
1111
1200
|
const yellow = "\x1B[33m";
|
|
@@ -1996,8 +2085,9 @@ async function loginAction(options) {
|
|
|
1996
2085
|
try {
|
|
1997
2086
|
const initResponse = await fetch(`${getApiUrl()}/v1/cli/auth/init`, {
|
|
1998
2087
|
method: "POST",
|
|
1999
|
-
headers: { "Content-Type": "application/json" }
|
|
2088
|
+
headers: { "Content-Type": "application/json", "X-CLI-Version": CLI_VERSION }
|
|
2000
2089
|
});
|
|
2090
|
+
await exitIfUpgradeRequired(initResponse);
|
|
2001
2091
|
if (!initResponse.ok) {
|
|
2002
2092
|
const error = await initResponse.text();
|
|
2003
2093
|
trackEvent("CLI: login failed", { method: "browser", reason: "init_failed" });
|
|
@@ -2014,8 +2104,10 @@ async function loginAction(options) {
|
|
|
2014
2104
|
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
2015
2105
|
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
2016
2106
|
const pollResponse = await fetch(
|
|
2017
|
-
`${getApiUrl()}/v1/cli/auth/poll?session=${session_id}
|
|
2107
|
+
`${getApiUrl()}/v1/cli/auth/poll?session=${session_id}`,
|
|
2108
|
+
{ headers: { "X-CLI-Version": CLI_VERSION } }
|
|
2018
2109
|
);
|
|
2110
|
+
await exitIfUpgradeRequired(pollResponse);
|
|
2019
2111
|
if (!pollResponse.ok) {
|
|
2020
2112
|
trackEvent("CLI: login failed", { method: "browser", reason: "poll_failed" });
|
|
2021
2113
|
console.error("\u2717 Poll failed");
|
|
@@ -2224,19 +2316,8 @@ EXAMPLES
|
|
|
2224
2316
|
ardent branch switch my-feature
|
|
2225
2317
|
ardent org members
|
|
2226
2318
|
`;
|
|
2227
|
-
var CLI_VERSION2 = getCliVersion2();
|
|
2228
2319
|
var program = new Command8();
|
|
2229
|
-
|
|
2230
|
-
try {
|
|
2231
|
-
const packageUrl = new URL("../package.json", import.meta.url);
|
|
2232
|
-
const raw = readFileSync5(packageUrl, "utf-8");
|
|
2233
|
-
const parsed = JSON.parse(raw);
|
|
2234
|
-
return parsed.version ?? "unknown";
|
|
2235
|
-
} catch {
|
|
2236
|
-
return "unknown";
|
|
2237
|
-
}
|
|
2238
|
-
}
|
|
2239
|
-
program.name("ardent").description("CLI for Ardent database branching").version(CLI_VERSION2).configureHelp({
|
|
2320
|
+
program.name("ardent").description("CLI for Ardent database branching").version(CLI_VERSION).configureHelp({
|
|
2240
2321
|
formatHelp: () => BANNER + HELP_TEXT
|
|
2241
2322
|
});
|
|
2242
2323
|
program.addCommand(loginCommand);
|
|
@@ -2268,5 +2349,5 @@ if (args.length === 0) {
|
|
|
2268
2349
|
program.help();
|
|
2269
2350
|
}
|
|
2270
2351
|
getAnonymousId();
|
|
2271
|
-
checkForUpdate(
|
|
2352
|
+
checkForUpdate(CLI_VERSION);
|
|
2272
2353
|
program.parse();
|