ardent-cli 0.0.50 → 0.0.51
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 +149 -48
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -511,6 +511,58 @@ async function resolveCurrentConnectorId() {
|
|
|
511
511
|
);
|
|
512
512
|
}
|
|
513
513
|
|
|
514
|
+
// src/lib/operation_stage_display.ts
|
|
515
|
+
var STAGE_DISPLAY = {
|
|
516
|
+
// engine_setup_worker / postgres_engine_setup
|
|
517
|
+
"dispatched": "Queued",
|
|
518
|
+
"preparing": "Preparing",
|
|
519
|
+
"creating-neon-project": "Provisioning the branch target",
|
|
520
|
+
"preparing-target-databases": "Preparing target databases",
|
|
521
|
+
"deploying-pgstream": "Starting replication",
|
|
522
|
+
"applying-rls": "Applying RLS policies",
|
|
523
|
+
"storing-credentials": "Storing connection credentials",
|
|
524
|
+
"validating": "Validating the branch target",
|
|
525
|
+
// reset_worker / reset_connector
|
|
526
|
+
"resetting": "Resetting",
|
|
527
|
+
"deleting-pgstream": "Stopping replication",
|
|
528
|
+
"rediscovering-source": "Re-checking the source database",
|
|
529
|
+
"resetting-neon-main": "Resetting the branch target",
|
|
530
|
+
"creating-target-schemas": "Recreating target schemas",
|
|
531
|
+
"redeploying-pgstream": "Restarting replication",
|
|
532
|
+
// environment deploy_worker
|
|
533
|
+
"loading_config": "Loading environment configuration",
|
|
534
|
+
"deploying_infrastructure": "Provisioning environment infrastructure",
|
|
535
|
+
"recording_success": "Finalizing environment",
|
|
536
|
+
"cleaning_failed_deploy": "Cleaning up failed environment provisioning",
|
|
537
|
+
// environment destroy_worker
|
|
538
|
+
"deleting_private_links": "Removing private network links",
|
|
539
|
+
"destroying_infrastructure": "Tearing down environment infrastructure",
|
|
540
|
+
"recording_destroy_success": "Finalizing environment teardown",
|
|
541
|
+
// discovery_worker / run_discovery_crawl (ARD-1098)
|
|
542
|
+
"connecting": "Connecting to source",
|
|
543
|
+
"enumerating_databases": "Listing databases",
|
|
544
|
+
"scanning_database": "Scanning schema",
|
|
545
|
+
"writing_schema": "Saving discovered schema",
|
|
546
|
+
"merging_results": "Combining results",
|
|
547
|
+
// branch.create.v1 workflow (ARD-1244)
|
|
548
|
+
"provisioning": "Provisioning the branch",
|
|
549
|
+
"configuring": "Storing connection credentials",
|
|
550
|
+
"recording": "Recording the branch",
|
|
551
|
+
"finalizing": "Finalizing the branch",
|
|
552
|
+
"activating": "Activating the branch"
|
|
553
|
+
};
|
|
554
|
+
function humanizeRawStage(_raw) {
|
|
555
|
+
return "Working";
|
|
556
|
+
}
|
|
557
|
+
function operationStageDisplay(stage) {
|
|
558
|
+
if (!stage) return "Working";
|
|
559
|
+
const colonIndex = stage.indexOf(":");
|
|
560
|
+
const base = colonIndex === -1 ? stage : stage.slice(0, colonIndex);
|
|
561
|
+
const suffix = colonIndex === -1 ? "" : stage.slice(colonIndex + 1);
|
|
562
|
+
const label = STAGE_DISPLAY[base] ?? humanizeRawStage(base);
|
|
563
|
+
return suffix ? `${label} (for ${suffix})` : label;
|
|
564
|
+
}
|
|
565
|
+
|
|
514
566
|
// src/lib/resource_name_validation.ts
|
|
515
567
|
var RESERVED_SUFFIXES = ["pooler", "readonly", "direct"];
|
|
516
568
|
var MAX_RESOURCE_NAME_LENGTH = 100;
|
|
@@ -683,6 +735,28 @@ function isMachineReadableBranchInvocation(args2) {
|
|
|
683
735
|
}
|
|
684
736
|
|
|
685
737
|
// src/commands/branch/create.ts
|
|
738
|
+
var BRANCH_CREATE_MAX_WAIT_MS = 10 * 60 * 1e3;
|
|
739
|
+
var BRANCH_CREATE_POLL_INTERVAL_MS = 2 * 1e3;
|
|
740
|
+
var BRANCH_CREATE_IN_PROGRESS_DETAIL = "Branch creation is still in progress";
|
|
741
|
+
function branchCreateMaxWaitMs() {
|
|
742
|
+
return Number(process.env.ARDENT_BRANCH_CREATE_MAX_WAIT_MS) || BRANCH_CREATE_MAX_WAIT_MS;
|
|
743
|
+
}
|
|
744
|
+
function branchCreatePollIntervalMs() {
|
|
745
|
+
return Number(process.env.ARDENT_BRANCH_CREATE_POLL_INTERVAL_MS) || BRANCH_CREATE_POLL_INTERVAL_MS;
|
|
746
|
+
}
|
|
747
|
+
var BRANCH_CREATE_TRANSIENT_WARN_EVERY = 10;
|
|
748
|
+
function asBranchCreateWarning(value) {
|
|
749
|
+
if (value && typeof value === "object" && value.type === "stale_source" && typeof value.message === "string") {
|
|
750
|
+
return value;
|
|
751
|
+
}
|
|
752
|
+
return void 0;
|
|
753
|
+
}
|
|
754
|
+
function isBranchCreateInProgressError(err) {
|
|
755
|
+
if (!(err instanceof Error)) {
|
|
756
|
+
return false;
|
|
757
|
+
}
|
|
758
|
+
return err.message.includes("API error 409") && err.message.includes(BRANCH_CREATE_IN_PROGRESS_DETAIL);
|
|
759
|
+
}
|
|
686
760
|
async function createAction(name, options) {
|
|
687
761
|
const modeResolution = resolveOutputMode(options);
|
|
688
762
|
if (modeResolution.error) {
|
|
@@ -715,7 +789,7 @@ async function createAction(name, options) {
|
|
|
715
789
|
idempotencyKey = randomUUID2();
|
|
716
790
|
setPendingBranchCreateKey(idempotencyScopeKey, idempotencyKey);
|
|
717
791
|
}
|
|
718
|
-
const
|
|
792
|
+
const dispatch = await api.post(
|
|
719
793
|
"/v1/branch/create",
|
|
720
794
|
{
|
|
721
795
|
connector_id: connectorId,
|
|
@@ -724,7 +798,7 @@ async function createAction(name, options) {
|
|
|
724
798
|
},
|
|
725
799
|
{ "X-Idempotency-Key": idempotencyKey }
|
|
726
800
|
);
|
|
727
|
-
const warning =
|
|
801
|
+
const warning = await pollBranchCreate(dispatch.operation_id, idempotencyScopeKey, mode);
|
|
728
802
|
const response = await api.get(`/v1/cli/branches?connector_id=${connectorId}`);
|
|
729
803
|
const apiBranches = response.branches || [];
|
|
730
804
|
let apiBranch;
|
|
@@ -816,6 +890,15 @@ ${url}`);
|
|
|
816
890
|
printCurrentConnectorSelectionError(err);
|
|
817
891
|
process.exit(1);
|
|
818
892
|
}
|
|
893
|
+
if (err instanceof BranchCreateTimeoutError) {
|
|
894
|
+
trackEvent("CLI: branch create failed", { reason: "timeout", output_mode: mode });
|
|
895
|
+
if (mode === "json") {
|
|
896
|
+
process.stdout.write(renderBranchJsonError("timeout", err.message));
|
|
897
|
+
process.exit(1);
|
|
898
|
+
}
|
|
899
|
+
console.error(`\u2717 ${err.message}`);
|
|
900
|
+
process.exit(1);
|
|
901
|
+
}
|
|
819
902
|
if (isNetworkError(err)) {
|
|
820
903
|
trackEvent("CLI: branch create failed", { reason: "offline", output_mode: mode });
|
|
821
904
|
if (mode === "json") {
|
|
@@ -827,6 +910,19 @@ ${url}`);
|
|
|
827
910
|
console.error("\u2717 Cannot create branch while offline");
|
|
828
911
|
process.exit(1);
|
|
829
912
|
}
|
|
913
|
+
if (isBranchCreateInProgressError(err)) {
|
|
914
|
+
trackEvent("CLI: branch create failed", {
|
|
915
|
+
reason: "in_progress",
|
|
916
|
+
output_mode: mode
|
|
917
|
+
});
|
|
918
|
+
const message2 = err instanceof Error ? err.message : String(err);
|
|
919
|
+
if (mode === "json") {
|
|
920
|
+
process.stdout.write(renderBranchJsonError("api_error", message2));
|
|
921
|
+
process.exit(1);
|
|
922
|
+
}
|
|
923
|
+
console.error("\u2717 Failed:", message2);
|
|
924
|
+
process.exit(1);
|
|
925
|
+
}
|
|
830
926
|
if (idempotencyScopeKey) {
|
|
831
927
|
clearPendingBranchCreateKey(idempotencyScopeKey);
|
|
832
928
|
}
|
|
@@ -840,6 +936,57 @@ ${url}`);
|
|
|
840
936
|
process.exit(1);
|
|
841
937
|
}
|
|
842
938
|
}
|
|
939
|
+
var BranchCreateTimeoutError = class extends Error {
|
|
940
|
+
constructor(message) {
|
|
941
|
+
super(message);
|
|
942
|
+
this.name = "BranchCreateTimeoutError";
|
|
943
|
+
}
|
|
944
|
+
};
|
|
945
|
+
async function pollBranchCreate(operationId, idempotencyScopeKey, mode) {
|
|
946
|
+
const startedAt = Date.now();
|
|
947
|
+
const maxWaitMs = branchCreateMaxWaitMs();
|
|
948
|
+
const pollIntervalMs = branchCreatePollIntervalMs();
|
|
949
|
+
let lastStage = null;
|
|
950
|
+
let consecutiveTransientFailures = 0;
|
|
951
|
+
let firstPoll = true;
|
|
952
|
+
while (Date.now() - startedAt < maxWaitMs) {
|
|
953
|
+
if (!firstPoll) {
|
|
954
|
+
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
|
|
955
|
+
}
|
|
956
|
+
firstPoll = false;
|
|
957
|
+
let op;
|
|
958
|
+
try {
|
|
959
|
+
op = await api.get(`/v1/operations/${operationId}`);
|
|
960
|
+
} catch (pollErr) {
|
|
961
|
+
if (isTransientOperationPollError(pollErr)) {
|
|
962
|
+
consecutiveTransientFailures += 1;
|
|
963
|
+
if (consecutiveTransientFailures % BRANCH_CREATE_TRANSIENT_WARN_EVERY === 0 && mode !== "json") {
|
|
964
|
+
console.warn(
|
|
965
|
+
` \u26A0 Status check has failed ${consecutiveTransientFailures} times in a row. Branch creation is still running server-side and the CLI will keep waiting.`
|
|
966
|
+
);
|
|
967
|
+
}
|
|
968
|
+
continue;
|
|
969
|
+
}
|
|
970
|
+
throw pollErr;
|
|
971
|
+
}
|
|
972
|
+
consecutiveTransientFailures = 0;
|
|
973
|
+
if (op.stage && op.stage !== lastStage && mode !== "json" && mode !== "print-url") {
|
|
974
|
+
const progressLabel = op.progress != null ? ` (${op.progress}%)` : "";
|
|
975
|
+
console.log(` ${operationStageDisplay(op.stage)}${progressLabel}`);
|
|
976
|
+
lastStage = op.stage;
|
|
977
|
+
}
|
|
978
|
+
if (op.status === "completed") {
|
|
979
|
+
return asBranchCreateWarning(op.result?.warning);
|
|
980
|
+
}
|
|
981
|
+
if (op.status === "failed") {
|
|
982
|
+
clearPendingBranchCreateKey(idempotencyScopeKey);
|
|
983
|
+
throw new Error(op.error ?? "Branch creation failed");
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
throw new BranchCreateTimeoutError(
|
|
987
|
+
`Branch creation did not complete within ${Math.round(maxWaitMs / 6e4)} minutes. It may still be running server-side \u2014 do NOT assume it failed. Re-run the same command to resume, or check \`ardent branch list\`. If you contact Ardent support, reference operation id ${operationId}.`
|
|
988
|
+
);
|
|
989
|
+
}
|
|
843
990
|
|
|
844
991
|
// src/commands/branch/list.ts
|
|
845
992
|
function formatCreatedDate(createdAtIso) {
|
|
@@ -1143,52 +1290,6 @@ function printDegradedWarnings(warnings) {
|
|
|
1143
1290
|
console.log(" Review this connector with: ardent connector list");
|
|
1144
1291
|
}
|
|
1145
1292
|
|
|
1146
|
-
// src/lib/operation_stage_display.ts
|
|
1147
|
-
var STAGE_DISPLAY = {
|
|
1148
|
-
// engine_setup_worker / postgres_engine_setup
|
|
1149
|
-
"dispatched": "Starting",
|
|
1150
|
-
"preparing": "Preparing",
|
|
1151
|
-
"creating-neon-project": "Provisioning the branch target",
|
|
1152
|
-
"preparing-target-databases": "Preparing target databases",
|
|
1153
|
-
"deploying-pgstream": "Starting replication",
|
|
1154
|
-
"applying-rls": "Applying RLS policies",
|
|
1155
|
-
"storing-credentials": "Storing connection credentials",
|
|
1156
|
-
"validating": "Validating the branch target",
|
|
1157
|
-
// reset_worker / reset_connector
|
|
1158
|
-
"resetting": "Resetting",
|
|
1159
|
-
"deleting-pgstream": "Stopping replication",
|
|
1160
|
-
"rediscovering-source": "Re-checking the source database",
|
|
1161
|
-
"resetting-neon-main": "Resetting the branch target",
|
|
1162
|
-
"creating-target-schemas": "Recreating target schemas",
|
|
1163
|
-
"redeploying-pgstream": "Restarting replication",
|
|
1164
|
-
// environment deploy_worker
|
|
1165
|
-
"loading_config": "Loading environment configuration",
|
|
1166
|
-
"deploying_infrastructure": "Provisioning environment infrastructure",
|
|
1167
|
-
"recording_success": "Finalizing environment",
|
|
1168
|
-
"cleaning_failed_deploy": "Cleaning up failed environment provisioning",
|
|
1169
|
-
// environment destroy_worker
|
|
1170
|
-
"deleting_private_links": "Removing private network links",
|
|
1171
|
-
"destroying_infrastructure": "Tearing down environment infrastructure",
|
|
1172
|
-
"recording_destroy_success": "Finalizing environment teardown",
|
|
1173
|
-
// discovery_worker / run_discovery_crawl (ARD-1098)
|
|
1174
|
-
"connecting": "Connecting to source",
|
|
1175
|
-
"enumerating_databases": "Listing databases",
|
|
1176
|
-
"scanning_database": "Scanning schema",
|
|
1177
|
-
"writing_schema": "Saving discovered schema",
|
|
1178
|
-
"merging_results": "Combining results"
|
|
1179
|
-
};
|
|
1180
|
-
function humanizeRawStage(_raw) {
|
|
1181
|
-
return "Working";
|
|
1182
|
-
}
|
|
1183
|
-
function operationStageDisplay(stage) {
|
|
1184
|
-
if (!stage) return "Working";
|
|
1185
|
-
const colonIndex = stage.indexOf(":");
|
|
1186
|
-
const base = colonIndex === -1 ? stage : stage.slice(0, colonIndex);
|
|
1187
|
-
const suffix = colonIndex === -1 ? "" : stage.slice(colonIndex + 1);
|
|
1188
|
-
const label = STAGE_DISPLAY[base] ?? humanizeRawStage(base);
|
|
1189
|
-
return suffix ? `${label} (for ${suffix})` : label;
|
|
1190
|
-
}
|
|
1191
|
-
|
|
1192
1293
|
// src/lib/discover.ts
|
|
1193
1294
|
var DiscoveryTimeoutError = class extends Error {
|
|
1194
1295
|
constructor(message) {
|