@xano/cli 1.0.2-beta.5 → 1.0.2-beta.7

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 (156) hide show
  1. package/README.md +87 -0
  2. package/dist/base-command.d.ts +21 -1
  3. package/dist/base-command.js +92 -6
  4. package/dist/commands/branch/create/index.d.ts +0 -1
  5. package/dist/commands/branch/create/index.js +1 -38
  6. package/dist/commands/branch/delete/index.d.ts +0 -1
  7. package/dist/commands/branch/delete/index.js +1 -39
  8. package/dist/commands/branch/edit/index.d.ts +0 -1
  9. package/dist/commands/branch/edit/index.js +1 -39
  10. package/dist/commands/branch/get/index.d.ts +0 -1
  11. package/dist/commands/branch/get/index.js +1 -39
  12. package/dist/commands/branch/list/index.d.ts +0 -1
  13. package/dist/commands/branch/list/index.js +1 -39
  14. package/dist/commands/branch/set_live/index.d.ts +0 -1
  15. package/dist/commands/branch/set_live/index.js +1 -39
  16. package/dist/commands/function/create/index.d.ts +0 -1
  17. package/dist/commands/function/create/index.js +1 -38
  18. package/dist/commands/function/edit/index.d.ts +0 -1
  19. package/dist/commands/function/edit/index.js +1 -37
  20. package/dist/commands/function/get/index.d.ts +0 -1
  21. package/dist/commands/function/get/index.js +1 -38
  22. package/dist/commands/function/list/index.d.ts +0 -1
  23. package/dist/commands/function/list/index.js +1 -39
  24. package/dist/commands/platform/get/index.d.ts +0 -1
  25. package/dist/commands/platform/get/index.js +1 -33
  26. package/dist/commands/platform/list/index.d.ts +0 -1
  27. package/dist/commands/platform/list/index.js +1 -33
  28. package/dist/commands/profile/use/index.d.ts +33 -0
  29. package/dist/commands/profile/use/index.js +179 -0
  30. package/dist/commands/release/create/index.d.ts +0 -1
  31. package/dist/commands/release/create/index.js +1 -33
  32. package/dist/commands/release/delete/index.d.ts +0 -1
  33. package/dist/commands/release/delete/index.js +1 -33
  34. package/dist/commands/release/deploy/index.js +1 -12
  35. package/dist/commands/release/edit/index.d.ts +0 -1
  36. package/dist/commands/release/edit/index.js +1 -33
  37. package/dist/commands/release/export/index.d.ts +0 -1
  38. package/dist/commands/release/export/index.js +1 -31
  39. package/dist/commands/release/get/index.d.ts +0 -1
  40. package/dist/commands/release/get/index.js +1 -33
  41. package/dist/commands/release/import/index.d.ts +0 -1
  42. package/dist/commands/release/import/index.js +1 -32
  43. package/dist/commands/release/list/index.d.ts +0 -1
  44. package/dist/commands/release/list/index.js +1 -32
  45. package/dist/commands/release/pull/index.d.ts +0 -1
  46. package/dist/commands/release/pull/index.js +2 -38
  47. package/dist/commands/release/push/index.d.ts +0 -1
  48. package/dist/commands/release/push/index.js +1 -37
  49. package/dist/commands/static_host/build/create/index.d.ts +0 -1
  50. package/dist/commands/static_host/build/create/index.js +1 -39
  51. package/dist/commands/static_host/build/get/index.d.ts +0 -1
  52. package/dist/commands/static_host/build/get/index.js +1 -39
  53. package/dist/commands/static_host/build/list/index.d.ts +0 -1
  54. package/dist/commands/static_host/build/list/index.js +1 -39
  55. package/dist/commands/static_host/list/index.d.ts +0 -1
  56. package/dist/commands/static_host/list/index.js +1 -39
  57. package/dist/commands/tenant/backup/create/index.d.ts +0 -1
  58. package/dist/commands/tenant/backup/create/index.js +1 -33
  59. package/dist/commands/tenant/backup/delete/index.d.ts +0 -1
  60. package/dist/commands/tenant/backup/delete/index.js +1 -32
  61. package/dist/commands/tenant/backup/export/index.d.ts +0 -1
  62. package/dist/commands/tenant/backup/export/index.js +1 -31
  63. package/dist/commands/tenant/backup/import/index.d.ts +0 -1
  64. package/dist/commands/tenant/backup/import/index.js +1 -32
  65. package/dist/commands/tenant/backup/list/index.d.ts +0 -1
  66. package/dist/commands/tenant/backup/list/index.js +1 -33
  67. package/dist/commands/tenant/backup/restore/index.d.ts +0 -1
  68. package/dist/commands/tenant/backup/restore/index.js +1 -32
  69. package/dist/commands/tenant/cluster/create/index.d.ts +0 -1
  70. package/dist/commands/tenant/cluster/create/index.js +1 -31
  71. package/dist/commands/tenant/cluster/delete/index.d.ts +0 -1
  72. package/dist/commands/tenant/cluster/delete/index.js +1 -33
  73. package/dist/commands/tenant/cluster/edit/index.d.ts +0 -1
  74. package/dist/commands/tenant/cluster/edit/index.js +1 -33
  75. package/dist/commands/tenant/cluster/get/index.d.ts +0 -1
  76. package/dist/commands/tenant/cluster/get/index.js +1 -32
  77. package/dist/commands/tenant/cluster/license/get/index.d.ts +0 -1
  78. package/dist/commands/tenant/cluster/license/get/index.js +1 -31
  79. package/dist/commands/tenant/cluster/license/set/index.d.ts +0 -1
  80. package/dist/commands/tenant/cluster/license/set/index.js +1 -31
  81. package/dist/commands/tenant/cluster/list/index.d.ts +0 -1
  82. package/dist/commands/tenant/cluster/list/index.js +1 -32
  83. package/dist/commands/tenant/create/index.d.ts +0 -1
  84. package/dist/commands/tenant/create/index.js +1 -30
  85. package/dist/commands/tenant/delete/index.d.ts +0 -1
  86. package/dist/commands/tenant/delete/index.js +1 -33
  87. package/dist/commands/tenant/deploy_platform/index.d.ts +0 -1
  88. package/dist/commands/tenant/deploy_platform/index.js +1 -31
  89. package/dist/commands/tenant/deploy_release/index.d.ts +0 -1
  90. package/dist/commands/tenant/deploy_release/index.js +1 -32
  91. package/dist/commands/tenant/edit/index.d.ts +0 -1
  92. package/dist/commands/tenant/edit/index.js +1 -33
  93. package/dist/commands/tenant/env/delete/index.d.ts +0 -1
  94. package/dist/commands/tenant/env/delete/index.js +1 -32
  95. package/dist/commands/tenant/env/get/index.d.ts +0 -1
  96. package/dist/commands/tenant/env/get/index.js +1 -32
  97. package/dist/commands/tenant/env/get_all/index.d.ts +0 -1
  98. package/dist/commands/tenant/env/get_all/index.js +1 -30
  99. package/dist/commands/tenant/env/list/index.d.ts +0 -1
  100. package/dist/commands/tenant/env/list/index.js +1 -32
  101. package/dist/commands/tenant/env/set/index.d.ts +0 -1
  102. package/dist/commands/tenant/env/set/index.js +1 -32
  103. package/dist/commands/tenant/env/set_all/index.d.ts +0 -1
  104. package/dist/commands/tenant/env/set_all/index.js +1 -30
  105. package/dist/commands/tenant/get/index.d.ts +0 -1
  106. package/dist/commands/tenant/get/index.js +1 -32
  107. package/dist/commands/tenant/impersonate/index.d.ts +0 -1
  108. package/dist/commands/tenant/impersonate/index.js +1 -32
  109. package/dist/commands/tenant/license/get/index.d.ts +0 -1
  110. package/dist/commands/tenant/license/get/index.js +1 -31
  111. package/dist/commands/tenant/license/set/index.d.ts +0 -1
  112. package/dist/commands/tenant/license/set/index.js +1 -31
  113. package/dist/commands/tenant/list/index.d.ts +0 -1
  114. package/dist/commands/tenant/list/index.js +1 -32
  115. package/dist/commands/tenant/pull/index.d.ts +0 -1
  116. package/dist/commands/tenant/pull/index.js +1 -37
  117. package/dist/commands/tenant/unit_test/list/index.js +1 -12
  118. package/dist/commands/tenant/unit_test/run/index.js +1 -12
  119. package/dist/commands/tenant/unit_test/run_all/index.js +1 -12
  120. package/dist/commands/tenant/workflow_test/list/index.js +1 -12
  121. package/dist/commands/tenant/workflow_test/run/index.js +1 -12
  122. package/dist/commands/tenant/workflow_test/run_all/index.js +1 -12
  123. package/dist/commands/unit_test/list/index.d.ts +0 -1
  124. package/dist/commands/unit_test/list/index.js +1 -33
  125. package/dist/commands/unit_test/run/index.d.ts +0 -1
  126. package/dist/commands/unit_test/run/index.js +1 -33
  127. package/dist/commands/unit_test/run_all/index.d.ts +0 -1
  128. package/dist/commands/unit_test/run_all/index.js +1 -32
  129. package/dist/commands/workflow_test/delete/index.d.ts +0 -1
  130. package/dist/commands/workflow_test/delete/index.js +1 -33
  131. package/dist/commands/workflow_test/get/index.d.ts +0 -1
  132. package/dist/commands/workflow_test/get/index.js +1 -33
  133. package/dist/commands/workflow_test/list/index.d.ts +0 -1
  134. package/dist/commands/workflow_test/list/index.js +1 -33
  135. package/dist/commands/workflow_test/run/index.d.ts +0 -1
  136. package/dist/commands/workflow_test/run/index.js +1 -33
  137. package/dist/commands/workflow_test/run_all/index.d.ts +0 -1
  138. package/dist/commands/workflow_test/run_all/index.js +1 -32
  139. package/dist/commands/workspace/create/index.d.ts +0 -1
  140. package/dist/commands/workspace/create/index.js +1 -39
  141. package/dist/commands/workspace/delete/index.d.ts +0 -1
  142. package/dist/commands/workspace/delete/index.js +1 -39
  143. package/dist/commands/workspace/edit/index.d.ts +0 -1
  144. package/dist/commands/workspace/edit/index.js +1 -38
  145. package/dist/commands/workspace/get/index.d.ts +0 -1
  146. package/dist/commands/workspace/get/index.js +1 -38
  147. package/dist/commands/workspace/list/index.d.ts +0 -1
  148. package/dist/commands/workspace/list/index.js +1 -38
  149. package/dist/commands/workspace/pull/index.d.ts +0 -1
  150. package/dist/commands/workspace/pull/index.js +1 -37
  151. package/dist/utils/local-config.d.ts +43 -0
  152. package/dist/utils/local-config.js +88 -0
  153. package/dist/utils/multidoc-push.d.ts +25 -0
  154. package/dist/utils/multidoc-push.js +39 -18
  155. package/oclif.manifest.json +2490 -2403
  156. package/package.json +1 -1
