ardent-cli 0.0.54 → 0.0.56
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 +109 -6
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -568,6 +568,9 @@ function operationStageDisplay(stage) {
|
|
|
568
568
|
const label = STAGE_DISPLAY[base] ?? humanizeRawStage(base);
|
|
569
569
|
return suffix ? `${label} (for ${suffix})` : label;
|
|
570
570
|
}
|
|
571
|
+
function operationStageLabel(op) {
|
|
572
|
+
return op.stage_label ?? operationStageDisplay(op.stage);
|
|
573
|
+
}
|
|
571
574
|
|
|
572
575
|
// src/lib/resource_name_validation.ts
|
|
573
576
|
var RESERVED_SUFFIXES = ["pooler", "readonly", "direct"];
|
|
@@ -978,7 +981,7 @@ async function pollBranchCreate(operationId, idempotencyScopeKey, mode) {
|
|
|
978
981
|
consecutiveTransientFailures = 0;
|
|
979
982
|
if (op.stage && op.stage !== lastStage && mode !== "json" && mode !== "print-url") {
|
|
980
983
|
const progressLabel = op.progress != null ? ` (${op.progress}%)` : "";
|
|
981
|
-
console.log(` ${
|
|
984
|
+
console.log(` ${operationStageLabel(op)}${progressLabel}`);
|
|
982
985
|
lastStage = op.stage;
|
|
983
986
|
}
|
|
984
987
|
if (op.status === "completed") {
|
|
@@ -1348,7 +1351,7 @@ async function runDiscoveryWithPolling(connectorId, options) {
|
|
|
1348
1351
|
}
|
|
1349
1352
|
if (op.stage && op.stage !== lastStage) {
|
|
1350
1353
|
const progressLabel = op.progress != null ? ` (${op.progress}%)` : "";
|
|
1351
|
-
console.log(` ${
|
|
1354
|
+
console.log(` ${operationStageLabel(op)}${progressLabel}`);
|
|
1352
1355
|
lastStage = op.stage;
|
|
1353
1356
|
}
|
|
1354
1357
|
if (op.status === "completed") {
|
|
@@ -1539,7 +1542,7 @@ async function runEngineSetupWithPolling(connectorId, connectorName, options = {
|
|
|
1539
1542
|
consecutiveTransientFailures = 0;
|
|
1540
1543
|
if (op.stage && op.stage !== lastStage) {
|
|
1541
1544
|
const progressLabel = op.progress != null ? ` (${op.progress}%)` : "";
|
|
1542
|
-
console.log(` ${
|
|
1545
|
+
console.log(` ${operationStageLabel(op)}${progressLabel}`);
|
|
1543
1546
|
lastStage = op.stage;
|
|
1544
1547
|
}
|
|
1545
1548
|
if (op.status === "completed") {
|
|
@@ -2655,8 +2658,9 @@ async function listAction2() {
|
|
|
2655
2658
|
if (render.kind === "engine_pending") enginePendingCount += 1;
|
|
2656
2659
|
const warnings = connector.warnings ?? [];
|
|
2657
2660
|
const warningSuffix = warnings.length > 0 ? ` ${yellow}\u26A0 ${warnings.length}${reset2}` : "";
|
|
2661
|
+
const lockSuffix = connector.deletion_locked ? ` ${yellow}[delete locked]${reset2}` : "";
|
|
2658
2662
|
const statusSuffix = render.kind === "ready" ? "" : ` ${render.color}[${connectorStatusDisplay(connector.status)}]${reset2}`;
|
|
2659
|
-
const nameLine = isCurrent ? `${green2}* ${render.color}${render.icon}${green2} ${connector.name}${reset2}${warningSuffix}${statusSuffix}` : ` ${render.color}${render.icon}${reset2} ${connector.name}${warningSuffix}${statusSuffix}`;
|
|
2663
|
+
const nameLine = isCurrent ? `${green2}* ${render.color}${render.icon}${green2} ${connector.name}${reset2}${warningSuffix}${lockSuffix}${statusSuffix}` : ` ${render.color}${render.icon}${reset2} ${connector.name}${warningSuffix}${lockSuffix}${statusSuffix}`;
|
|
2660
2664
|
console.log(nameLine);
|
|
2661
2665
|
if (isCurrent) {
|
|
2662
2666
|
console.log(`${green2} ${connector.service_name}${reset2}`);
|
|
@@ -2690,6 +2694,10 @@ async function listAction2() {
|
|
|
2690
2694
|
var CONNECTOR_DELETE_MAX_WAIT_MS = 60 * 60 * 1e3;
|
|
2691
2695
|
var CONNECTOR_DELETE_POLL_INTERVAL_MS = 5 * 1e3;
|
|
2692
2696
|
var CONNECTOR_DELETE_TRANSIENT_WARN_EVERY = 6;
|
|
2697
|
+
var CONNECTOR_DELETION_LOCKED_MESSAGE = "Connector deletion is locked. Unlock this connector, then retry.";
|
|
2698
|
+
function stripApiErrorPrefix(message) {
|
|
2699
|
+
return message.replace(/^API error \d{3}:\s*/, "");
|
|
2700
|
+
}
|
|
2693
2701
|
async function deleteAction2(name, options = {}) {
|
|
2694
2702
|
const cached = getCacheEntry("connectors");
|
|
2695
2703
|
let connector = cached?.data.find((c) => c.name === name);
|
|
@@ -2745,6 +2753,11 @@ async function deleteAction2(name, options = {}) {
|
|
|
2745
2753
|
process.exit(1);
|
|
2746
2754
|
}
|
|
2747
2755
|
const message = err instanceof Error ? err.message : String(err);
|
|
2756
|
+
if (message.includes(CONNECTOR_DELETION_LOCKED_MESSAGE)) {
|
|
2757
|
+
trackEvent("CLI: connector delete failed", { reason: "deletion_locked" });
|
|
2758
|
+
console.error(`\u2717 ${stripApiErrorPrefix(message)}`);
|
|
2759
|
+
process.exit(1);
|
|
2760
|
+
}
|
|
2748
2761
|
const isDrainRefusal = message.includes("Branch still has un-replicated changes") || typeof err === "object" && err !== null && "status" in err && err.status === 409;
|
|
2749
2762
|
if (isDrainRefusal) {
|
|
2750
2763
|
trackEvent("CLI: connector delete failed", { reason: "drain_refused" });
|
|
@@ -2780,7 +2793,7 @@ async function waitForConnectorDelete(operationId) {
|
|
|
2780
2793
|
consecutiveTransientFailures = 0;
|
|
2781
2794
|
if (operation.stage && operation.stage !== lastStage) {
|
|
2782
2795
|
const progressLabel = operation.progress != null ? ` (${operation.progress}%)` : "";
|
|
2783
|
-
console.log(` ${
|
|
2796
|
+
console.log(` ${operationStageLabel(operation)}${progressLabel}`);
|
|
2784
2797
|
lastStage = operation.stage;
|
|
2785
2798
|
}
|
|
2786
2799
|
if (operation.status === "completed") {
|
|
@@ -3250,6 +3263,94 @@ async function updateAction(name, options = {}) {
|
|
|
3250
3263
|
}
|
|
3251
3264
|
}
|
|
3252
3265
|
|
|
3266
|
+
// src/commands/connector/lock.ts
|
|
3267
|
+
async function resolveConnectorByName2(name) {
|
|
3268
|
+
const cached = getCacheEntry("connectors");
|
|
3269
|
+
let connector = cached?.data.find((candidate) => candidate.name === name);
|
|
3270
|
+
if (!connector) {
|
|
3271
|
+
try {
|
|
3272
|
+
const result = await api.get("/v1/cli/connectors");
|
|
3273
|
+
if (result.connectors) {
|
|
3274
|
+
setCacheEntry("connectors", result.connectors);
|
|
3275
|
+
connector = result.connectors.find((candidate) => candidate.name === name);
|
|
3276
|
+
}
|
|
3277
|
+
} catch (err) {
|
|
3278
|
+
if (isNetworkError(err)) {
|
|
3279
|
+
console.error("\u2717 Connector not found in cache and offline");
|
|
3280
|
+
process.exit(1);
|
|
3281
|
+
}
|
|
3282
|
+
throw err;
|
|
3283
|
+
}
|
|
3284
|
+
}
|
|
3285
|
+
if (!connector) {
|
|
3286
|
+
console.error(`\u2717 Connector "${name}" not found`);
|
|
3287
|
+
console.log(" Run: ardent connector list");
|
|
3288
|
+
process.exit(1);
|
|
3289
|
+
}
|
|
3290
|
+
return connector;
|
|
3291
|
+
}
|
|
3292
|
+
function refreshCachedConnector(updatedConnector) {
|
|
3293
|
+
const currentCache = getCacheEntry("connectors");
|
|
3294
|
+
if (!currentCache?.data) {
|
|
3295
|
+
return;
|
|
3296
|
+
}
|
|
3297
|
+
const updatedConnectors = currentCache.data.map(
|
|
3298
|
+
(connector) => connector.id === updatedConnector.id ? { ...connector, ...updatedConnector } : connector
|
|
3299
|
+
);
|
|
3300
|
+
setCacheEntry("connectors", updatedConnectors);
|
|
3301
|
+
}
|
|
3302
|
+
async function lockAction(name, options = {}) {
|
|
3303
|
+
const connector = await resolveConnectorByName2(name);
|
|
3304
|
+
try {
|
|
3305
|
+
const response = await api.post(
|
|
3306
|
+
`/v1/connectors/${connector.id}/deletion-lock`,
|
|
3307
|
+
{ reason: options.reason ?? null }
|
|
3308
|
+
);
|
|
3309
|
+
refreshCachedConnector({ ...response.connector, deletion_locked: true });
|
|
3310
|
+
trackEvent("CLI: connector deletion lock succeeded");
|
|
3311
|
+
console.log(`\u2713 Connector deletion locked for '${name}'`);
|
|
3312
|
+
} catch (err) {
|
|
3313
|
+
if (isPermissionError(err)) {
|
|
3314
|
+
trackEvent("CLI: connector deletion lock failed", { reason: "permission_denied" });
|
|
3315
|
+
console.error("\u2717 You don't have permission to update this connector.");
|
|
3316
|
+
process.exit(1);
|
|
3317
|
+
}
|
|
3318
|
+
if (isNetworkError(err)) {
|
|
3319
|
+
trackEvent("CLI: connector deletion lock failed", { reason: "offline" });
|
|
3320
|
+
console.error("\u2717 Cannot lock connector deletion while offline");
|
|
3321
|
+
process.exit(1);
|
|
3322
|
+
}
|
|
3323
|
+
trackEvent("CLI: connector deletion lock failed", { reason: "api_error" });
|
|
3324
|
+
console.error("\u2717 Failed:", err instanceof Error ? err.message : err);
|
|
3325
|
+
process.exit(1);
|
|
3326
|
+
}
|
|
3327
|
+
}
|
|
3328
|
+
async function unlockAction(name) {
|
|
3329
|
+
const connector = await resolveConnectorByName2(name);
|
|
3330
|
+
try {
|
|
3331
|
+
const response = await api.delete(
|
|
3332
|
+
`/v1/connectors/${connector.id}/deletion-lock`
|
|
3333
|
+
);
|
|
3334
|
+
refreshCachedConnector({ ...response.connector, deletion_locked: false });
|
|
3335
|
+
trackEvent("CLI: connector deletion unlock succeeded");
|
|
3336
|
+
console.log(`\u2713 Connector deletion unlocked for '${name}'`);
|
|
3337
|
+
} catch (err) {
|
|
3338
|
+
if (isPermissionError(err)) {
|
|
3339
|
+
trackEvent("CLI: connector deletion unlock failed", { reason: "permission_denied" });
|
|
3340
|
+
console.error("\u2717 You don't have permission to update this connector.");
|
|
3341
|
+
process.exit(1);
|
|
3342
|
+
}
|
|
3343
|
+
if (isNetworkError(err)) {
|
|
3344
|
+
trackEvent("CLI: connector deletion unlock failed", { reason: "offline" });
|
|
3345
|
+
console.error("\u2717 Cannot unlock connector deletion while offline");
|
|
3346
|
+
process.exit(1);
|
|
3347
|
+
}
|
|
3348
|
+
trackEvent("CLI: connector deletion unlock failed", { reason: "api_error" });
|
|
3349
|
+
console.error("\u2717 Failed:", err instanceof Error ? err.message : err);
|
|
3350
|
+
process.exit(1);
|
|
3351
|
+
}
|
|
3352
|
+
}
|
|
3353
|
+
|
|
3253
3354
|
// src/commands/connector/index.ts
|
|
3254
3355
|
var connectorCommand = new Command2("connector").description("Manage database connectors");
|
|
3255
3356
|
connectorCommand.command("preflight <type> [url]").description(
|
|
@@ -3300,8 +3401,10 @@ connectorCommand.command("update <name>").description("Update a connector's conf
|
|
|
3300
3401
|
).action(updateAction);
|
|
3301
3402
|
connectorCommand.command("delete <name>").description("Delete a connector by name").option(
|
|
3302
3403
|
"--force",
|
|
3303
|
-
"Skip the in-flight
|
|
3404
|
+
"Skip the wait for in-flight changes to finish replicating. Any un-replicated changes are abandoned."
|
|
3304
3405
|
).action(deleteAction2);
|
|
3406
|
+
connectorCommand.command("lock <name>").description("Lock connector deletion").option("--reason <text>", "Optional reason for the deletion lock").action(lockAction);
|
|
3407
|
+
connectorCommand.command("unlock <name>").description("Unlock connector deletion").action(unlockAction);
|
|
3305
3408
|
|
|
3306
3409
|
// src/commands/invite/index.ts
|
|
3307
3410
|
import { Command as Command3 } from "commander";
|