@robinmordasiewicz/f5xc-xcsh 1.0.82-2601011720 → 1.0.82-2601012039

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 +236 -150
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -45392,8 +45392,8 @@ function getLogoModeFromEnv(envPrefix) {
45392
45392
  var CLI_NAME = "xcsh";
45393
45393
  var CLI_FULL_NAME = "F5 Distributed Cloud Shell";
45394
45394
  function getVersion() {
45395
- if ("v1.0.82-2601011720") {
45396
- return "v1.0.82-2601011720";
45395
+ if ("v1.0.82-2601012039") {
45396
+ return "v1.0.82-2601012039";
45397
45397
  }
45398
45398
  if (process.env.XCSH_VERSION) {
45399
45399
  return process.env.XCSH_VERSION;
@@ -46655,6 +46655,120 @@ function formatAPIError(statusCode, body, operation) {
46655
46655
  return lines.join("\n");
46656
46656
  }
46657
46657
 
46658
+ // src/output/domain-formatter.ts
46659
+ function parseDomainOutputFlags(args, sessionFormat = "table") {
46660
+ const { format: parsedFormat, remainingArgs } = parseOutputFlag(args);
46661
+ let noColor = false;
46662
+ const finalArgs = [];
46663
+ for (const arg of remainingArgs) {
46664
+ if (arg === "--no-color") {
46665
+ noColor = true;
46666
+ } else {
46667
+ finalArgs.push(arg);
46668
+ }
46669
+ }
46670
+ const effectiveNoColor = noColor || !shouldUseColors();
46671
+ return {
46672
+ options: {
46673
+ format: parsedFormat ?? sessionFormat,
46674
+ noColor: effectiveNoColor
46675
+ },
46676
+ remainingArgs: finalArgs
46677
+ };
46678
+ }
46679
+ function formatDomainOutput(data, options) {
46680
+ const { format, noColor } = options;
46681
+ if (format === "none") {
46682
+ return [];
46683
+ }
46684
+ const formatted = formatOutput(data, format, noColor);
46685
+ if (formatted === "") {
46686
+ return [];
46687
+ }
46688
+ return formatted.split("\n");
46689
+ }
46690
+ function formatKeyValueOutput(data, options) {
46691
+ const { format, noColor, title } = options;
46692
+ if (format === "none") {
46693
+ return [];
46694
+ }
46695
+ if (format === "json") {
46696
+ return formatJSON(data).split("\n");
46697
+ }
46698
+ if (format === "yaml") {
46699
+ return formatYAML(data).split("\n");
46700
+ }
46701
+ if (format === "tsv") {
46702
+ const lines = [];
46703
+ for (const [key, value] of Object.entries(data)) {
46704
+ if (value !== null && value !== void 0) {
46705
+ lines.push(`${key} ${String(value)}`);
46706
+ }
46707
+ }
46708
+ return lines;
46709
+ }
46710
+ const boxData = [];
46711
+ for (const [key, value] of Object.entries(data)) {
46712
+ if (value !== null && value !== void 0) {
46713
+ const label = formatLabel(key);
46714
+ boxData.push({ label, value: String(value) });
46715
+ }
46716
+ }
46717
+ if (boxData.length === 0) {
46718
+ return [];
46719
+ }
46720
+ const boxOutput = formatKeyValueBox(boxData, title ?? "Info", noColor);
46721
+ return boxOutput.split("\n");
46722
+ }
46723
+ function formatListOutput(data, options) {
46724
+ const { format, noColor } = options;
46725
+ if (format === "none") {
46726
+ return [];
46727
+ }
46728
+ if (format === "json") {
46729
+ return formatJSON(data).split("\n");
46730
+ }
46731
+ if (format === "yaml") {
46732
+ return formatYAML(data).split("\n");
46733
+ }
46734
+ if (format === "tsv") {
46735
+ if (data.length === 0) {
46736
+ return [];
46737
+ }
46738
+ const firstItem = data[0];
46739
+ if (typeof firstItem !== "object" || firstItem === null) {
46740
+ return data.map((item) => String(item));
46741
+ }
46742
+ const keys = Object.keys(firstItem);
46743
+ const lines = [];
46744
+ for (const item of data) {
46745
+ if (typeof item === "object" && item !== null) {
46746
+ const record = item;
46747
+ const values = keys.map((k) => {
46748
+ const val = record[k];
46749
+ if (val === null || val === void 0) return "";
46750
+ if (typeof val === "object") return JSON.stringify(val);
46751
+ return String(val);
46752
+ });
46753
+ lines.push(values.join(" "));
46754
+ }
46755
+ }
46756
+ return lines;
46757
+ }
46758
+ const tableOutput = formatResourceTable(data, noColor);
46759
+ if (tableOutput === "") {
46760
+ return [];
46761
+ }
46762
+ return tableOutput.split("\n");
46763
+ }
46764
+ function formatLabel(key) {
46765
+ if (key.includes("_")) {
46766
+ return key.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
46767
+ }
46768
+ const withSpaces = key.replace(/([A-Z])/g, " $1");
46769
+ return withSpaces.charAt(0).toUpperCase() + withSpaces.slice(1);
46770
+ }
46771
+
46658
46772
  // src/config/envvars.ts
46659
46773
  var EnvVarRegistry = [
46660
46774
  {
@@ -47937,6 +48051,9 @@ var REPLSession = class {
47937
48051
  _validationError = null;
47938
48052
  // Authentication source tracking
47939
48053
  _authSource = "none";
48054
+ // Fallback tracking for improved error messages
48055
+ _fallbackAttempted = false;
48056
+ _fallbackReason = null;
47940
48057
  constructor(config = {}) {
47941
48058
  this._namespace = config.namespace ?? this.getDefaultNamespace();
47942
48059
  this._contextPath = new ContextPath();
@@ -47994,36 +48111,57 @@ var REPLSession = class {
47994
48111
  validationError: this._validationError,
47995
48112
  authSource: this._authSource
47996
48113
  });
47997
- if (!result.valid && (this._authSource === "env" || this._authSource === "mixed") && this._activeProfile?.apiToken && this._activeProfile.apiToken !== this._apiToken) {
47998
- debugProtocol.auth("token_fallback_attempt", {
47999
- fromSource: this._authSource,
48000
- hasProfileToken: true,
48001
- profileName: this._activeProfileName
48002
- });
48003
- this._apiToken = this._activeProfile.apiToken;
48004
- if (this._authSource === "mixed" && !process.env[`${ENV_PREFIX}_API_URL`] && this._activeProfile.apiUrl) {
48005
- this._serverUrl = this._activeProfile.apiUrl;
48006
- this._tenant = this.extractTenant(
48007
- this._activeProfile.apiUrl
48008
- );
48009
- }
48010
- this._apiClient = new APIClient({
48011
- serverUrl: this._serverUrl,
48012
- apiToken: this._apiToken,
48013
- debug: this._debug
48014
- });
48015
- const fallbackResult = await this._apiClient.validateToken();
48016
- if (fallbackResult.valid) {
48017
- this._tokenValidated = true;
48018
- this._validationError = null;
48019
- this._authSource = "profile-fallback";
48020
- debugProtocol.auth("token_fallback_success", {
48021
- authSource: this._authSource,
48114
+ if (!result.valid && (this._authSource === "env" || this._authSource === "mixed")) {
48115
+ if (this._activeProfile?.apiToken && this._activeProfile.apiToken !== this._apiToken) {
48116
+ this._fallbackAttempted = true;
48117
+ debugProtocol.auth("token_fallback_attempt", {
48118
+ fromSource: this._authSource,
48119
+ hasProfileToken: true,
48022
48120
  profileName: this._activeProfileName
48023
48121
  });
48024
- } else {
48025
- debugProtocol.auth("token_fallback_failed", {
48026
- error: fallbackResult.error,
48122
+ this._apiToken = this._activeProfile.apiToken;
48123
+ if (this._authSource === "mixed" && !process.env[`${ENV_PREFIX}_API_URL`] && this._activeProfile.apiUrl) {
48124
+ this._serverUrl = this._activeProfile.apiUrl;
48125
+ this._tenant = this.extractTenant(
48126
+ this._activeProfile.apiUrl
48127
+ );
48128
+ }
48129
+ this._apiClient = new APIClient({
48130
+ serverUrl: this._serverUrl,
48131
+ apiToken: this._apiToken,
48132
+ debug: this._debug
48133
+ });
48134
+ const fallbackResult = await this._apiClient.validateToken();
48135
+ if (fallbackResult.valid) {
48136
+ this._tokenValidated = true;
48137
+ this._validationError = null;
48138
+ this._authSource = "profile-fallback";
48139
+ this._fallbackReason = null;
48140
+ debugProtocol.auth("token_fallback_success", {
48141
+ authSource: this._authSource,
48142
+ profileName: this._activeProfileName
48143
+ });
48144
+ } else {
48145
+ this._fallbackReason = `Profile '${this._activeProfileName}' credentials are also invalid`;
48146
+ debugProtocol.auth("token_fallback_failed", {
48147
+ error: fallbackResult.error,
48148
+ profileName: this._activeProfileName
48149
+ });
48150
+ }
48151
+ } else if (this._activeProfile?.apiToken && this._activeProfile.apiToken === this._apiToken) {
48152
+ this._fallbackReason = `Profile '${this._activeProfileName}' has the same credentials - please update`;
48153
+ debugProtocol.auth("token_fallback_skipped", {
48154
+ reason: "same_token",
48155
+ profileName: this._activeProfileName
48156
+ });
48157
+ } else if (!this._activeProfile?.apiToken) {
48158
+ if (this._activeProfileName) {
48159
+ this._fallbackReason = `Profile '${this._activeProfileName}' has no saved credentials`;
48160
+ } else {
48161
+ this._fallbackReason = "No saved profiles available for fallback";
48162
+ }
48163
+ debugProtocol.auth("token_fallback_skipped", {
48164
+ reason: "no_profile_token",
48027
48165
  profileName: this._activeProfileName
48028
48166
  });
48029
48167
  }
@@ -48223,6 +48361,18 @@ var REPLSession = class {
48223
48361
  getAuthSource() {
48224
48362
  return this._authSource;
48225
48363
  }
48364
+ /**
48365
+ * Check if a credential fallback was attempted
48366
+ */
48367
+ getFallbackAttempted() {
48368
+ return this._fallbackAttempted;
48369
+ }
48370
+ /**
48371
+ * Get the reason why fallback failed or was skipped (for user messaging)
48372
+ */
48373
+ getFallbackReason() {
48374
+ return this._fallbackReason;
48375
+ }
48226
48376
  /**
48227
48377
  * Get the API client
48228
48378
  */
@@ -48280,6 +48430,8 @@ var REPLSession = class {
48280
48430
  this.clearNamespaceCache();
48281
48431
  this._tokenValidated = false;
48282
48432
  this._validationError = null;
48433
+ this._fallbackAttempted = false;
48434
+ this._fallbackReason = null;
48283
48435
  this._activeProfileName = profileName;
48284
48436
  this._activeProfile = profile;
48285
48437
  if (profile.apiUrl) {
@@ -48841,120 +48993,6 @@ function useHistory(options) {
48841
48993
  // src/repl/hooks/useCompletion.ts
48842
48994
  var import_react27 = __toESM(require_react(), 1);
48843
48995
 
48844
- // src/output/domain-formatter.ts
48845
- function parseDomainOutputFlags(args, sessionFormat = "table") {
48846
- const { format: parsedFormat, remainingArgs } = parseOutputFlag(args);
48847
- let noColor = false;
48848
- const finalArgs = [];
48849
- for (const arg of remainingArgs) {
48850
- if (arg === "--no-color") {
48851
- noColor = true;
48852
- } else {
48853
- finalArgs.push(arg);
48854
- }
48855
- }
48856
- const effectiveNoColor = noColor || !shouldUseColors();
48857
- return {
48858
- options: {
48859
- format: parsedFormat ?? sessionFormat,
48860
- noColor: effectiveNoColor
48861
- },
48862
- remainingArgs: finalArgs
48863
- };
48864
- }
48865
- function formatDomainOutput(data, options) {
48866
- const { format, noColor } = options;
48867
- if (format === "none") {
48868
- return [];
48869
- }
48870
- const formatted = formatOutput(data, format, noColor);
48871
- if (formatted === "") {
48872
- return [];
48873
- }
48874
- return formatted.split("\n");
48875
- }
48876
- function formatKeyValueOutput(data, options) {
48877
- const { format, noColor, title } = options;
48878
- if (format === "none") {
48879
- return [];
48880
- }
48881
- if (format === "json") {
48882
- return formatJSON(data).split("\n");
48883
- }
48884
- if (format === "yaml") {
48885
- return formatYAML(data).split("\n");
48886
- }
48887
- if (format === "tsv") {
48888
- const lines = [];
48889
- for (const [key, value] of Object.entries(data)) {
48890
- if (value !== null && value !== void 0) {
48891
- lines.push(`${key} ${String(value)}`);
48892
- }
48893
- }
48894
- return lines;
48895
- }
48896
- const boxData = [];
48897
- for (const [key, value] of Object.entries(data)) {
48898
- if (value !== null && value !== void 0) {
48899
- const label = formatLabel(key);
48900
- boxData.push({ label, value: String(value) });
48901
- }
48902
- }
48903
- if (boxData.length === 0) {
48904
- return [];
48905
- }
48906
- const boxOutput = formatKeyValueBox(boxData, title ?? "Info", noColor);
48907
- return boxOutput.split("\n");
48908
- }
48909
- function formatListOutput(data, options) {
48910
- const { format, noColor } = options;
48911
- if (format === "none") {
48912
- return [];
48913
- }
48914
- if (format === "json") {
48915
- return formatJSON(data).split("\n");
48916
- }
48917
- if (format === "yaml") {
48918
- return formatYAML(data).split("\n");
48919
- }
48920
- if (format === "tsv") {
48921
- if (data.length === 0) {
48922
- return [];
48923
- }
48924
- const firstItem = data[0];
48925
- if (typeof firstItem !== "object" || firstItem === null) {
48926
- return data.map((item) => String(item));
48927
- }
48928
- const keys = Object.keys(firstItem);
48929
- const lines = [];
48930
- for (const item of data) {
48931
- if (typeof item === "object" && item !== null) {
48932
- const record = item;
48933
- const values = keys.map((k) => {
48934
- const val = record[k];
48935
- if (val === null || val === void 0) return "";
48936
- if (typeof val === "object") return JSON.stringify(val);
48937
- return String(val);
48938
- });
48939
- lines.push(values.join(" "));
48940
- }
48941
- }
48942
- return lines;
48943
- }
48944
- const tableOutput = formatResourceTable(data, noColor);
48945
- if (tableOutput === "") {
48946
- return [];
48947
- }
48948
- return tableOutput.split("\n");
48949
- }
48950
- function formatLabel(key) {
48951
- if (key.includes("_")) {
48952
- return key.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
48953
- }
48954
- const withSpaces = key.replace(/([A-Z])/g, " $1");
48955
- return withSpaces.charAt(0).toUpperCase() + withSpaces.slice(1);
48956
- }
48957
-
48958
48996
  // src/domains/login/profile/list.ts
48959
48997
  var listCommand = {
48960
48998
  name: "list",
@@ -53520,9 +53558,12 @@ async function executeAPICommand(session, ctx, cmd) {
53520
53558
  }
53521
53559
  }
53522
53560
  const effectiveFormat = outputFormat ?? session.getOutputFormat();
53523
- const formatted = formatOutput(result, effectiveFormat, noColor);
53561
+ const formatted = formatDomainOutput(result, {
53562
+ format: effectiveFormat,
53563
+ noColor: noColor ?? false
53564
+ });
53524
53565
  return {
53525
- output: formatted ? [formatted] : ["(no output)"],
53566
+ output: formatted.length > 0 ? formatted : ["(no output)"],
53526
53567
  shouldExit: false,
53527
53568
  shouldClear: false,
53528
53569
  contextChanged: false
@@ -54376,12 +54417,35 @@ program2.name(CLI_NAME).description("F5 Distributed Cloud Shell - Interactive CL
54376
54417
  emitSessionState(session);
54377
54418
  process.stdout.write("\r\x1B[K");
54378
54419
  renderBanner(cliLogoMode, "startup");
54379
- if (session.isAuthenticated() && !session.isTokenValidated() && session.getValidationError()) {
54420
+ if (session.getAuthSource() === "profile-fallback") {
54421
+ const profileName = session.getActiveProfileName();
54380
54422
  console.log("");
54381
54423
  console.log(
54382
- `${colors.yellow}Warning: ${session.getValidationError()}${colors.reset}`
54424
+ `${colors.blue}Info: Using credentials from profile '${profileName}' (environment variables were invalid)${colors.reset}`
54383
54425
  );
54384
54426
  }
54427
+ if (session.isAuthenticated() && !session.isTokenValidated() && session.getValidationError()) {
54428
+ const authSource = session.getAuthSource();
54429
+ const fallbackReason = session.getFallbackReason();
54430
+ console.log("");
54431
+ if (authSource === "env" || authSource === "mixed") {
54432
+ console.log(
54433
+ `${colors.yellow}Warning: Environment variable credentials are invalid or expired${colors.reset}`
54434
+ );
54435
+ if (fallbackReason) {
54436
+ console.log(
54437
+ `${colors.dim} ${fallbackReason}${colors.reset}`
54438
+ );
54439
+ }
54440
+ console.log(
54441
+ `${colors.dim} Run 'login' to authenticate or update your F5XC_API_TOKEN environment variable${colors.reset}`
54442
+ );
54443
+ } else {
54444
+ console.log(
54445
+ `${colors.yellow}Warning: ${session.getValidationError()}${colors.reset}`
54446
+ );
54447
+ }
54448
+ }
54385
54449
  const profiles = await session.getProfileManager().list();
54386
54450
  const envConfigured = process.env[`${ENV_PREFIX}_API_URL`] && process.env[`${ENV_PREFIX}_API_TOKEN`];
54387
54451
  if (profiles.length === 0 && !envConfigured) {
@@ -54424,11 +54488,33 @@ async function executeNonInteractive(args) {
54424
54488
  command: args.join(" ")
54425
54489
  });
54426
54490
  emitSessionState(session);
54427
- if (session.isAuthenticated() && !session.isTokenValidated() && session.getValidationError()) {
54491
+ if (session.getAuthSource() === "profile-fallback") {
54492
+ const profileName = session.getActiveProfileName();
54428
54493
  console.error(
54429
- `${colors.yellow}Warning: ${session.getValidationError()}${colors.reset}`
54494
+ `${colors.blue}Info: Using credentials from profile '${profileName}' (environment variables were invalid)${colors.reset}`
54430
54495
  );
54431
54496
  }
54497
+ if (session.isAuthenticated() && !session.isTokenValidated() && session.getValidationError()) {
54498
+ const authSource = session.getAuthSource();
54499
+ const fallbackReason = session.getFallbackReason();
54500
+ if (authSource === "env" || authSource === "mixed") {
54501
+ console.error(
54502
+ `${colors.yellow}Warning: Environment variable credentials are invalid or expired${colors.reset}`
54503
+ );
54504
+ if (fallbackReason) {
54505
+ console.error(
54506
+ `${colors.dim} ${fallbackReason}${colors.reset}`
54507
+ );
54508
+ }
54509
+ console.error(
54510
+ `${colors.dim} Run 'login' to authenticate or update your F5XC_API_TOKEN environment variable${colors.reset}`
54511
+ );
54512
+ } else {
54513
+ console.error(
54514
+ `${colors.yellow}Warning: ${session.getValidationError()}${colors.reset}`
54515
+ );
54516
+ }
54517
+ }
54432
54518
  const command = args.join(" ");
54433
54519
  const result = await executeCommand(command, session);
54434
54520
  result.output.forEach((line) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@robinmordasiewicz/f5xc-xcsh",
3
- "version": "1.0.82-2601011720",
3
+ "version": "1.0.82-2601012039",
4
4
  "description": "F5 Distributed Cloud Shell - Interactive CLI for F5 XC",
5
5
  "type": "module",
6
6
  "bin": {