@xano/cli 0.0.64 → 0.0.66

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 (32) hide show
  1. package/README.md +25 -0
  2. package/dist/base-command.d.ts +25 -0
  3. package/dist/base-command.js +53 -11
  4. package/dist/commands/auth/index.d.ts +2 -0
  5. package/dist/commands/auth/index.js +23 -16
  6. package/dist/commands/function/edit/index.js +17 -18
  7. package/dist/commands/function/get/index.js +11 -11
  8. package/dist/commands/profile/create/index.d.ts +1 -0
  9. package/dist/commands/profile/create/index.js +10 -0
  10. package/dist/commands/profile/edit/index.d.ts +2 -0
  11. package/dist/commands/profile/edit/index.js +23 -1
  12. package/dist/commands/profile/list/index.js +3 -0
  13. package/dist/commands/profile/wizard/index.d.ts +2 -0
  14. package/dist/commands/profile/wizard/index.js +23 -12
  15. package/dist/commands/release/export/index.js +14 -13
  16. package/dist/commands/release/pull/index.d.ts +0 -6
  17. package/dist/commands/release/pull/index.js +15 -62
  18. package/dist/commands/release/push/index.js +16 -6
  19. package/dist/commands/tenant/backup/export/index.js +4 -2
  20. package/dist/commands/tenant/create/index.js +3 -0
  21. package/dist/commands/tenant/deploy_platform/index.js +1 -0
  22. package/dist/commands/tenant/deploy_release/index.js +1 -0
  23. package/dist/commands/tenant/pull/index.d.ts +0 -6
  24. package/dist/commands/tenant/pull/index.js +9 -56
  25. package/dist/commands/tenant/push/index.js +16 -6
  26. package/dist/commands/workspace/git/pull/index.js +9 -8
  27. package/dist/commands/workspace/pull/index.js +9 -6
  28. package/dist/commands/workspace/push/index.js +10 -1
  29. package/dist/utils/document-parser.d.ts +22 -0
  30. package/dist/utils/document-parser.js +54 -1
  31. package/oclif.manifest.json +992 -952
  32. package/package.json +1 -1
package/README.md CHANGED
@@ -36,6 +36,7 @@ npm install -g @xano/cli
36
36
  # Interactive browser-based authentication
37
37
  xano auth
38
38
  xano auth --origin https://custom.xano.com
39
+ xano auth --insecure # Skip TLS verification (self-signed certs)
39
40
  ```
40
41
 
41
42
  ### Profiles
@@ -48,6 +49,7 @@ xano profile wizard
48
49
 
49
50
  # Create a profile manually
50
51
  xano profile create myprofile -i https://instance.xano.com -t <access_token>
52
+ xano profile create myprofile -i https://self-signed.example.com -t <token> --insecure
51
53
 
52
54
  # List profiles
53
55
  xano profile list
@@ -59,6 +61,8 @@ xano profile set myprofile
59
61
 
60
62
  # Edit a profile
61
63
  xano profile edit myprofile -w 123
64
+ xano profile edit myprofile --insecure # Enable insecure mode (self-signed certs)
65
+ xano profile edit myprofile --remove-insecure # Disable insecure mode
62
66
  xano profile edit myprofile --remove-branch # Remove branch from profile
63
67
 
64
68
  # Get current user info
@@ -467,9 +471,30 @@ profiles:
467
471
  access_token: <token>
468
472
  workspace: <workspace_id>
469
473
  branch: <branch_id>
474
+ self-hosted:
475
+ instance_origin: https://self-signed.example.com
476
+ access_token: <token>
477
+ insecure: true
470
478
  default: default
471
479
  ```
472
480
 