@@ -1,6 +1,4 @@
1
1
  import { Args, Flags } from '@oclif/core';
2
- import * as yaml from 'js-yaml';
3
- import * as fs from 'node:fs';
4
2
  import BaseCommand from '../../../base-command.js';
5
3
  export default class BranchSetLive extends BaseCommand {
6
4
  static args = {
@@ -50,23 +48,7 @@ Branch 'v1' is now live
50
48
  };
51
49
  async run() {
52
50
  const { args, flags } = await this.parse(BranchSetLive);
53
- // Get profile name (default or from flag/env)
54
- const profileName = flags.profile || this.getDefaultProfile();
55
- // Load credentials
56
- const credentials = this.loadCredentials();
57
- // Get the profile configuration
58
- if (!(profileName in credentials.profiles)) {
59
- this.error(`Profile '${profileName}' not found. Available profiles: ${Object.keys(credentials.profiles).join(', ')}\n` +
60
- `Create a profile using 'xano profile create'`);
61
- }
62
- const profile = credentials.profiles[profileName];
63
- // Validate required fields
64
- if (!profile.instance_origin) {
65
- this.error(`Profile '${profileName}' is missing instance_origin`);
66
- }
67
- if (!profile.access_token) {
68
- this.error(`Profile '${profileName}' is missing access_token`);
69
- }
51
+ const { profile } = this.resolveProfile(flags);
70
52
  // Get workspace ID from flag or profile
71
53
  const workspaceId = flags.workspace || profile.workspace;
72
54
  if (!workspaceId) {
@@ -129,24 +111,4 @@ Branch 'v1' is now live
129
111
  });
130
112
  });
