ardent-cli 0.0.24 → 0.0.25

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.
Files changed (2) hide show
  1. package/dist/index.js +147 -70
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,19 +1,80 @@
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
+ return `${formatErrorDetail(json.detail)}
31
+
32
+ npm install -g ardent-cli@latest`;
33
+ }
34
+ } catch {
35
+ }
36
+ return "Your CLI is outdated. Please update:\n\n npm install -g ardent-cli@latest";
37
+ }
38
+ function parseApiError(status, text) {
39
+ if (status === 426) {
40
+ return formatUpgradeRequiredMessage(text);
41
+ }
42
+ try {
43
+ const json = JSON.parse(text);
44
+ if (json.detail) return `API error ${status}: ${formatErrorDetail(json.detail)}`;
45
+ } catch {
46
+ }
47
+ return `API error ${status}: ${text}`;
48
+ }
49
+ function exitWithUpgradeRequiredMessage(text) {
50
+ console.error(`
51
+ \u2717 ${formatUpgradeRequiredMessage(text)}
52
+ `);
53
+ process.exit(1);
54
+ }
55
+ async function exitIfUpgradeRequired(response) {
56
+ if (response.status !== 426) {
57
+ return;
58
+ }
59
+ const text = await response.text();
60
+ exitWithUpgradeRequiredMessage(text);
61
+ }
62
+
63
+ // src/lib/cli_version.ts
64
+ import { readFileSync } from "fs";
65
+ function getCliVersion() {
66
+ try {
67
+ const packageUrl = new URL("../package.json", import.meta.url);
68
+ const raw = readFileSync(packageUrl, "utf-8");
69
+ const parsed = JSON.parse(raw);
70
+ return parsed.version ?? "unknown";
71
+ } catch {
72
+ return "unknown";
73
+ }
74
+ }
75
+ var CLI_VERSION = getCliVersion();
76
+
77
+ // src/lib/config.ts
17
78
  var CONFIG_DIR = join(homedir(), ".ardent");
18
79
  var CONFIG_FILE = join(CONFIG_DIR, "config.json");