481
+ ### Self-Signed Certificates
482
+
483
+ For environments using self-signed TLS certificates, use the `--insecure` (`-k`) flag to skip certificate verification:
484
+
485
+ ```bash
486
+ # During authentication
487
+ xano auth --insecure
488
+
489
+ # When creating a profile
490
+ xano profile create myprofile -i https://self-signed.example.com -t <token> -k
491
+
492
+ # Add to an existing profile
493
+ xano profile edit myprofile --insecure
494
+ ```
495
+
496
+ When a profile has `insecure: true`, all commands using that profile will automatically skip TLS certificate verification. A warning is displayed when insecure mode is active.
497
+
473
498
  ### Update
474
499
 
475
500
  ```bash
@@ -1,4 +1,19 @@
1
1
  import { Command } from '@oclif/core';
2
+ export interface ProfileConfig {
3
+ access_token: string;
4
+ account_origin?: string;
5
+ branch?: string;
6
+ insecure?: boolean;
7
+ instance_origin: string;
8
+ workspace?: string;
9
+ }
10
+ export interface CredentialsFile {
11
+ default?: string;
12
+ profiles: {
13
+ [key: string]: ProfileConfig;
14
+ };
15
+ }
16
+ export declare function buildUserAgent(version: string): string;
2
17
  export default abstract class BaseCommand extends Command {
3
18
  static baseFlags: {
4
19
  profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
@@ -8,8 +23,18 @@ export default abstract class BaseCommand extends Command {
8
23
  profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
9
24
  verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
10
25
  };
26
+ init(): Promise<void>;
27
+ /**
28
+ * Apply insecure TLS mode if the active profile has insecure: true.
29
+ * Sets NODE_TLS_REJECT_UNAUTHORIZED=0 so all fetch() calls skip cert verification.
30
+ */
31
+ protected applyInsecureFromProfile(): void;
11
32
  protected getDefaultProfile(): string;
12
33
  protected getProfile(): string | undefined;
34
+ /**
35
+ * Load and parse the credentials file. Returns null if the file doesn't exist.
36
+ */
37
+ protected loadCredentialsFile(): CredentialsFile | null;
13
38
  /**
14
39
  * Make an HTTP request with optional verbose logging.
15
40
  * Use this for all Metadata API calls to support the --verbose flag.
@@ -3,6 +3,9 @@ import * as yaml from 'js-yaml';
3
3
  import * as fs from 'node:fs';
4
4
  import * as os from 'node:os';
5
5
  import * as path from 'node:path';
6
+ export function buildUserAgent(version) {
7
+ return `xano-cli/${version} (${process.platform}; ${process.arch}) node/${process.version}`;
8
+ }
6
9
  export default class BaseCommand extends Command {
7
10
  static baseFlags = {
8
11
  profile: Flags.string({
@@ -21,18 +24,36 @@ export default class BaseCommand extends Command {
21
24
  };
22
25
  // Override the flags property to include baseFlags
23
26
  static flags = BaseCommand.baseFlags;
27
+ async init() {
28
+ await super.init();
29
+ this.applyInsecureFromProfile();
30
+ }
31
+ /**
32
+ * Apply insecure TLS mode if the active profile has insecure: true.
33
+ * Sets NODE_TLS_REJECT_UNAUTHORIZED=0 so all fetch() calls skip cert verification.
34
+ */
35
+ applyInsecureFromProfile() {
36
+ try {
37
+ const profileName = this.flags?.profile || this.getDefaultProfile();
38
+ const credentials = this.loadCredentialsFile();
39
+ if (!credentials)
40
+ return;
41
+ const profile = credentials.profiles[profileName];
42
+ if (profile?.insecure) {
43
+ process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
44
+ this.warn('TLS certificate verification is disabled for this profile (insecure mode)');
45
+ }
46
+ }
47
+ catch {
48
+ // Don't fail the command if we can't read the profile for insecure check
49
+ }
50
+ }
24
51
  // Helper method to get the default profile from credentials file
25
52
  getDefaultProfile() {
26
53
  try {
27
- const configDir = path.join(os.homedir(), '.xano');
28
- const credentialsPath = path.join(configDir, 'credentials.yaml');
29
- if (!fs.existsSync(credentialsPath)) {
30
- return 'default';
31
- }
32
- const fileContent = fs.readFileSync(credentialsPath, 'utf8');
33
- const parsed = yaml.load(fileContent);
34
- if (parsed && typeof parsed === 'object' && 'default' in parsed && parsed.default) {
35
- return parsed.default;
54
+ const credentials = this.loadCredentialsFile();
55
+ if (credentials?.default) {
56
+ return credentials.default;
36
57
  }
37
58
  return 'default';
38
59
  }
@@ -44,13 +65,34 @@ export default class BaseCommand extends Command {
44
65
  getProfile() {
45
66
  return this.flags?.profile;
46
67
  }
68
+ /**
69
+ * Load and parse the credentials file. Returns null if the file doesn't exist.
70
+ */
71
+ loadCredentialsFile() {
72
+ const configDir = path.join(os.homedir(), '.xano');
73
+ const credentialsPath = path.join(configDir, 'credentials.yaml');
74
+ if (!fs.existsSync(credentialsPath)) {
75
+ return null;
76
+ }
77
+ const fileContent = fs.readFileSync(credentialsPath, 'utf8');
78
+ const parsed = yaml.load(fileContent);
79
+ if (parsed && typeof parsed === 'object' && 'profiles' in parsed) {
80
+ return parsed;
81
+ }
82
+ return null;
83
+ }
47
84
  /**
48
85
  * Make an HTTP request with optional verbose logging.
49
86
  * Use this for all Metadata API calls to support the --verbose flag.
50
87
  */
51
88
  async verboseFetch(url, options, verbose, authToken) {
52
89
  const method = options.method || 'GET';
53
- const contentType = options.headers?.['Content-Type'] || 'application/json';
90
+ const headers = {
91
+ 'User-Agent': buildUserAgent(this.config.version),
92
+ ...options.headers,
93
+ };
94
+ const fetchOptions = { ...options, headers };
95
+ const contentType = headers['Content-Type'] || 'application/json';
54
96
  if (verbose) {
55
97
  this.log('');
56
98
  this.log('─'.repeat(60));
@@ -66,7 +108,7 @@ export default class BaseCommand extends Command {
66
108
  }
67
109
  }
68
110
  const startTime = Date.now();
69
- const response = await fetch(url, options);
111
+ const response = await fetch(url, fetchOptions);
70
112
  const elapsed = Date.now() - startTime;
71
113
  if (verbose) {
72
114
  this.log(`← ${response.status} ${response.statusText} (${elapsed}ms)`);
@@ -3,9 +3,11 @@ export default class Auth extends Command {
3
3
  static description: string;
4
4
  static examples: string[];
5
5
  static flags: {
6
+ insecure: import("@oclif/core/interfaces").BooleanFlag<boolean>;
6
7
  origin: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
7
8
  };
8
9
  run(): Promise<void>;
10
+ private getHeaders;
9
11
  private fetchBranches;
10
12
  private fetchInstances;
11
13
  private fetchWorkspaces;
@@ -7,6 +7,7 @@ import * as http from 'node:http';
7
7
  import * as os from 'node:os';
8
8
  import { join } from 'node:path';
9
9
  import open from 'open';
10
+ import { buildUserAgent } from '../../base-command.js';
10
11
  const AUTH_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes
11
12
  export default class Auth extends Command {
12
13
  static description = 'Authenticate with Xano via browser login';
@@ -22,6 +23,11 @@ Profile 'default' created successfully!`,
22
23
  Opening browser for Xano login at https://custom.xano.com...`,