131
113
  }
132
- loadCredentials() {
133
- const credentialsPath = this.getCredentialsPath();
134
- // Check if credentials file exists
135
- if (!fs.existsSync(credentialsPath)) {
136
- this.error(`Credentials file not found at ${credentialsPath}\n` +
137
- `Create a profile using 'xano profile create'`);
138
- }
139
- // Read credentials file
140
- try {
141
- const fileContent = fs.readFileSync(credentialsPath, 'utf8');
142
- const parsed = yaml.load(fileContent);
143
- if (!parsed || typeof parsed !== 'object' || !('profiles' in parsed)) {
144
- this.error('Credentials file has invalid format.');
145
- }
146
- return parsed;
147
- }
148
- catch (error) {
149
- this.error(`Failed to parse credentials file: ${error}`);
150
- }
151
- }
152
114
  }
@@ -15,6 +15,5 @@ export default class FunctionCreate extends BaseCommand {
15
15
  };
16
16
  run(): Promise<void>;
17
17
  private editFile;
18
- private loadCredentials;
19
18
  private readStdin;
20
19
  }
@@ -1,5 +1,4 @@
1
1
  import { Flags } from '@oclif/core';
2
- import * as yaml from 'js-yaml';
3
2
  import { execSync } from 'node:child_process';
4
3
  import * as fs from 'node:fs';
5
4
  import * as os from 'node:os';
@@ -75,23 +74,7 @@ Name: my_function
75
74
  };
