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.
Files changed (2) hide show
  1. package/dist/index.js +149 -48
  2. 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 createResponse = await api.post(
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 = createResponse?.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) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ardent-cli",
3
- "version": "0.0.50",
3
+ "version": "0.0.51",
4
4
  "description": "Git for Data infrastructure",
5
5
  "type": "module",
6
6
  "bin": {