@xano/cli 0.0.2
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 +1200 -0
- package/bin/dev.cmd +3 -0
- package/bin/dev.js +5 -0
- package/bin/run.cmd +3 -0
- package/bin/run.js +5 -0
- package/dist/base-command.d.ts +11 -0
- package/dist/base-command.js +40 -0
- package/dist/commands/ephemeral/run/job/index.d.ts +19 -0
- package/dist/commands/ephemeral/run/job/index.js +318 -0
- package/dist/commands/ephemeral/run/service/index.d.ts +18 -0
- package/dist/commands/ephemeral/run/service/index.js +286 -0
- package/dist/commands/function/create/index.d.ts +18 -0
- package/dist/commands/function/create/index.js +280 -0
- package/dist/commands/function/edit/index.d.ts +24 -0
- package/dist/commands/function/edit/index.js +482 -0
- package/dist/commands/function/get/index.d.ts +18 -0
- package/dist/commands/function/get/index.js +279 -0
- package/dist/commands/function/list/index.d.ts +19 -0
- package/dist/commands/function/list/index.js +208 -0
- package/dist/commands/profile/create/index.d.ts +17 -0
- package/dist/commands/profile/create/index.js +123 -0
- package/dist/commands/profile/delete/index.d.ts +14 -0
- package/dist/commands/profile/delete/index.js +124 -0
- package/dist/commands/profile/edit/index.d.ts +18 -0
- package/dist/commands/profile/edit/index.js +129 -0
- package/dist/commands/profile/get-default/index.d.ts +6 -0
- package/dist/commands/profile/get-default/index.js +44 -0
- package/dist/commands/profile/list/index.d.ts +10 -0
- package/dist/commands/profile/list/index.js +115 -0
- package/dist/commands/profile/set-default/index.d.ts +9 -0
- package/dist/commands/profile/set-default/index.js +63 -0
- package/dist/commands/profile/wizard/index.d.ts +15 -0
- package/dist/commands/profile/wizard/index.js +350 -0
- package/dist/commands/static_host/build/create/index.d.ts +18 -0
- package/dist/commands/static_host/build/create/index.js +194 -0
- package/dist/commands/static_host/build/get/index.d.ts +16 -0
- package/dist/commands/static_host/build/get/index.js +165 -0
- package/dist/commands/static_host/build/list/index.d.ts +17 -0
- package/dist/commands/static_host/build/list/index.js +192 -0
- package/dist/commands/static_host/list/index.d.ts +15 -0
- package/dist/commands/static_host/list/index.js +187 -0
- package/dist/commands/workspace/list/index.d.ts +11 -0
- package/dist/commands/workspace/list/index.js +154 -0
- package/dist/help.d.ts +20 -0
- package/dist/help.js +26 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/oclif.manifest.json +1370 -0
- package/package.json +79 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { Args, Command, Flags } from '@oclif/core';
|
|
2
|
+
import * as fs from 'node:fs';
|
|
3
|
+
import * as os from 'node:os';
|
|
4
|
+
import * as path from 'node:path';
|
|
5
|
+
import * as yaml from 'js-yaml';
|
|
6
|
+
export default class ProfileDelete extends Command {
|
|
7
|
+
static args = {
|
|
8
|
+
name: Args.string({
|
|
9
|
+
description: 'Profile name to delete',
|
|
10
|
+
required: true,
|
|
11
|
+
}),
|
|
12
|
+
};
|
|
13
|
+
static flags = {
|
|
14
|
+
force: Flags.boolean({
|
|
15
|
+
char: 'f',
|
|
16
|
+
description: 'Skip confirmation prompt',
|
|
17
|
+
required: false,
|
|
18
|
+
default: false,
|
|
19
|
+
}),
|
|
20
|
+
};
|
|
21
|
+
static description = 'Delete a profile configuration';
|
|
22
|
+
static examples = [
|
|
23
|
+
`$ xano profile:delete old-profile
|
|
24
|
+
Are you sure you want to delete profile 'old-profile'? (y/n): y
|
|
25
|
+
Profile 'old-profile' deleted successfully from ~/.xano/credentials.yaml
|
|
26
|
+
`,
|
|
27
|
+
`$ xano profile:delete old-profile --force
|
|
28
|
+
Profile 'old-profile' deleted successfully from ~/.xano/credentials.yaml
|
|
29
|
+
`,
|
|
30
|
+
`$ xano profile:delete old-profile -f
|
|
31
|
+
Profile 'old-profile' deleted successfully from ~/.xano/credentials.yaml
|
|
32
|
+
`,
|
|
33
|
+
];
|
|
34
|
+
async run() {
|
|
35
|
+
const { args, flags } = await this.parse(ProfileDelete);
|
|
36
|
+
const configDir = path.join(os.homedir(), '.xano');
|
|
37
|
+
const credentialsPath = path.join(configDir, 'credentials.yaml');
|
|
38
|
+
// Check if credentials file exists
|
|
39
|
+
if (!fs.existsSync(credentialsPath)) {
|
|
40
|
+
this.error(`Credentials file not found at ${credentialsPath}. No profiles to delete.`);
|
|
41
|
+
}
|
|
42
|
+
// Read existing credentials file
|
|
43
|
+
let credentials;
|
|
44
|
+
try {
|
|
45
|
+
const fileContent = fs.readFileSync(credentialsPath, 'utf8');
|
|
46
|
+
const parsed = yaml.load(fileContent);
|
|
47
|
+
if (!parsed || typeof parsed !== 'object' || !('profiles' in parsed)) {
|
|
48
|
+
this.error('Credentials file has invalid format.');
|
|
49
|
+
}
|
|
50
|
+
credentials = parsed;
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
this.error(`Failed to parse credentials file: ${error}`);
|
|
54
|
+
}
|
|
55
|
+
// Check if profile exists
|
|
56
|
+
if (!(args.name in credentials.profiles)) {
|
|
57
|
+
this.error(`Profile '${args.name}' not found. Available profiles: ${Object.keys(credentials.profiles).join(', ')}`);
|
|
58
|
+
}
|
|
59
|
+
// Confirm deletion unless --force flag is used
|
|
60
|
+
if (!flags.force) {
|
|
61
|
+
const confirm = await this.confirm(`Are you sure you want to delete profile '${args.name}'?`);
|
|
62
|
+
if (!confirm) {
|
|
63
|
+
this.log('Deletion cancelled.');
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// Check if deleting the default profile
|
|
68
|
+
const wasDefault = credentials.default === args.name;
|
|
69
|
+
// Delete the profile
|
|
70
|
+
delete credentials.profiles[args.name];
|
|
71
|
+
// If deleted profile was the default, update to first available profile
|
|
72
|
+
if (wasDefault) {
|
|
73
|
+
const remainingProfiles = Object.keys(credentials.profiles);
|
|
74
|
+
if (remainingProfiles.length > 0) {
|
|
75
|
+
credentials.default = remainingProfiles[0];
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
delete credentials.default;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// Write the updated credentials back to the file
|
|
82
|
+
try {
|
|
83
|
+
const yamlContent = yaml.dump(credentials, {
|
|
84
|
+
indent: 2,
|
|
85
|
+
lineWidth: -1,
|
|
86
|
+
noRefs: true,
|
|
87
|
+
});
|
|
88
|
+
fs.writeFileSync(credentialsPath, yamlContent, 'utf8');
|
|
89
|
+
this.log(`Profile '${args.name}' deleted successfully from ${credentialsPath}`);
|
|
90
|
+
if (wasDefault) {
|
|
91
|
+
if (credentials.default) {
|
|
92
|
+
this.log(`Default profile changed to '${credentials.default}'`);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
this.log(`Default profile removed (no profiles remaining)`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
this.error(`Failed to write credentials file: ${error}`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
async confirm(message) {
|
|
104
|
+
// Simple confirmation using stdin
|
|
105
|
+
const response = await this.promptInput(`${message} (y/n): `);
|
|
106
|
+
return response.toLowerCase() === 'y' || response.toLowerCase() === 'yes';
|
|
107
|
+
}
|
|
108
|
+
async promptInput(prompt) {
|
|
109
|
+
process.stdout.write(prompt);
|
|
110
|
+
// Set stdin to raw mode temporarily
|
|
111
|
+
const wasRaw = process.stdin.isRaw;
|
|
112
|
+
process.stdin.setRawMode?.(false);
|
|
113
|
+
process.stdin.resume();
|
|
114
|
+
return new Promise((resolve) => {
|
|
115
|
+
process.stdin.once('data', (data) => {
|
|
116
|
+
process.stdin.pause();
|
|
117
|
+
if (wasRaw !== undefined) {
|
|
118
|
+
process.stdin.setRawMode?.(wasRaw);
|
|
119
|
+
}
|
|
120
|
+
resolve(data.toString().trim());
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
export default class ProfileEdit extends Command {
|
|
3
|
+
static args: {
|
|
4
|
+
name: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
5
|
+
};
|
|
6
|
+
static flags: {
|
|
7
|
+
account_origin: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
instance_origin: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
access_token: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
workspace: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
branch: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
'remove-workspace': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
13
|
+
'remove-branch': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
14
|
+
};
|
|
15
|
+
static description: string;
|
|
16
|
+
static examples: string[];
|
|
17
|
+
run(): Promise<void>;
|
|
18
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { Args, Command, Flags } from '@oclif/core';
|
|
2
|
+
import * as fs from 'node:fs';
|
|
3
|
+
import * as os from 'node:os';
|
|
4
|
+
import * as path from 'node:path';
|
|
5
|
+
import * as yaml from 'js-yaml';
|
|
6
|
+
export default class ProfileEdit extends Command {
|
|
7
|
+
static args = {
|
|
8
|
+
name: Args.string({
|
|
9
|
+
description: 'Profile name to edit',
|
|
10
|
+
required: true,
|
|
11
|
+
}),
|
|
12
|
+
};
|
|
13
|
+
static flags = {
|
|
14
|
+
account_origin: Flags.string({
|
|
15
|
+
char: 'a',
|
|
16
|
+
description: 'Update account origin URL',
|
|
17
|
+
required: false,
|
|
18
|
+
}),
|
|
19
|
+
instance_origin: Flags.string({
|
|
20
|
+
char: 'i',
|
|
21
|
+
description: 'Update instance origin URL',
|
|
22
|
+
required: false,
|
|
23
|
+
}),
|
|
24
|
+
access_token: Flags.string({
|
|
25
|
+
char: 't',
|
|
26
|
+
description: 'Update access token for the Xano Metadata API',
|
|
27
|
+
required: false,
|
|
28
|
+
}),
|
|
29
|
+
workspace: Flags.string({
|
|
30
|
+
char: 'w',
|
|
31
|
+
description: 'Update workspace name',
|
|
32
|
+
required: false,
|
|
33
|
+
}),
|
|
34
|
+
branch: Flags.string({
|
|
35
|
+
char: 'b',
|
|
36
|
+
description: 'Update branch name',
|
|
37
|
+
required: false,
|
|
38
|
+
}),
|
|
39
|
+
'remove-workspace': Flags.boolean({
|
|
40
|
+
description: 'Remove workspace from profile',
|
|
41
|
+
required: false,
|
|
42
|
+
default: false,
|
|
43
|
+
}),
|
|
44
|
+
'remove-branch': Flags.boolean({
|
|
45
|
+
description: 'Remove branch from profile',
|
|
46
|
+
required: false,
|
|
47
|
+
default: false,
|
|
48
|
+
}),
|
|
49
|
+
};
|
|
50
|
+
static description = 'Edit an existing profile configuration';
|
|
51
|
+
static examples = [
|
|
52
|
+
`$ xano profile:edit production --access_token new_token123
|
|
53
|
+
Profile 'production' updated successfully at ~/.xano/credentials.yaml
|
|
54
|
+
`,
|
|
55
|
+
`$ xano profile:edit staging -i https://new-staging-instance.xano.com -t new_token456
|
|
56
|
+
Profile 'staging' updated successfully at ~/.xano/credentials.yaml
|
|
57
|
+
`,
|
|
58
|
+
`$ xano profile:edit dev -w new-workspace -b new-branch
|
|
59
|
+
Profile 'dev' updated successfully at ~/.xano/credentials.yaml
|
|
60
|
+
`,
|
|
61
|
+
`$ xano profile:edit dev --remove-workspace
|
|
62
|
+
Profile 'dev' updated successfully at ~/.xano/credentials.yaml
|
|
63
|
+
`,
|
|
64
|
+
];
|
|
65
|
+
async run() {
|
|
66
|
+
const { args, flags } = await this.parse(ProfileEdit);
|
|
67
|
+
const configDir = path.join(os.homedir(), '.xano');
|
|
68
|
+
const credentialsPath = path.join(configDir, 'credentials.yaml');
|
|
69
|
+
// Check if credentials file exists
|
|
70
|
+
if (!fs.existsSync(credentialsPath)) {
|
|
71
|
+
this.error(`Credentials file not found at ${credentialsPath}. Create a profile first using 'profile:create'.`);
|
|
72
|
+
}
|
|
73
|
+
// Read existing credentials file
|
|
74
|
+
let credentials;
|
|
75
|
+
try {
|
|
76
|
+
const fileContent = fs.readFileSync(credentialsPath, 'utf8');
|
|
77
|
+
const parsed = yaml.load(fileContent);
|
|
78
|
+
if (!parsed || typeof parsed !== 'object' || !('profiles' in parsed)) {
|
|
79
|
+
this.error('Credentials file has invalid format.');
|
|
80
|
+
}
|
|
81
|
+
credentials = parsed;
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
this.error(`Failed to parse credentials file: ${error}`);
|
|
85
|
+
}
|
|
86
|
+
// Check if profile exists
|
|
87
|
+
if (!(args.name in credentials.profiles)) {
|
|
88
|
+
this.error(`Profile '${args.name}' not found. Available profiles: ${Object.keys(credentials.profiles).join(', ')}`);
|
|
89
|
+
}
|
|
90
|
+
// Get the existing profile
|
|
91
|
+
const existingProfile = credentials.profiles[args.name];
|
|
92
|
+
// Check if any flags were provided
|
|
93
|
+
const hasFlags = flags.account_origin || flags.instance_origin || flags.access_token ||
|
|
94
|
+
flags.workspace || flags.branch || flags['remove-workspace'] || flags['remove-branch'];
|
|
95
|
+
if (!hasFlags) {
|
|
96
|
+
this.error('No fields specified to update. Use at least one flag to edit the profile.');
|
|
97
|
+
}
|
|
98
|
+
// Update only the fields that were provided
|
|
99
|
+
const updatedProfile = {
|
|
100
|
+
...existingProfile,
|
|
101
|
+
...(flags.account_origin !== undefined && { account_origin: flags.account_origin }),
|
|
102
|
+
...(flags.instance_origin !== undefined && { instance_origin: flags.instance_origin }),
|
|
103
|
+
...(flags.access_token !== undefined && { access_token: flags.access_token }),
|
|
104
|
+
...(flags.workspace !== undefined && { workspace: flags.workspace }),
|
|
105
|
+
...(flags.branch !== undefined && { branch: flags.branch }),
|
|
106
|
+
};
|
|
107
|
+
// Handle removal flags
|
|
108
|
+
if (flags['remove-workspace']) {
|
|
109
|
+
delete updatedProfile.workspace;
|
|
110
|
+
}
|
|
111
|
+
if (flags['remove-branch']) {
|
|
112
|
+
delete updatedProfile.branch;
|
|
113
|
+
}
|
|
114
|
+
credentials.profiles[args.name] = updatedProfile;
|
|
115
|
+
// Write the updated credentials back to the file
|
|
116
|
+
try {
|
|
117
|
+
const yamlContent = yaml.dump(credentials, {
|
|
118
|
+
indent: 2,
|
|
119
|
+
lineWidth: -1,
|
|
120
|
+
noRefs: true,
|
|
121
|
+
});
|
|
122
|
+
fs.writeFileSync(credentialsPath, yamlContent, 'utf8');
|
|
123
|
+
this.log(`Profile '${args.name}' updated successfully at ${credentialsPath}`);
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
this.error(`Failed to write credentials file: ${error}`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
import * as fs from 'node:fs';
|
|
3
|
+
import * as os from 'node:os';
|
|
4
|
+
import * as path from 'node:path';
|
|
5
|
+
import * as yaml from 'js-yaml';
|
|
6
|
+
export default class ProfileGetDefault extends Command {
|
|
7
|
+
static description = 'Get the current default profile name';
|
|
8
|
+
static examples = [
|
|
9
|
+
`$ xano profile:get-default
|
|
10
|
+
production
|
|
11
|
+
`,
|
|
12
|
+
`$ xano profile:get-default
|
|
13
|
+
No default profile set
|
|
14
|
+
`,
|
|
15
|
+
];
|
|
16
|
+
async run() {
|
|
17
|
+
const configDir = path.join(os.homedir(), '.xano');
|
|
18
|
+
const credentialsPath = path.join(configDir, 'credentials.yaml');
|
|
19
|
+
// Check if credentials file exists
|
|
20
|
+
if (!fs.existsSync(credentialsPath)) {
|
|
21
|
+
this.error(`Credentials file not found at ${credentialsPath}. No profiles exist.`);
|
|
22
|
+
}
|
|
23
|
+
// Read credentials file
|
|
24
|
+
let credentials;
|
|
25
|
+
try {
|
|
26
|
+
const fileContent = fs.readFileSync(credentialsPath, 'utf8');
|
|
27
|
+
const parsed = yaml.load(fileContent);
|
|
28
|
+
if (!parsed || typeof parsed !== 'object' || !('profiles' in parsed)) {
|
|
29
|
+
this.error('Credentials file has invalid format.');
|
|
30
|
+
}
|
|
31
|
+
credentials = parsed;
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
this.error(`Failed to parse credentials file: ${error}`);
|
|
35
|
+
}
|
|
36
|
+
// Get and display the default profile
|
|
37
|
+
if (credentials.default) {
|
|
38
|
+
this.log(credentials.default);
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
this.log('No default profile set');
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
export default class ProfileList extends Command {
|
|
3
|
+
static flags: {
|
|
4
|
+
details: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
5
|
+
};
|
|
6
|
+
static description: string;
|
|
7
|
+
static examples: string[];
|
|
8
|
+
run(): Promise<void>;
|
|
9
|
+
private maskToken;
|
|
10
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { Command, Flags } from '@oclif/core';
|
|
2
|
+
import * as fs from 'node:fs';
|
|
3
|
+
import * as os from 'node:os';
|
|
4
|
+
import * as path from 'node:path';
|
|
5
|
+
import * as yaml from 'js-yaml';
|
|
6
|
+
export default class ProfileList extends Command {
|
|
7
|
+
static flags = {
|
|
8
|
+
details: Flags.boolean({
|
|
9
|
+
char: 'd',
|
|
10
|
+
description: 'Show detailed information for each profile',
|
|
11
|
+
required: false,
|
|
12
|
+
default: false,
|
|
13
|
+
}),
|
|
14
|
+
};
|
|
15
|
+
static description = 'List all available profile configurations';
|
|
16
|
+
static examples = [
|
|
17
|
+
`$ xano profile:list
|
|
18
|
+
Available profiles:
|
|
19
|
+
- default
|
|
20
|
+
- production
|
|
21
|
+
- staging
|
|
22
|
+
- development
|
|
23
|
+
`,
|
|
24
|
+
`$ xano profile:list --details
|
|
25
|
+
Available profiles:
|
|
26
|
+
|
|
27
|
+
Profile: default
|
|
28
|
+
Account Origin: https://account.xano.com
|
|
29
|
+
Instance Origin: https://instance.xano.com
|
|
30
|
+
Access Token: ***...***
|
|
31
|
+
Workspace: my-workspace
|
|
32
|
+
Branch: main
|
|
33
|
+
|
|
34
|
+
Profile: production
|
|
35
|
+
Account Origin: https://account.xano.com
|
|
36
|
+
Instance Origin: https://prod-instance.xano.com
|
|
37
|
+
Access Token: ***...***
|
|
38
|
+
`,
|
|
39
|
+
`$ xano profile:list -d
|
|
40
|
+
Available profiles:
|
|
41
|
+
|
|
42
|
+
Profile: default
|
|
43
|
+
Account Origin: https://account.xano.com
|
|
44
|
+
Instance Origin: https://instance.xano.com
|
|
45
|
+
Access Token: ***...***
|
|
46
|
+
Workspace: my-workspace
|
|
47
|
+
Branch: main
|
|
48
|
+
`,
|
|
49
|
+
];
|
|
50
|
+
async run() {
|
|
51
|
+
const { flags } = await this.parse(ProfileList);
|
|
52
|
+
const configDir = path.join(os.homedir(), '.xano');
|
|
53
|
+
const credentialsPath = path.join(configDir, 'credentials.yaml');
|
|
54
|
+
// Check if credentials file exists
|
|
55
|
+
if (!fs.existsSync(credentialsPath)) {
|
|
56
|
+
this.log(`No profiles found. The credentials file does not exist at ${credentialsPath}`);
|
|
57
|
+
this.log(`Create a profile using 'xano profile:create'`);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
// Read credentials file
|
|
61
|
+
let credentials;
|
|
62
|
+
try {
|
|
63
|
+
const fileContent = fs.readFileSync(credentialsPath, 'utf8');
|
|
64
|
+
const parsed = yaml.load(fileContent);
|
|
65
|
+
if (!parsed || typeof parsed !== 'object' || !('profiles' in parsed)) {
|
|
66
|
+
this.error('Credentials file has invalid format.');
|
|
67
|
+
}
|
|
68
|
+
credentials = parsed;
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
this.error(`Failed to parse credentials file: ${error}`);
|
|
72
|
+
}
|
|
73
|
+
// Get profile names
|
|
74
|
+
const profileNames = Object.keys(credentials.profiles);
|
|
75
|
+
if (profileNames.length === 0) {
|
|
76
|
+
this.log('No profiles found in credentials file.');
|
|
77
|
+
this.log(`Create a profile using 'xano profile:create'`);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
// Display profiles
|
|
81
|
+
if (flags.details) {
|
|
82
|
+
this.log('Available profiles:\n');
|
|
83
|
+
for (const name of profileNames.sort()) {
|
|
84
|
+
const profile = credentials.profiles[name];
|
|
85
|
+
const isDefault = credentials.default === name ? ' [DEFAULT]' : '';
|
|
86
|
+
this.log(`Profile: ${name}${isDefault}`);
|
|
87
|
+
this.log(` Account Origin: ${profile.account_origin || '(not set)'}`);
|
|
88
|
+
this.log(` Instance Origin: ${profile.instance_origin}`);
|
|
89
|
+
this.log(` Access Token: ${this.maskToken(profile.access_token)}`);
|
|
90
|
+
if (profile.workspace) {
|
|
91
|
+
this.log(` Workspace: ${profile.workspace}`);
|
|
92
|
+
}
|
|
93
|
+
if (profile.branch) {
|
|
94
|
+
this.log(` Branch: ${profile.branch}`);
|
|
95
|
+
}
|
|
96
|
+
this.log(''); // Empty line between profiles
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
this.log('Available profiles:');
|
|
101
|
+
for (const name of profileNames.sort()) {
|
|
102
|
+
const isDefault = credentials.default === name ? ' [DEFAULT]' : '';
|
|
103
|
+
this.log(` - ${name}${isDefault}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
maskToken(token) {
|
|
108
|
+
if (token.length <= 8) {
|
|
109
|
+
return '***';
|
|
110
|
+
}
|
|
111
|
+
const start = token.slice(0, 3);
|
|
112
|
+
const end = token.slice(-3);
|
|
113
|
+
return `${start}...${end}`;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
export default class ProfileSetDefault extends Command {
|
|
3
|
+
static args: {
|
|
4
|
+
name: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
5
|
+
};
|
|
6
|
+
static description: string;
|
|
7
|
+
static examples: string[];
|
|
8
|
+
run(): Promise<void>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { Args, Command } from '@oclif/core';
|
|
2
|
+
import * as fs from 'node:fs';
|
|
3
|
+
import * as os from 'node:os';
|
|
4
|
+
import * as path from 'node:path';
|
|
5
|
+
import * as yaml from 'js-yaml';
|
|
6
|
+
export default class ProfileSetDefault extends Command {
|
|
7
|
+
static args = {
|
|
8
|
+
name: Args.string({
|
|
9
|
+
description: 'Profile name to set as default',
|
|
10
|
+
required: true,
|
|
11
|
+
}),
|
|
12
|
+
};
|
|
13
|
+
static description = 'Set the default profile';
|
|
14
|
+
static examples = [
|
|
15
|
+
`$ xano profile:set-default production
|
|
16
|
+
Default profile set to 'production'
|
|
17
|
+
`,
|
|
18
|
+
`$ xano profile:set-default staging
|
|
19
|
+
Default profile set to 'staging'
|
|
20
|
+
`,
|
|
21
|
+
];
|
|
22
|
+
async run() {
|
|
23
|
+
const { args } = await this.parse(ProfileSetDefault);
|
|
24
|
+
const configDir = path.join(os.homedir(), '.xano');
|
|
25
|
+
const credentialsPath = path.join(configDir, 'credentials.yaml');
|
|
26
|
+
// Check if credentials file exists
|
|
27
|
+
if (!fs.existsSync(credentialsPath)) {
|
|
28
|
+
this.error(`Credentials file not found at ${credentialsPath}. Create a profile first using 'profile:create'.`);
|
|
29
|
+
}
|
|
30
|
+
// Read existing credentials file
|
|
31
|
+
let credentials;
|
|
32
|
+
try {
|
|
33
|
+
const fileContent = fs.readFileSync(credentialsPath, 'utf8');
|
|
34
|
+
const parsed = yaml.load(fileContent);
|
|
35
|
+
if (!parsed || typeof parsed !== 'object' || !('profiles' in parsed)) {
|
|
36
|
+
this.error('Credentials file has invalid format.');
|
|
37
|
+
}
|
|
38
|
+
credentials = parsed;
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
this.error(`Failed to parse credentials file: ${error}`);
|
|
42
|
+
}
|
|
43
|
+
// Check if profile exists
|
|
44
|
+
if (!(args.name in credentials.profiles)) {
|
|
45
|
+
this.error(`Profile '${args.name}' not found. Available profiles: ${Object.keys(credentials.profiles).join(', ')}`);
|
|
46
|
+
}
|
|
47
|
+
// Set the default profile
|
|
48
|
+
credentials.default = args.name;
|
|
49
|
+
// Write the updated credentials back to the file
|
|
50
|
+
try {
|
|
51
|
+
const yamlContent = yaml.dump(credentials, {
|
|
52
|
+
indent: 2,
|
|
53
|
+
lineWidth: -1,
|
|
54
|
+
noRefs: true,
|
|
55
|
+
});
|
|
56
|
+
fs.writeFileSync(credentialsPath, yamlContent, 'utf8');
|
|
57
|
+
this.log(`Default profile set to '${args.name}'`);
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
this.error(`Failed to write credentials file: ${error}`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
export default class ProfileWizard extends Command {
|
|
3
|
+
static flags: {
|
|
4
|
+
name: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
5
|
+
origin: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
6
|
+
};
|
|
7
|
+
static description: string;
|
|
8
|
+
static examples: string[];
|
|
9
|
+
run(): Promise<void>;
|
|
10
|
+
private fetchInstances;
|
|
11
|
+
private fetchWorkspaces;
|
|
12
|
+
private fetchBranches;
|
|
13
|
+
private getDefaultProfileName;
|
|
14
|
+
private saveProfile;
|
|
15
|
+
}
|