76
75
  async run() {
77
76
  const { flags } = await this.parse(FunctionCreate);
78
- // Get profile name (default or from flag/env)
79
- const profileName = flags.profile || this.getDefaultProfile();
80
- // Load credentials
81
- const credentials = this.loadCredentials();
82
- // Get the profile configuration
83
- if (!(profileName in credentials.profiles)) {
84
- this.error(`Profile '${profileName}' not found. Available profiles: ${Object.keys(credentials.profiles).join(', ')}\n` +
85
- `Create a profile using 'xano profile:create'`);
86
- }
87
- const profile = credentials.profiles[profileName];
88
- // Validate required fields
89
- if (!profile.instance_origin) {
90
- this.error(`Profile '${profileName}' is missing instance_origin`);
91
- }
92
- if (!profile.access_token) {
93
- this.error(`Profile '${profileName}' is missing access_token`);
94
- }
77
+ const { profile, profileName } = this.resolveProfile(flags);
95
78
  // Determine workspace_id from flag or profile
96
79
  let workspaceId;
97
80
  if (flags.workspace) {
@@ -240,26 +223,6 @@ Name: my_function
240
223
  }
241
224
  return tmpFile;
242
225
  }
243
- loadCredentials() {
244
- const credentialsPath = this.getCredentialsPath();
245
- // Check if credentials file exists
246
- if (!fs.existsSync(credentialsPath)) {
247
- this.error(`Credentials file not found at ${credentialsPath}\n` +
248
- `Create a profile using 'xano profile:create'`);
249
- }
250
- // Read credentials file
251
- try {
252
- const fileContent = fs.readFileSync(credentialsPath, 'utf8');
253
- const parsed = yaml.load(fileContent);
254
- if (!parsed || typeof parsed !== 'object' || !('profiles' in parsed)) {
255
- this.error('Credentials file has invalid format.');
256
- }
257
- return parsed;
258
- }
259
- catch (error) {
260
- this.error(`Failed to parse credentials file: ${error}`);
261
- }
262
- }
263
226
  async readStdin() {
264
227
  return new Promise((resolve, reject) => {
265
228
  const chunks = [];
@@ -20,7 +20,6 @@ export default class FunctionEdit extends BaseCommand {
20
20
  private editFile;
21
21
  private editFunctionContent;
22
22
  private fetchFunctionCode;
23
- private loadCredentials;
24
23
  private promptForFunctionId;
25
24
  private readStdin;
26
25
  }
@@ -1,6 +1,5 @@
1
1
  import { Args, Flags } from '@oclif/core';
2
2
  import inquirer from 'inquirer';
3
- import * as yaml from 'js-yaml';
4
3
  import { execSync } from 'node:child_process';
5
4
  import * as fs from 'node:fs';
6
5
  import * as os from 'node:os';
@@ -102,23 +101,7 @@ Name: my_function
102
101
  };
103
102
  async run() {
104
103
  const { args, flags } = await this.parse(FunctionEdit);
105
- // Get profile name (default or from flag/env)
106
- const profileName = flags.profile || this.getDefaultProfile();
107
- // Load credentials
108
- const credentials = this.loadCredentials();
109
- // Get the profile configuration
110
- if (!(profileName in credentials.profiles)) {
111
- this.error(`Profile '${profileName}' not found. Available profiles: ${Object.keys(credentials.profiles).join(', ')}\n` +
112
- `Create a profile using 'xano profile:create'`);
113
- }
114
- const profile = credentials.profiles[profileName];
115
- // Validate required fields
116
- if (!profile.instance_origin) {
117
- this.error(`Profile '${profileName}' is missing instance_origin`);
118
- }
119
- if (!profile.access_token) {
120
- this.error(`Profile '${profileName}' is missing access_token`);
121
- }
104
+ const { profile, profileName } = this.resolveProfile(flags);
122
105
  // Validate flag combinations
123
106
  if (flags.edit && !flags.file) {
124
107
  this.error('The --edit flag requires --file to be specified');
@@ -368,25 +351,6 @@ Name: my_function
368
351
  throw error;
369
352
  }
370
353
  }
371
- loadCredentials() {
372
- const credentialsPath = this.getCredentialsPath();
373
- // Check if credentials file exists
374
- if (!fs.existsSync(credentialsPath)) {
375
- this.error(`Credentials file not found at ${credentialsPath}\n` + `Create a profile using 'xano profile:create'`);
376
- }
377
- // Read credentials file
378
- try {
379
- const fileContent = fs.readFileSync(credentialsPath, 'utf8');
380
- const parsed = yaml.load(fileContent);
381
- if (!parsed || typeof parsed !== 'object' || !('profiles' in parsed)) {
382
- this.error('Credentials file has invalid format.');
383
- }
384
- return parsed;
385
- }
386
- catch (error) {
387
- this.error(`Failed to parse credentials file: ${error}`);
388
- }
389
- }
390
354
  async promptForFunctionId(profile, workspaceId) {
391
355
  try {
392
356
  // Fetch list of functions
@@ -15,6 +15,5 @@ export default class FunctionGet extends BaseCommand {
15
15
  verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
16
16
  };
17
17
  run(): Promise<void>;
18
- private loadCredentials;
19
18
  private promptForFunctionId;
20
19
  }
@@ -1,7 +1,5 @@
1
1
  import { Args, Flags } from '@oclif/core';
2
2
  import inquirer from 'inquirer';
3
- import * as yaml from 'js-yaml';
4
- import * as fs from 'node:fs';
5
3
  import BaseCommand, { buildUserAgent } from '../../../base-command.js';
6
4
  export default class FunctionGet extends BaseCommand {
7
5
  static args = {
@@ -76,23 +74,7 @@ function yo {
76
74
  };
77
75
  async run() {
78
76
  const { args, flags } = await this.parse(FunctionGet);
79
- // Get profile name (default or from flag/env)
80
- const profileName = flags.profile || this.getDefaultProfile();
81
- // Load credentials
82
- const credentials = this.loadCredentials();
83
- // Get the profile configuration
84
- if (!(profileName in credentials.profiles)) {
85
- this.error(`Profile '${profileName}' not found. Available profiles: ${Object.keys(credentials.profiles).join(', ')}\n` +
86
- `Create a profile using 'xano profile:create'`);
87
- }
88
- const profile = credentials.profiles[profileName];
89
- // Validate required fields
90
- if (!profile.instance_origin) {
91
- this.error(`Profile '${profileName}' is missing instance_origin`);
92
- }
93
- if (!profile.access_token) {
94
- this.error(`Profile '${profileName}' is missing access_token`);
95
- }
77
+ const { profile, profileName } = this.resolveProfile(flags);
96
78
  // Determine workspace_id from flag or profile
97
79
  let workspaceId;
98
80
  if (flags.workspace) {
@@ -182,25 +164,6 @@ function yo {
182
164
  }
183
165
  }
184
166
  }
185
- loadCredentials() {
186
- const credentialsPath = this.getCredentialsPath();
187
- // Check if credentials file exists
188
- if (!fs.existsSync(credentialsPath)) {
189
- this.error(`Credentials file not found at ${credentialsPath}\n` + `Create a profile using 'xano profile:create'`);
190
- }
191
- // Read credentials file
192
- try {
193
- const fileContent = fs.readFileSync(credentialsPath, 'utf8');
194
- const parsed = yaml.load(fileContent);
195
- if (!parsed || typeof parsed !== 'object' || !('profiles' in parsed)) {
196
- this.error('Credentials file has invalid format.');
197
- }
198
- return parsed;
199
- }
200
- catch (error) {
201
- this.error(`Failed to parse credentials file: ${error}`);
202
- }
203
- }
204
167
  async promptForFunctionId(profile, workspaceId) {
205
168
  try {
206
169
  // Fetch list of functions
@@ -17,5 +17,4 @@ export default class FunctionList extends BaseCommand {
17
17
  verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
18
18
  };
19
19
  run(): Promise<void>;
20
- private loadCredentials;
21
20
  }
@@ -1,6 +1,4 @@
1
1
  import { Flags } from '@oclif/core';
2
- import * as yaml from 'js-yaml';
3
- import * as fs from 'node:fs';
4
2
  import BaseCommand from '../../../base-command.js';
5
3
  export default class FunctionList extends BaseCommand {
6
4
  static args = {};
@@ -82,23 +80,7 @@ Available functions:
82
80
  };
83
81
  async run() {
84
82
  const { flags } = await this.parse(FunctionList);
85
- // Get profile name (default or from flag/env)
86
- const profileName = flags.profile || this.getDefaultProfile();
87
- // Load credentials
88
- const credentials = this.loadCredentials();
89
- // Get the profile configuration
90
- if (!(profileName in credentials.profiles)) {
91
- this.error(`Profile '${profileName}' not found. Available profiles: ${Object.keys(credentials.profiles).join(', ')}\n` +
92
- `Create a profile using 'xano profile:create'`);
93
- }
94
- const profile = credentials.profiles[profileName];
95
- // Validate required fields
96
- if (!profile.instance_origin) {
97
- this.error(`Profile '${profileName}' is missing instance_origin`);
98
- }
99
- if (!profile.access_token) {
100
- this.error(`Profile '${profileName}' is missing access_token`);
101
- }
83
+ const { profile, profileName } = this.resolveProfile(flags);
102
84
  // Determine workspace_id from flag or profile
103
85
  let workspaceId;
104
86
  if (flags.workspace) {
@@ -182,24 +164,4 @@ Available functions:
182
164
  }
183
165
  }
184
166
  }
185
- loadCredentials() {
186
- const credentialsPath = this.getCredentialsPath();
187
- // Check if credentials file exists
188
- if (!fs.existsSync(credentialsPath)) {
189
- this.error(`Credentials file not found at ${credentialsPath}\n` +
190
- `Create a profile using 'xano profile:create'`);
191
- }
192
- // Read credentials file
193
- try {
194
- const fileContent = fs.readFileSync(credentialsPath, 'utf8');
195
- const parsed = yaml.load(fileContent);
196
- if (!parsed || typeof parsed !== 'object' || !('profiles' in parsed)) {
197
- this.error('Credentials file has invalid format.');
198
- }
199
- return parsed;
200
- }
201
- catch (error) {
202
- this.error(`Failed to parse credentials file: ${error}`);
203
- }
204
- }
205
167
  }
@@ -15,5 +15,4 @@ export default class PlatformGet extends BaseCommand {
15
15
  verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
16
16
  };
17
17
  run(): Promise<void>;
18
- private loadCredentials;
19
18
  }
@@ -1,6 +1,4 @@
1
1
  import { Args, Flags } from '@oclif/core';
2
- import * as yaml from 'js-yaml';
3
- import * as fs from 'node:fs';
4
2
  import BaseCommand from '../../../base-command.js';
5
3
  export default class PlatformGet extends BaseCommand {
6
4
  static args = {
@@ -43,19 +41,7 @@ Platform ID: 23629
43
41
  };
44
42
  async run() {
45
43
  const { args, flags } = await this.parse(PlatformGet);
46
- const profileName = flags.profile || this.getDefaultProfile();
47
- const credentials = this.loadCredentials();
48
- if (!(profileName in credentials.profiles)) {
49
- this.error(`Profile '${profileName}' not found. Available profiles: ${Object.keys(credentials.profiles).join(', ')}\n` +
50
- `Create a profile using 'xano profile create'`);
51
- }
52
- const profile = credentials.profiles[profileName];
53
- if (!profile.instance_origin) {
54
- this.error(`Profile '${profileName}' is missing instance_origin`);
55
- }
56
- if (!profile.access_token) {
57
- this.error(`Profile '${profileName}' is missing access_token`);
58
- }
44
+ const { profile } = this.resolveProfile(flags);
59
45
  const platformId = args.platform_id;
60
46
  const apiUrl = `${profile.instance_origin}/api:meta/platform/${platformId}`;
61
47
  try {
@@ -102,22 +88,4 @@ Platform ID: 23629
102
88
  }
103
89
  }
104
90
  }
105
- loadCredentials() {
106
- const credentialsPath = this.getCredentialsPath();
107
- if (!fs.existsSync(credentialsPath)) {
108
- this.error(`Credentials file not found at ${credentialsPath}\n` +
109
- `Create a profile using 'xano profile create'`);
110
- }
111
- try {
112
- const fileContent = fs.readFileSync(credentialsPath, 'utf8');
113
- const parsed = yaml.load(fileContent);
114
- if (!parsed || typeof parsed !== 'object' || !('profiles' in parsed)) {
115
- this.error('Credentials file has invalid format.');
116
- }
117
- return parsed;
118
- }
119
- catch (error) {
120
- this.error(`Failed to parse credentials file: ${error}`);
121
- }
122
- }
123
91
  }
@@ -9,5 +9,4 @@ export default class PlatformList extends BaseCommand {
9
9
  verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
10
10
  };
11
11
  run(): Promise<void>;
12
- private loadCredentials;
13
12
  }
@@ -1,6 +1,4 @@
1
1
  import { Flags } from '@oclif/core';
2
- import * as yaml from 'js-yaml';
3
- import * as fs from 'node:fs';
4
2
  import BaseCommand from '../../../base-command.js';
5
3
  export default class PlatformList extends BaseCommand {
6
4
  static description = 'List all platforms';
@@ -23,19 +21,7 @@ Platforms:
23
21
  };
24
22
  async run() {
25
23
  const { flags } = await this.parse(PlatformList);
26
- const profileName = flags.profile || this.getDefaultProfile();
27
- const credentials = this.loadCredentials();
28
- if (!(profileName in credentials.profiles)) {
29
- this.error(`Profile '${profileName}' not found. Available profiles: ${Object.keys(credentials.profiles).join(', ')}\n` +
30
- `Create a profile using 'xano profile create'`);
31
- }
32
- const profile = credentials.profiles[profileName];
33
- if (!profile.instance_origin) {
34
- this.error(`Profile '${profileName}' is missing instance_origin`);
35
- }
36
- if (!profile.access_token) {
37
- this.error(`Profile '${profileName}' is missing access_token`);
38
- }
24
+ const { profile } = this.resolveProfile(flags);
39
25
  const apiUrl = `${profile.instance_origin}/api:meta/platform`;
40
26
  try {
41
27
  const response = await this.verboseFetch(apiUrl, {
@@ -89,22 +75,4 @@ Platforms:
89
75
  }
90
76
  }
91
77
  }
92
- loadCredentials() {
93
- const credentialsPath = this.getCredentialsPath();
94
- if (!fs.existsSync(credentialsPath)) {
95
- this.error(`Credentials file not found at ${credentialsPath}\n` +
96
- `Create a profile using 'xano profile create'`);
97
- }
98
- try {
99
- const fileContent = fs.readFileSync(credentialsPath, 'utf8');
100
- const parsed = yaml.load(fileContent);
101
- if (!parsed || typeof parsed !== 'object' || !('profiles' in parsed)) {
102
- this.error('Credentials file has invalid format.');
103
- }
104
- return parsed;
105
- }
106
- catch (error) {
107
- this.error(`Failed to parse credentials file: ${error}`);
108
- }
109
- }
110
78
  }
@@ -0,0 +1,33 @@
1
+ import { Command } from '@oclif/core';
2
+ import { type LocalProfileConfig } from '../../../utils/local-config.js';
3
+ /**
4
+ * Ensure `entry` exists as its own line in a .gitignore.
5
+ * Returns the (possibly unchanged) content and whether a write is needed.
6
+ */
7
+ export declare function ensureGitignoreEntry(existing: null | string, entry: string): {
8
+ changed: boolean;
9
+ content: string;
10
+ };
11
+ /**
12
+ * Build a self-documenting profile.yaml string from a LocalProfileConfig.
13
+ * Set fields are emitted uncommented; unset fields appear as commented placeholders.
14
+ */
15
+ export declare function buildProfileYaml(config: LocalProfileConfig): string;
16
+ export default class ProfileUse extends Command {
17
+ static args: {
18
+ name: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
19
+ };
20
+ static description: string;
21
+ static examples: string[];
22
+ static flags: {
23
+ account_origin: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
24
+ branch: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
25
+ config: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
26
+ gitignore: import("@oclif/core/interfaces").BooleanFlag<boolean>;
27
+ instance_origin: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
28
+ workspace: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
29
+ };
30
+ run(): Promise<void>;
31
+ private assertProfileExists;
32
+ private handleGitignore;
33
+ }
@@ -0,0 +1,179 @@
1
+ import { Args, Command, Flags } from '@oclif/core';
2
+ import inquirer from 'inquirer';
3
+ import * as yaml from 'js-yaml';
4
+ import * as fs from 'node:fs';
5
+ import { resolve } from 'node:path';
6
+ import { resolveCredentialsPath } from '../../../base-command.js';
7
+ import { LOCAL_PROFILE_FILENAME } from '../../../utils/local-config.js';
8
+ /**
9
+ * Ensure `entry` exists as its own line in a .gitignore.
10
+ * Returns the (possibly unchanged) content and whether a write is needed.
11
+ */
12
+ export function ensureGitignoreEntry(existing, entry) {
13
+ const lines = existing ? existing.split('\n').map((line) => line.trim()) : [];
14
+ if (lines.includes(entry)) {
15
+ return { changed: false, content: existing ?? '' };
16
+ }
17
+ const base = existing && !existing.endsWith('\n') ? existing + '\n' : existing ?? '';
18
+ return { changed: true, content: `${base}${entry}\n` };
19
+ }
20
+ const OVERRIDE_FIELDS = [
21
+ { key: 'workspace', placeholder: '123' },
22
+ { key: 'instance_origin', placeholder: 'https://your-instance.xano.io' },
23
+ { key: 'account_origin', placeholder: 'https://app.xano.com' },
24
+ { key: 'branch', placeholder: 'main' },
25
+ ];
26
+ /**
27
+ * Build a self-documenting profile.yaml string from a LocalProfileConfig.
28
+ * Set fields are emitted uncommented; unset fields appear as commented placeholders.
29
+ */
30
+ export function buildProfileYaml(config) {
31
+ const lines = [
32
+ '# Xano project-local profile — pins this project to a profile in ~/.xano/credentials.yaml.',
33
+ '# No secrets here: the access token always comes from credentials.yaml.',
34
+ '# Precedence: an explicit -p/--profile or XANO_PROFILE overrides this file entirely.',
35
+ '',
36
+ '# Profile to use (a profile name from ~/.xano/credentials.yaml):',
37
+ `profile: ${config.profile}`,
38
+ '',
39
+ '# Optional per-project overrides — uncomment and edit any you need:',
40
+ ];
41
+ for (const { key, placeholder } of OVERRIDE_FIELDS) {
42
+ const value = config[key];
43
+ lines.push(value === undefined ? `# ${key}: ${placeholder}` : `${key}: ${value}`);
44
+ }
45
+ lines.push('');
46
+ return lines.join('\n');
47
+ }
48
+ export default class ProfileUse extends Command {
49
+ static args = {
50
+ name: Args.string({
51
+ description: 'Profile name (from credentials.yaml) to pin for this project',
52
+ required: true,
53
+ }),
54
+ };
55
+ static description = 'Pin a profile for the current project by writing a local profile.yaml. ' +
56
+ 'When present, the CLI uses this profile (and any overrides) instead of the default, ' +
57
+ 'unless -p/--profile or XANO_PROFILE is set.';
58
+ static examples = [
59
+ `$ xano profile use staging
60
+ Wrote profile.yaml pinning profile 'staging'
61
+ `,
62
+ `$ xano profile use staging -w 110
63
+ Wrote profile.yaml pinning profile 'staging' (workspace 110)
64
+ `,
65
+ `$ xano profile use staging -w 110 --gitignore
66
+ Wrote profile.yaml pinning profile 'staging' (workspace 110)
67
+ Added profile.yaml to .gitignore
68
+ `,
69
+ ];
70
+ static flags = {
71
+ // eslint-disable-next-line camelcase
72
+ account_origin: Flags.string({
73
+ char: 'a',
74
+ description: 'Override account origin for this project',
75
+ required: false,
76
+ }),
77
+ branch: Flags.string({
78
+ char: 'b',
79
+ description: 'Override branch for this project',
80
+ required: false,
81
+ }),
82
+ config: Flags.string({
83
+ char: 'c',
84
+ description: 'Path to credentials file (default: ~/.xano/credentials.yaml)',
85
+ env: 'XANO_CONFIG',
86
+ required: false,
87
+ }),
88
+ gitignore: Flags.boolean({
89
+ allowNo: true,
90
+ description: 'Add (or skip adding) profile.yaml to .gitignore without prompting',
91
+ required: false,
92
+ }),
93
+ // eslint-disable-next-line camelcase
94
+ instance_origin: Flags.string({
95
+ char: 'i',
96
+ description: 'Override instance origin for this project',
97
+ required: false,
98
+ }),
99
+ workspace: Flags.string({
100
+ char: 'w',
101
+ description: 'Override workspace for this project',
102
+ required: false,
103
+ }),
104
+ };
105
+ async run() {
106
+ const { args, flags } = await this.parse(ProfileUse);
107
+ this.assertProfileExists(args.name, flags.config);
108
+ const config = { profile: args.name };
109
+ if (flags.workspace)
110
+ config.workspace = flags.workspace;
111
+ // eslint-disable-next-line camelcase
112
+ if (flags.instance_origin)
113
+ config.instance_origin = flags.instance_origin;
114
+ // eslint-disable-next-line camelcase
115
+ if (flags.account_origin)
116
+ config.account_origin = flags.account_origin;
117
+ if (flags.branch)
118
+ config.branch = flags.branch;
119
+ const filePath = resolve(process.cwd(), LOCAL_PROFILE_FILENAME);
120
+ if (fs.existsSync(filePath)) {
121
+ this.warn(`Overwriting existing ${LOCAL_PROFILE_FILENAME}`);
122
+ }
123
+ try {
124
+ fs.writeFileSync(filePath, buildProfileYaml(config), 'utf8');
125
+ }
126
+ catch (error) {
127
+ this.error(`Failed to write ${LOCAL_PROFILE_FILENAME}: ${error}`);
128
+ }
129
+ const workspaceNote = flags.workspace ? ` (workspace ${flags.workspace})` : '';
130
+ this.log(`Wrote ${LOCAL_PROFILE_FILENAME} pinning profile '${args.name}'${workspaceNote}`);
131
+ await this.handleGitignore(flags.gitignore);
132
+ }
133
+ assertProfileExists(name, configPath) {
134
+ const credentialsPath = resolveCredentialsPath(configPath);
135
+ if (!fs.existsSync(credentialsPath)) {
136
+ this.error(`Credentials file not found at ${credentialsPath}. Create a profile first using 'xano auth'.`);
137
+ }
138
+ let parsed;
139
+ try {
140
+ parsed = yaml.load(fs.readFileSync(credentialsPath, 'utf8'));
141
+ }
142
+ catch (error) {
143
+ this.error(`Failed to parse credentials file: ${error}`);
144
+ }
145
+ if (!parsed || typeof parsed !== 'object' || !('profiles' in parsed)) {
146
+ this.error('Credentials file has invalid format.');
147
+ }
148
+ if (!(name in parsed.profiles)) {
149
+ this.error(`Profile '${name}' not found. Available profiles: ${Object.keys(parsed.profiles).join(', ')}`);
150
+ }
151
+ }
152
+ async handleGitignore(flag) {
153
+ const gitignorePath = resolve(process.cwd(), '.gitignore');
154
+ const existing = fs.existsSync(gitignorePath) ? fs.readFileSync(gitignorePath, 'utf8') : null;
155
+ // If profile.yaml is already in .gitignore, no action needed regardless of flag.
156
+ const alreadyIgnored = !ensureGitignoreEntry(existing, LOCAL_PROFILE_FILENAME).changed;
157
+ if (alreadyIgnored) {
158
+ return;
159
+ }
160
+ let shouldAdd = flag;
161
+ if (shouldAdd === undefined) {
162
+ const { add } = await inquirer.prompt([
163
+ {
164
+ default: false,
165
+ message: `Add ${LOCAL_PROFILE_FILENAME} to .gitignore?`,
166
+ name: 'add',
167
+ type: 'confirm',
168
+ },
169
+ ]);
170
+ shouldAdd = add;
171
+ }
172
+ if (!shouldAdd) {
173
+ return;
174
+ }
175
+ const { content } = ensureGitignoreEntry(existing, LOCAL_PROFILE_FILENAME);
176
+ fs.writeFileSync(gitignorePath, content, 'utf8');
177
+ this.log(`Added ${LOCAL_PROFILE_FILENAME} to .gitignore`);
178
+ }
179
+ }
@@ -17,5 +17,4 @@ export default class ReleaseCreate extends BaseCommand {
17
17
  verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
18
18
  };
19
19
  run(): Promise<void>;
20
- private loadCredentials;
21
20
  }