23
24
  ];
24
25
  static flags = {
26
+ insecure: Flags.boolean({
27
+ char: 'k',
28
+ default: false,
29
+ description: 'Skip TLS certificate verification (for self-signed certificates)',
30
+ }),
25
31
  origin: Flags.string({
26
32
  char: 'o',
27
33
  default: 'https://app.xano.com',
@@ -30,6 +36,10 @@ Opening browser for Xano login at https://custom.xano.com...`,
30
36
  };
31
37
  async run() {
32
38
  const { flags } = await this.parse(Auth);
39
+ if (flags.insecure) {
40
+ process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
41
+ this.warn('TLS certificate verification is disabled (insecure mode)');
42
+ }
33
43
  try {
34
44
  // Step 1: Get token via browser auth
35
45
  this.log('Starting authentication flow...');
@@ -73,6 +83,7 @@ Opening browser for Xano login at https://custom.xano.com...`,
73
83
  access_token: token,
74
84
  account_origin: flags.origin,
75
85
  branch,
86
+ ...(flags.insecure && { insecure: true }),
76
87
  instance_origin: instance.origin,
77
88
  name: profileName,
78
89
  workspace: workspace?.id,
@@ -90,13 +101,17 @@ Opening browser for Xano login at https://custom.xano.com...`,
90
101
  throw error;
91
102
  }
92
103
  }
104
+ getHeaders(accessToken) {
105
+ return {
106
+ 'User-Agent': buildUserAgent(this.config.version),
107
+ accept: 'application/json',
108
+ ...(accessToken && { Authorization: `Bearer ${accessToken}` }),
109
+ };
110
+ }
93
111
  async fetchBranches(accessToken, origin, workspaceId) {
94
112
  try {
95
113
  const response = await fetch(`${origin}/api:meta/workspace/${workspaceId}/branch`, {
96
- headers: {
97
- accept: 'application/json',
98
- Authorization: `Bearer ${accessToken}`,
99
- },
114
+ headers: this.getHeaders(accessToken),
100
115
  method: 'GET',
101
116
  });
102
117
  if (!response.ok) {
@@ -117,10 +132,7 @@ Opening browser for Xano login at https://custom.xano.com...`,
117
132
  }
118
133
  async fetchInstances(accessToken, origin) {
119
134
  const response = await fetch(`${origin}/api:meta/instance`, {
120
- headers: {
121
- accept: 'application/json',
122
- Authorization: `Bearer ${accessToken}`,
123
- },
135
+ headers: this.getHeaders(accessToken),
124
136
  method: 'GET',
125
137
  });
126
138
  if (!response.ok) {
@@ -143,10 +155,7 @@ Opening browser for Xano login at https://custom.xano.com...`,
143
155
  async fetchWorkspaces(accessToken, origin) {
144
156
  try {
145
157
  const response = await fetch(`${origin}/api:meta/workspace`, {
146
- headers: {
147
- accept: 'application/json',
148
- Authorization: `Bearer ${accessToken}`,
149
- },
158
+ headers: this.getHeaders(accessToken),
150
159
  method: 'GET',
151
160
  });
152
161
  if (!response.ok) {
@@ -211,6 +220,7 @@ Opening browser for Xano login at https://custom.xano.com...`,
211
220
  instance_origin: profile.instance_origin,
212
221
  ...(profile.workspace && { workspace: profile.workspace }),
213
222
  ...(profile.branch && { branch: profile.branch }),
223
+ ...(profile.insecure && { insecure: true }),
214
224
  };
215
225
  // Set as default profile
216
226
  credentials.default = profile.name;
@@ -464,10 +474,7 @@ Opening browser for Xano login at https://custom.xano.com...`,
464
474
  }
465
475
  async validateToken(token, origin) {
466
476
  const response = await fetch(`${origin}/api:meta/auth/me`, {
467
- headers: {
468
- accept: 'application/json',
469
- Authorization: `Bearer ${token}`,
470
- },
477
+ headers: this.getHeaders(token),
471
478
  method: 'GET',
472
479
  });
473
480
  if (!response.ok) {
@@ -5,7 +5,7 @@ import { execSync } from 'node:child_process';
5
5
  import * as fs from 'node:fs';
6
6
  import * as os from 'node:os';
7
7
  import * as path from 'node:path';
8
- import BaseCommand from '../../../base-command.js';
8
+ import BaseCommand, { buildUserAgent } from '../../../base-command.js';
9
9
  export default class FunctionEdit extends BaseCommand {
10
10
  static args = {
11
11
  function_id: Args.string({
@@ -138,7 +138,7 @@ Name: my_function
138
138
  }
139
139
  // If function_id is not provided, prompt user to select from list
140
140
  let functionId;
141
- functionId = args.function_id ? args.function_id : (await this.promptForFunctionId(profile, workspaceId));
141
+ functionId = args.function_id ? args.function_id : await this.promptForFunctionId(profile, workspaceId);
142
142
  // Read XanoScript content
143
143
  let xanoscript;
144
144
  if (flags.file) {
@@ -199,8 +199,8 @@ Name: my_function
199
199
  const response = await this.verboseFetch(apiUrl, {
200
200
  body: xanoscript,
201
201
  headers: {
202
- 'accept': 'application/json',
203
- 'Authorization': `Bearer ${profile.access_token}`,
202
+ accept: 'application/json',
203
+ Authorization: `Bearer ${profile.access_token}`,
204
204
  'Content-Type': 'text/x-xanoscript',
205
205
  },
206
206
  method: 'PUT',
@@ -209,7 +209,7 @@ Name: my_function
209
209
  const errorText = await response.text();
210
210
  this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
211
211
  }
212
- const result = await response.json();
212
+ const result = (await response.json());
213
213
  // Validate response
214
214
  if (!result || typeof result !== 'object') {
215
215
  this.error('Unexpected API response format');
@@ -238,16 +238,14 @@ Name: my_function
238
238
  // Get the EDITOR environment variable
239
239
  const editor = process.env.EDITOR || process.env.VISUAL;
240
240
  if (!editor) {
241
- this.error('No editor configured. Please set the EDITOR or VISUAL environment variable.\n' +
242
- 'Example: export EDITOR=vim');
241
+ this.error('No editor configured. Please set the EDITOR or VISUAL environment variable.\n' + 'Example: export EDITOR=vim');
243
242
  }
244
243
  // Validate editor executable exists
245
244
  try {
246
245
  execSync(`which ${editor.split(' ')[0]}`, { stdio: 'ignore' });
247
246
  }
248
247
  catch {
249
- this.error(`Editor '${editor}' not found. Please set EDITOR to a valid editor.\n` +
250
- 'Example: export EDITOR=vim');
248
+ this.error(`Editor '${editor}' not found. Please set EDITOR to a valid editor.\n` + 'Example: export EDITOR=vim');
251
249
  }
252
250
  // Read the original file
253
251
  let originalContent;
@@ -343,8 +341,9 @@ Name: my_function
343
341
  try {
344
342
  const response = await fetch(apiUrl, {
345
343
  headers: {
346
- 'accept': 'application/json',
347
- 'Authorization': `Bearer ${profile.access_token}`,
344
+ 'User-Agent': buildUserAgent(this.config.version),
345
+ accept: 'application/json',
346
+ Authorization: `Bearer ${profile.access_token}`,
348
347
  },
349
348
  method: 'GET',
350
349
  });
@@ -352,7 +351,7 @@ Name: my_function
352
351
  const errorText = await response.text();
353
352
  throw new Error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
354
353
  }
355
- const result = await response.json();
354
+ const result = (await response.json());
356
355
  // Handle xanoscript as an object with status and value
357
356
  if (result.xanoscript) {
358
357
  if (result.xanoscript.status === 'ok' && result.xanoscript.value !== undefined) {
@@ -374,8 +373,7 @@ Name: my_function
374
373
  const credentialsPath = path.join(configDir, 'credentials.yaml');
375
374
  // Check if credentials file exists
376
375
  if (!fs.existsSync(credentialsPath)) {
377
- this.error(`Credentials file not found at ${credentialsPath}\n` +
378
- `Create a profile using 'xano profile:create'`);
376
+ this.error(`Credentials file not found at ${credentialsPath}\n` + `Create a profile using 'xano profile:create'`);
379
377
  }
380
378
  // Read credentials file
381
379
  try {
@@ -404,8 +402,9 @@ Name: my_function
404
402
  const listUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}/function?${queryParams.toString()}`;
405
403
  const response = await fetch(listUrl, {
406
404
  headers: {
407
- 'accept': 'application/json',
408
- 'Authorization': `Bearer ${profile.access_token}`,
405
+ 'User-Agent': buildUserAgent(this.config.version),
406
+ accept: 'application/json',
407
+ Authorization: `Bearer ${profile.access_token}`,
409
408
  },
410
409
  method: 'GET',
411
410
  });
@@ -413,7 +412,7 @@ Name: my_function
413
412
  const errorText = await response.text();
414
413
  this.error(`Failed to fetch function list: ${response.status} ${response.statusText}\n${errorText}`);
415
414
  }
416
- const data = await response.json();
415
+ const data = (await response.json());
417
416
  // Handle different response formats
418
417
  let functions;
419
418
  if (Array.isArray(data)) {
@@ -432,7 +431,7 @@ Name: my_function
432
431
  this.error('No functions found in workspace');
433
432
  }
434
433
  // Create choices for inquirer
435
- const choices = functions.map(func => ({
434
+ const choices = functions.map((func) => ({
436
435
  name: `${func.name} (ID: ${func.id})${func.description ? ` - ${func.description}` : ''}`,
437
436
  value: func.id.toString(),
438
437
  }));
@@ -4,7 +4,7 @@ import * as yaml from 'js-yaml';
4
4
  import * as fs from 'node:fs';
5
5
  import * as os from 'node:os';
6
6
  import * as path from 'node:path';
7
- import BaseCommand from '../../../base-command.js';
7
+ import BaseCommand, { buildUserAgent } from '../../../base-command.js';
8
8
  export default class FunctionGet extends BaseCommand {
9
9
  static args = {
10
10
  function_id: Args.string({
@@ -110,7 +110,7 @@ function yo {
110
110
  }
111
111
  // If function_id is not provided, prompt user to select from list
112
112
  let functionId;
113
- functionId = args.function_id ? args.function_id : (await this.promptForFunctionId(profile, workspaceId));
113
+ functionId = args.function_id ? args.function_id : await this.promptForFunctionId(profile, workspaceId);
114
114
  // Build query parameters
115
115
  // Automatically set include_xanoscript to true if output format is xs
116
116
  const includeXanoscript = flags.output === 'xs' ? true : flags.include_xanoscript;
@@ -124,8 +124,8 @@ function yo {
124
124
  try {
125
125
  const response = await this.verboseFetch(apiUrl, {
126
126
  headers: {
127
- 'accept': 'application/json',
128
- 'Authorization': `Bearer ${profile.access_token}`,
127
+ accept: 'application/json',
128
+ Authorization: `Bearer ${profile.access_token}`,
129
129
  },
130
130
  method: 'GET',
131
131
  }, flags.verbose, profile.access_token);
@@ -133,7 +133,7 @@ function yo {
133
133
  const errorText = await response.text();
134
134
  this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
135
135
  }
136
- const func = await response.json();
136
+ const func = (await response.json());
137
137
  // Validate response is an object
138
138
  if (!func || typeof func !== 'object') {
139
139
  this.error('Unexpected API response format: expected a function object');
@@ -189,8 +189,7 @@ function yo {
189
189
  const credentialsPath = path.join(configDir, 'credentials.yaml');
190
190
  // Check if credentials file exists
191
191
  if (!fs.existsSync(credentialsPath)) {
192
- this.error(`Credentials file not found at ${credentialsPath}\n` +
193
- `Create a profile using 'xano profile:create'`);
192
+ this.error(`Credentials file not found at ${credentialsPath}\n` + `Create a profile using 'xano profile:create'`);
194
193
  }
195
194
  // Read credentials file
196
195
  try {
@@ -219,8 +218,9 @@ function yo {
219
218
  const listUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}/function?${queryParams.toString()}`;
220
219
  const response = await fetch(listUrl, {
221
220
  headers: {
222
- 'accept': 'application/json',
223
- 'Authorization': `Bearer ${profile.access_token}`,
221
+ 'User-Agent': buildUserAgent(this.config.version),
222
+ accept: 'application/json',
223
+ Authorization: `Bearer ${profile.access_token}`,
224
224
  },
225
225
  method: 'GET',
226
226
  });
@@ -228,7 +228,7 @@ function yo {
228
228
  const errorText = await response.text();
229
229
  this.error(`Failed to fetch function list: ${response.status} ${response.statusText}\n${errorText}`);
230
230
  }
231
- const data = await response.json();
231
+ const data = (await response.json());
232
232
  // Handle different response formats
233
233
  let functions;
234
234
  if (Array.isArray(data)) {
@@ -247,7 +247,7 @@ function yo {
247
247
  this.error('No functions found in workspace');
248
248
  }
249
249
  // Create choices for inquirer
250
- const choices = functions.map(func => ({
250
+ const choices = functions.map((func) => ({
251
251
  name: `${func.name} (ID: ${func.id})${func.description ? ` - ${func.description}` : ''}`,
252
252
  value: func.id.toString(),
253
253
  }));
@@ -10,6 +10,7 @@ export default class ProfileCreate extends Command {
10
10
  account_origin: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
11
  branch: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
12
12
  default: import("@oclif/core/interfaces").BooleanFlag<boolean>;
13
+ insecure: import("@oclif/core/interfaces").BooleanFlag<boolean>;
13
14
  instance_origin: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
14
15
  workspace: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
15
16
  };
@@ -24,6 +24,9 @@ Profile 'dev' created successfully at ~/.xano/credentials.yaml
24
24
  `$ xano profile:create production --account_origin https://account.xano.com --instance_origin https://instance.xano.com --access_token token123 --default
25
25
  Profile 'production' created successfully at ~/.xano/credentials.yaml
26
26
  Default profile set to 'production'
27
+ `,
28
+ `$ xano profile:create selfhosted -i https://self-signed.example.com -t token123 --insecure
29
+ Profile 'selfhosted' created successfully at ~/.xano/credentials.yaml
27
30
  `,
28
31
  ];
29
32
  static flags = {
@@ -47,6 +50,12 @@ Default profile set to 'production'
47
50
  description: 'Set this profile as the default',
48
51
  required: false,
49
52
  }),
53
+ insecure: Flags.boolean({
54
+ char: 'k',
55
+ default: false,
56
+ description: 'Skip TLS certificate verification (for self-signed certificates)',
57
+ required: false,
58
+ }),
50
59
  instance_origin: Flags.string({
51
60
  char: 'i',
52
61
  description: 'Instance origin URL',
@@ -93,6 +102,7 @@ Default profile set to 'production'
93
102
  instance_origin: flags.instance_origin,
94
103
  ...(flags.workspace && { workspace: flags.workspace }),
95
104
  ...(flags.branch && { branch: flags.branch }),
105
+ ...(flags.insecure && { insecure: true }),
96
106
  };
97
107
  // Set default if flag is provided
98
108
  if (flags.default) {
@@ -9,8 +9,10 @@ export default class ProfileEdit extends BaseCommand {
9
9
  access_token: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
10
  account_origin: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
11
  branch: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
12
+ insecure: import("@oclif/core/interfaces").BooleanFlag<boolean>;
12
13
  instance_origin: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
13
14
  'remove-branch': import("@oclif/core/interfaces").BooleanFlag<boolean>;
15
+ 'remove-insecure': import("@oclif/core/interfaces").BooleanFlag<boolean>;
14
16
  'remove-workspace': import("@oclif/core/interfaces").BooleanFlag<boolean>;
15
17
  workspace: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
16
18
  profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
@@ -27,6 +27,12 @@ Profile 'default' updated successfully at ~/.xano/credentials.yaml
27
27
  `,
28
28
  `$ xano profile:edit --remove-branch
29
29
  Profile 'default' updated successfully at ~/.xano/credentials.yaml
30
+ `,
31
+ `$ xano profile:edit --insecure
32
+ Profile 'default' updated successfully at ~/.xano/credentials.yaml
33
+ `,
34
+ `$ xano profile:edit --remove-insecure
35
+ Profile 'default' updated successfully at ~/.xano/credentials.yaml
30
36
  `,
31
37
  ];
32
38
  static flags = {
@@ -46,6 +52,11 @@ Profile 'default' updated successfully at ~/.xano/credentials.yaml
46
52
  description: 'Update branch name',
47
53
  required: false,
48
54
  }),
55
+ insecure: Flags.boolean({
56
+ default: false,
57
+ description: 'Enable insecure mode (skip TLS certificate verification)',
58
+ required: false,
59
+ }),
49
60
  instance_origin: Flags.string({
50
61
  char: 'i',
51
62
  description: 'Update instance origin URL',
@@ -56,6 +67,11 @@ Profile 'default' updated successfully at ~/.xano/credentials.yaml
56
67
  description: 'Remove branch from profile',
57
68
  required: false,
58
69
  }),
70
+ 'remove-insecure': Flags.boolean({
71
+ default: false,
72
+ description: 'Remove insecure mode from profile',
73
+ required: false,
74
+ }),
59
75
  'remove-workspace': Flags.boolean({
60
76
  default: false,
61
77
  description: 'Remove workspace from profile',
@@ -102,8 +118,10 @@ Profile 'default' updated successfully at ~/.xano/credentials.yaml
102
118
  flags.access_token ||
103
119
  flags.workspace ||
104
120
  flags.branch ||
121
+ flags.insecure ||
105
122
  flags['remove-workspace'] ||
106
- flags['remove-branch'];
123
+ flags['remove-branch'] ||
124
+ flags['remove-insecure'];
107
125
  if (!hasFlags) {
108
126
  this.error('No fields specified to update. Use at least one flag to edit the profile.');
109
127
  }
@@ -115,6 +133,7 @@ Profile 'default' updated successfully at ~/.xano/credentials.yaml
115
133
  ...(flags.access_token !== undefined && { access_token: flags.access_token }),
116
134
  ...(flags.workspace !== undefined && { workspace: flags.workspace }),
117
135
  ...(flags.branch !== undefined && { branch: flags.branch }),
136
+ ...(flags.insecure && { insecure: true }),
118
137
  };
119
138
  // Handle removal flags
120
139
  if (flags['remove-workspace']) {
@@ -123,6 +142,9 @@ Profile 'default' updated successfully at ~/.xano/credentials.yaml
123
142
  if (flags['remove-branch']) {
124
143
  delete updatedProfile.branch;
125
144
  }
145
+ if (flags['remove-insecure']) {
146
+ delete updatedProfile.insecure;
147
+ }
126
148
  credentials.profiles[profileName] = updatedProfile;
127
149
  // Write the updated credentials back to the file
128
150
  try {
@@ -98,6 +98,9 @@ Profile: default
98
98
  if (profile.project) {
99
99
  this.log(` Project: ${profile.project}`);
100
100
  }
101
+ if (profile.insecure) {
102
+ this.log(` Insecure: true`);
103
+ }
101
104
  this.log(''); // Empty line between profiles
102
105
  }
103
106
  }
@@ -3,10 +3,12 @@ export default class ProfileWizard extends Command {
3
3
  static description: string;
4
4
  static examples: string[];
5
5
  static flags: {
6
+ insecure: import("@oclif/core/interfaces").BooleanFlag<boolean>;
6
7
  name: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
7
8
  origin: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
8
9
  };
9
10
  run(): Promise<void>;
11
+ private getHeaders;
10
12
  private fetchBranches;
11
13
  private fetchInstances;
12
14
  private fetchWorkspaces;