19
80
  function ensureConfigDir() {
@@ -24,7 +85,7 @@ function ensureConfigDir() {
24
85
  function loadConfig() {
25
86
  try {
26
87
  if (existsSync(CONFIG_FILE)) {
27
- return JSON.parse(readFileSync(CONFIG_FILE, "utf-8"));
88
+ return JSON.parse(readFileSync2(CONFIG_FILE, "utf-8"));
28
89
  }
29
90
  } catch {
30
91
  }
@@ -144,9 +205,11 @@ async function bootstrapCache() {
144
205
  const apiUrl = getApiUrl();
145
206
  const headers = {
146
207
  "Content-Type": "application/json",
147
- "Authorization": `Bearer ${token}`
208
+ "Authorization": `Bearer ${token}`,
209
+ "X-CLI-Version": CLI_VERSION
148
210
  };
149
211
  const userInfoResponse = await fetch(`${apiUrl}/v1/cli/me`, { headers });
212
+ await exitIfUpgradeRequired(userInfoResponse);
150
213
  if (!userInfoResponse.ok) {
151
214
  throw new Error("Failed to fetch user info");
152
215
  }
@@ -157,6 +220,7 @@ async function bootstrapCache() {
157
220
  return bootstrap;
158
221
  }
159
222
  const projectsResponse = await fetch(`${apiUrl}/v1/projects?org_id=${user.org_id}`, { headers });
223
+ await exitIfUpgradeRequired(projectsResponse);
160
224
  if (projectsResponse.ok) {
161
225
  const projectsPayload = await projectsResponse.json();
162
226
  if (!Array.isArray(projectsPayload.projects)) {
@@ -176,6 +240,7 @@ async function bootstrapCache() {
176
240
  `${apiUrl}/v1/cli/connectors?project_id=${currentProjectId}`,
177
241
  { headers }
178
242
  );
243
+ await exitIfUpgradeRequired(connectorsResponse);
179
244
  if (connectorsResponse.ok) {
180
245
  const connectorsPayload = await connectorsResponse.json();
181
246
  if (!Array.isArray(connectorsPayload.connectors)) {
@@ -196,6 +261,7 @@ async function bootstrapCache() {
196
261
  `${apiUrl}/v1/cli/branches?connector_id=${currentConnectorId}`,
197
262
  { headers }
198
263
  );
264
+ await exitIfUpgradeRequired(branchesResponse);
199
265
  if (branchesResponse.ok) {
200
266
  const branchesPayload = await branchesResponse.json();
201
267
  if (!Array.isArray(branchesPayload.branches)) {
@@ -209,49 +275,8 @@ async function bootstrapCache() {
209
275
  }
210
276
 
211
277
  // 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
278
  function handleUpgradeRequired(text) {
243
- try {
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);
279
+ exitWithUpgradeRequiredMessage(text);
255
280
  }
256
281
  var ApiClient = class {
257
282
  getHeaders() {
@@ -347,6 +372,69 @@ function isGatewayTimeoutError(err) {
347
372
  return isNetworkError(err);
348
373
  }
349
374
 
375
+ // src/lib/connector_selection.ts
376
+ function clearSelectedConnector() {
377
+ setConfig("currentConnectorId", void 0);
378
+ setConfig("currentConnectorName", void 0);
379
+ clearCurrentBranch();
380
+ }
381
+ function findConnectorById(connectors, connectorId) {
382
+ for (const connector of connectors) {
383
+ if (connector.id === connectorId) {
384
+ return connector;
385
+ }
386
+ }
387
+ return void 0;
388
+ }
389
+ function reconcileSelectedConnector(connectors) {
390
+ const currentConnectorId = getConfig("currentConnectorId");
391
+ if (currentConnectorId) {
392
+ const selectedConnector = findConnectorById(connectors, currentConnectorId);
393
+ if (selectedConnector) {
394
+ setConfig("currentConnectorName", selectedConnector.name);
395
+ return selectedConnector;
396
+ }
397
+ }
398
+ clearSelectedConnector();
399
+ if (connectors.length === 1) {
400
+ const onlyConnector = connectors[0];
401
+ setConfig("currentConnectorId", onlyConnector.id);
402
+ setConfig("currentConnectorName", onlyConnector.name);
403
+ return onlyConnector;
404
+ }
405
+ return void 0;
406
+ }
407
+ async function requireCurrentConnectorId() {
408
+ const currentProjectId = getConfig("currentProjectId");
409
+ if (!currentProjectId) {
410
+ console.error("\u2717 No current project set. Switch to a project first:");
411
+ console.error(" ardent project list");
412
+ console.error(" ardent project switch <name>");
413
+ process.exit(1);
414
+ }
415
+ const result = await api.get(
416
+ `/v1/cli/connectors?project_id=${currentProjectId}`
417
+ );
418
+ if (!result.connectors) {
419
+ throw new Error("API returned invalid response: missing connectors array");
420
+ }
421
+ setCacheEntry("connectors", result.connectors);
422
+ const selectedConnector = reconcileSelectedConnector(result.connectors);
423
+ if (selectedConnector) {
424
+ return selectedConnector.id;
425
+ }
426
+ if (result.connectors.length === 0) {
427
+ console.error("\u2717 No connectors found.");
428
+ console.error(" Create one with: ardent connector create postgresql <url>");
429
+ } else {
430
+ console.error("\u2717 Previously selected connector is no longer available.");
431
+ console.error(" Select one of your current connectors:");
432
+ console.error(" ardent connector list");
433
+ console.error(" ardent connector switch <name>");
434
+ }
435
+ process.exit(1);
436
+ }
437
+
350
438
  // src/lib/telemetry.ts
351
439
  import { randomUUID } from "crypto";
352
440
  function getAnonymousId() {
@@ -400,11 +488,7 @@ function identifyUser(userId, personProperties = {}) {
400
488
  async function createAction(name, options) {
401
489
  try {
402
490
  const startTime = performance.now();
403
- const connectorId = getConfig("currentConnectorId");
404
- if (!connectorId) {
405
- console.error("\u2717 No connector selected. Run 'ardent connector switch' first.");
406
- process.exit(1);
407
- }
491
+ const connectorId = await requireCurrentConnectorId();
408
492
  await api.post("/v1/branch/create", {
409
493
  connector_id: connectorId,
410
494
  service_type: options.service,
@@ -1105,7 +1189,8 @@ async function listAction2() {
1105
1189
  console.log(`${green3} Create one with: ardent connector create postgresql <url>${reset3}`);
1106
1190
  return;
1107
1191
  }
1108
- const currentConnectorId = getConfig("currentConnectorId");
1192
+ const selectedConnector = fromCache ? void 0 : reconcileSelectedConnector(connectors);
1193
+ const currentConnectorId = selectedConnector?.id ?? getConfig("currentConnectorId");
1109
1194
  const green2 = "\x1B[32m";
1110
1195
  const dim2 = "\x1B[2m";
1111
1196
  const yellow = "\x1B[33m";
@@ -1996,8 +2081,9 @@ async function loginAction(options) {
1996
2081
  try {
1997
2082
  const initResponse = await fetch(`${getApiUrl()}/v1/cli/auth/init`, {
1998
2083
  method: "POST",
1999
- headers: { "Content-Type": "application/json" }
2084
+ headers: { "Content-Type": "application/json", "X-CLI-Version": CLI_VERSION }
2000
2085
  });
2086
+ await exitIfUpgradeRequired(initResponse);
2001
2087
  if (!initResponse.ok) {
2002
2088
  const error = await initResponse.text();
2003
2089
  trackEvent("CLI: login failed", { method: "browser", reason: "init_failed" });
@@ -2014,8 +2100,10 @@ async function loginAction(options) {
2014
2100
  for (let attempt = 0; attempt < maxAttempts; attempt++) {
2015
2101
  await new Promise((resolve) => setTimeout(resolve, pollInterval));
2016
2102
  const pollResponse = await fetch(
2017
- `${getApiUrl()}/v1/cli/auth/poll?session=${session_id}`
2103
+ `${getApiUrl()}/v1/cli/auth/poll?session=${session_id}`,
2104
+ { headers: { "X-CLI-Version": CLI_VERSION } }
2018
2105
  );
2106
+ await exitIfUpgradeRequired(pollResponse);
2019
2107
  if (!pollResponse.ok) {
2020
2108
  trackEvent("CLI: login failed", { method: "browser", reason: "poll_failed" });
2021
2109
  console.error("\u2717 Poll failed");
@@ -2224,19 +2312,8 @@ EXAMPLES
2224
2312
  ardent branch switch my-feature
2225
2313
  ardent org members
2226
2314
  `;
2227
- var CLI_VERSION2 = getCliVersion2();
2228
2315
  var program = new Command8();
2229
- function getCliVersion2() {
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({
2316
+ program.name("ardent").description("CLI for Ardent database branching").version(CLI_VERSION).configureHelp({
2240
2317
  formatHelp: () => BANNER + HELP_TEXT
2241
2318
  });
2242
2319
  program.addCommand(loginCommand);
@@ -2268,5 +2345,5 @@ if (args.length === 0) {
2268
2345
  program.help();
2269
2346
  }
2270
2347
  getAnonymousId();
2271
- checkForUpdate(CLI_VERSION2);
2348
+ checkForUpdate(CLI_VERSION);
2272
2349
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ardent-cli",
3
- "version": "0.0.24",
3
+ "version": "0.0.25",
4
4
  "description": "Git for Data infrastructure",
5
5
  "type": "module",
6
6
  "bin": {