@xano/cli 0.0.65 → 0.0.67

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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
@@ -70,6 +74,10 @@ xano profile token
70
74
  # Print workspace ID (useful for piping)
71
75
  xano profile workspace
72
76
 
77
+ # Interactively change the workspace on a profile
78
+ xano profile workspace set
79
+ xano profile workspace set -p production
80
+
73
81
  # Delete a profile
74
82
  xano profile delete myprofile
75
83
  ```
@@ -467,9 +475,30 @@ profiles:
467
475
  access_token: <token>
468
476
  workspace: <workspace_id>
469
477
  branch: <branch_id>
478
+ self-hosted:
479
+ instance_origin: https://self-signed.example.com
480
+ access_token: <token>
481
+ insecure: true
470
482
  default: default
471
483
  ```
472
484
 
485
+ ### Self-Signed Certificates
486
+
487
+ For environments using self-signed TLS certificates, use the `--insecure` (`-k`) flag to skip certificate verification:
488
+
489
+ ```bash
490
+ # During authentication
491
+ xano auth --insecure
492
+
493
+ # When creating a profile
494
+ xano profile create myprofile -i https://self-signed.example.com -t <token> -k
495
+
496
+ # Add to an existing profile
497
+ xano profile edit myprofile --insecure
498
+ ```
499
+
500
+ 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.
501
+
473
502
  ### Update
474
503
 
475
504
  ```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,23 +36,42 @@ 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...');
36
46
  const token = await this.startAuthServer(flags.origin);
47
+ this.log(`Received token: ${token}`);
37
48
  // Step 2: Validate token and get user info
38
49
  this.log('');
39
50
  this.log('Validating authentication...');
40
51
  const user = await this.validateToken(token, flags.origin);
41
52
  this.log(`Authenticated as ${user.name} (${user.email})`);
42
53
  // Step 3: Fetch and select instance
43
- this.log('');
44
- this.log('Fetching available instances...');
45
- const instances = await this.fetchInstances(token, flags.origin);
46
- if (instances.length === 0) {
47
- this.error('No instances found. Please check your account.');
54
+ // Self-hosted instances (non-default origin) don't have /api:meta/instance
55
+ // The origin itself IS the instance
56
+ const isSelfHosted = !/^https:\/\/app\.(.*\.)?xano\.com$/.test(flags.origin);
57
+ let instance;
58
+ if (isSelfHosted) {
59
+ instance = {
60
+ display: flags.origin,
61
+ id: 'self-hosted',
62
+ name: 'self-hosted',
63
+ origin: flags.origin,
64
+ };
65
+ }
66
+ else {
67
+ this.log('');
68
+ this.log('Fetching available instances...');
69
+ const instances = await this.fetchInstances(token, flags.origin);
70
+ if (instances.length === 0) {
71
+ this.error('No instances found. Please check your account.');
72
+ }
73
+ instance = await this.selectInstance(instances);
48
74
  }
49
- const instance = await this.selectInstance(instances);
50
75
  // Step 4: Workspace selection
51
76
  let workspace;
52
77
  let branch;
@@ -73,6 +98,7 @@ Opening browser for Xano login at https://custom.xano.com...`,
73
98
  access_token: token,
74
99
  account_origin: flags.origin,
75
100
  branch,
101
+ ...(flags.insecure && { insecure: true }),
76
102
  instance_origin: instance.origin,
77
103
  name: profileName,
78
104
  workspace: workspace?.id,
@@ -90,13 +116,17 @@ Opening browser for Xano login at https://custom.xano.com...`,
90
116
  throw error;
91
117
  }
92
118
  }
119
+ getHeaders(accessToken) {
120
+ return {
121
+ 'User-Agent': buildUserAgent(this.config.version),
122
+ accept: 'application/json',
123
+ ...(accessToken && { Authorization: `Bearer ${accessToken}` }),
124
+ };
125
+ }
93
126
  async fetchBranches(accessToken, origin, workspaceId) {
94
127
  try {
95
128
  const response = await fetch(`${origin}/api:meta/workspace/${workspaceId}/branch`, {
96
- headers: {
97
- accept: 'application/json',
98
- Authorization: `Bearer ${accessToken}`,
99
- },
129
+ headers: this.getHeaders(accessToken),
100
130
  method: 'GET',
101
131
  });
102
132
  if (!response.ok) {
@@ -117,10 +147,7 @@ Opening browser for Xano login at https://custom.xano.com...`,
117
147
  }
118
148
  async fetchInstances(accessToken, origin) {
119
149
  const response = await fetch(`${origin}/api:meta/instance`, {
120
- headers: {
121
- accept: 'application/json',
122
- Authorization: `Bearer ${accessToken}`,
123
- },
150
+ headers: this.getHeaders(accessToken),
124
151
  method: 'GET',
125
152
  });
126
153
  if (!response.ok) {
@@ -143,10 +170,7 @@ Opening browser for Xano login at https://custom.xano.com...`,
143
170
  async fetchWorkspaces(accessToken, origin) {
144
171
  try {
145
172
  const response = await fetch(`${origin}/api:meta/workspace`, {
146
- headers: {
147
- accept: 'application/json',
148
- Authorization: `Bearer ${accessToken}`,
149
- },
173
+ headers: this.getHeaders(accessToken),
150
174
  method: 'GET',
151
175
  });
152
176
  if (!response.ok) {
@@ -211,6 +235,7 @@ Opening browser for Xano login at https://custom.xano.com...`,
211
235
  instance_origin: profile.instance_origin,
212
236
  ...(profile.workspace && { workspace: profile.workspace }),
213
237
  ...(profile.branch && { branch: profile.branch }),
238
+ ...(profile.insecure && { insecure: true }),
214
239
  };
215
240
  // Set as default profile
216
241
  credentials.default = profile.name;
@@ -464,10 +489,7 @@ Opening browser for Xano login at https://custom.xano.com...`,
464
489
  }
465
490
  async validateToken(token, origin) {
466
491
  const response = await fetch(`${origin}/api:meta/auth/me`, {
467
- headers: {
468
- accept: 'application/json',
469
- Authorization: `Bearer ${token}`,
470
- },
492
+ headers: this.getHeaders(token),
471
493
  method: 'GET',
472
494
  });
473
495
  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>;