@xano/cli 0.0.13 → 0.0.15
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 +97 -12
- package/dist/commands/profile/create/index.d.ts +2 -0
- package/dist/commands/profile/create/index.js +15 -0
- package/dist/commands/profile/edit/index.d.ts +4 -0
- package/dist/commands/profile/edit/index.js +37 -1
- package/dist/commands/profile/list/index.js +5 -0
- package/dist/commands/profile/project/index.d.ts +6 -0
- package/dist/commands/profile/project/index.js +54 -0
- package/dist/commands/profile/token/index.d.ts +6 -0
- package/dist/commands/profile/token/index.js +54 -0
- package/dist/commands/profile/wizard/index.d.ts +1 -0
- package/dist/commands/profile/wizard/index.js +70 -0
- package/dist/commands/run/env/delete/index.d.ts +13 -0
- package/dist/commands/run/env/delete/index.js +65 -0
- package/dist/commands/run/env/get/index.d.ts +13 -0
- package/dist/commands/run/env/get/index.js +52 -0
- package/dist/commands/run/env/list/index.d.ts +11 -0
- package/dist/commands/run/env/list/index.js +58 -0
- package/dist/commands/run/env/set/index.d.ts +13 -0
- package/dist/commands/run/env/set/index.js +51 -0
- package/dist/commands/{ephemeral/run/job → run/exec}/index.d.ts +4 -3
- package/dist/commands/run/exec/index.js +353 -0
- package/dist/commands/{ephemeral/run/service → run/info}/index.d.ts +3 -5
- package/dist/commands/run/info/index.js +160 -0
- package/dist/commands/run/projects/create/index.d.ts +13 -0
- package/dist/commands/run/projects/create/index.js +75 -0
- package/dist/commands/run/projects/delete/index.d.ts +13 -0
- package/dist/commands/run/projects/delete/index.js +65 -0
- package/dist/commands/run/projects/list/index.d.ts +12 -0
- package/dist/commands/run/projects/list/index.js +66 -0
- package/dist/commands/run/projects/update/index.d.ts +15 -0
- package/dist/commands/run/projects/update/index.js +86 -0
- package/dist/commands/run/secrets/delete/index.d.ts +13 -0
- package/dist/commands/run/secrets/delete/index.js +65 -0
- package/dist/commands/run/secrets/get/index.d.ts +13 -0
- package/dist/commands/run/secrets/get/index.js +52 -0
- package/dist/commands/run/secrets/list/index.d.ts +11 -0
- package/dist/commands/run/secrets/list/index.js +62 -0
- package/dist/commands/run/secrets/set/index.d.ts +15 -0
- package/dist/commands/run/secrets/set/index.js +74 -0
- package/dist/commands/run/sessions/delete/index.d.ts +13 -0
- package/dist/commands/run/sessions/delete/index.js +65 -0
- package/dist/commands/run/sessions/get/index.d.ts +13 -0
- package/dist/commands/run/sessions/get/index.js +72 -0
- package/dist/commands/run/sessions/list/index.d.ts +12 -0
- package/dist/commands/run/sessions/list/index.js +64 -0
- package/dist/commands/run/sessions/start/index.d.ts +13 -0
- package/dist/commands/run/sessions/start/index.js +56 -0
- package/dist/commands/run/sessions/stop/index.d.ts +13 -0
- package/dist/commands/run/sessions/stop/index.js +56 -0
- package/dist/commands/run/sink/get/index.d.ts +13 -0
- package/dist/commands/run/sink/get/index.js +63 -0
- package/dist/lib/base-run-command.d.ts +41 -0
- package/dist/lib/base-run-command.js +73 -0
- package/dist/lib/run-http-client.d.ts +58 -0
- package/dist/lib/run-http-client.js +136 -0
- package/dist/lib/run-types.d.ts +226 -0
- package/dist/lib/run-types.js +5 -0
- package/oclif.manifest.json +1423 -306
- package/package.json +1 -1
- package/dist/commands/ephemeral/run/job/index.js +0 -311
- package/dist/commands/ephemeral/run/service/index.js +0 -287
package/README.md
CHANGED
|
@@ -23,16 +23,16 @@ npm install -g @xano/cli
|
|
|
23
23
|
xano workspace:list
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
-
3.
|
|
26
|
+
3. Execute XanoScript code:
|
|
27
27
|
```bash
|
|
28
|
-
xano
|
|
28
|
+
xano run exec -f script.xs
|
|
29
29
|
```
|
|
30
30
|
|
|
31
31
|
## Commands
|
|
32
32
|
|
|
33
33
|
### Profile Management
|
|
34
34
|
|
|
35
|
-
Profiles store your Xano credentials and default workspace settings.
|
|
35
|
+
Profiles store your Xano credentials and default workspace/project settings.
|
|
36
36
|
|
|
37
37
|
```bash
|
|
38
38
|
# Create a profile interactively
|
|
@@ -41,6 +41,9 @@ xano profile:wizard
|
|
|
41
41
|
# Create a profile manually
|
|
42
42
|
xano profile:create myprofile -i https://instance.xano.com -t <access_token>
|
|
43
43
|
|
|
44
|
+
# Create a profile with workspace and project
|
|
45
|
+
xano profile:create myprofile -i https://instance.xano.com -t <access_token> -w my-workspace -j my-project
|
|
46
|
+
|
|
44
47
|
# List profiles
|
|
45
48
|
xano profile:list
|
|
46
49
|
xano profile:list --details
|
|
@@ -49,7 +52,8 @@ xano profile:list --details
|
|
|
49
52
|
xano profile:set-default myprofile
|
|
50
53
|
|
|
51
54
|
# Edit a profile
|
|
52
|
-
xano profile:edit myprofile -w 123
|
|
55
|
+
xano profile:edit myprofile -w 123 # Set default workspace
|
|
56
|
+
xano profile:edit myprofile -j my-project # Set default project
|
|
53
57
|
|
|
54
58
|
# Delete a profile
|
|
55
59
|
xano profile:delete myprofile
|
|
@@ -84,18 +88,99 @@ xano function:edit 145 -f new.xs # Update from file
|
|
|
84
88
|
xano function:edit 145 --publish # Publish after editing
|
|
85
89
|
```
|
|
86
90
|
|
|
87
|
-
###
|
|
91
|
+
### Xano Run
|
|
92
|
+
|
|
93
|
+
Execute XanoScript code and manage projects, sessions, environment variables, and secrets.
|
|
94
|
+
|
|
95
|
+
#### Executing Code
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
# Execute XanoScript (job or service)
|
|
99
|
+
xano run exec -f script.xs
|
|
100
|
+
xano run exec -f https://example.com/script.xs # From URL
|
|
101
|
+
xano run exec -f script.xs -a args.json # With input arguments (file)
|
|
102
|
+
xano run exec -f script.xs -a https://ex.com/args.json # With input arguments (URL)
|
|
103
|
+
xano run exec -f script.xs --edit # Edit in $EDITOR first
|
|
104
|
+
xano run exec -f script.xs --env API_KEY=secret # With env overrides
|
|
105
|
+
cat script.xs | xano run exec --stdin # From stdin
|
|
106
|
+
|
|
107
|
+
# Get document info (type, inputs, env vars)
|
|
108
|
+
xano run info -f script.xs
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
#### Projects
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
# List projects
|
|
115
|
+
xano run projects list
|
|
116
|
+
|
|
117
|
+
# Create a project
|
|
118
|
+
xano run projects create -n "My Project"
|
|
119
|
+
xano run projects create -n "My Project" -d "Description"
|
|
120
|
+
|
|
121
|
+
# Update a project
|
|
122
|
+
xano run projects update <project-id> -n "New Name"
|
|
123
|
+
xano run projects update <project-id> -d "New description"
|
|
124
|
+
|
|
125
|
+
# Delete a project
|
|
126
|
+
xano run projects delete <project-id>
|
|
127
|
+
xano run projects delete <project-id> --force # Skip confirmation
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
#### Sessions
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
# List sessions
|
|
134
|
+
xano run sessions list
|
|
135
|
+
|
|
136
|
+
# Get session details
|
|
137
|
+
xano run sessions get <session-id>
|
|
138
|
+
|
|
139
|
+
# Start/stop a session
|
|
140
|
+
xano run sessions start <session-id>
|
|
141
|
+
xano run sessions stop <session-id>
|
|
142
|
+
|
|
143
|
+
# Delete a session
|
|
144
|
+
xano run sessions delete <session-id>
|
|
145
|
+
xano run sessions delete <session-id> --force # Skip confirmation
|
|
146
|
+
|
|
147
|
+
# Get sink data for a completed session
|
|
148
|
+
xano run sink get <session-id>
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
#### Environment Variables
|
|
88
152
|
|
|
89
|
-
|
|
153
|
+
```bash
|
|
154
|
+
# List environment variable keys
|
|
155
|
+
xano run env list
|
|
156
|
+
|
|
157
|
+
# Set an environment variable
|
|
158
|
+
xano run env set API_KEY my-secret-key
|
|
159
|
+
|
|
160
|
+
# Get an environment variable value
|
|
161
|
+
xano run env get API_KEY
|
|
162
|
+
|
|
163
|
+
# Delete an environment variable
|
|
164
|
+
xano run env delete API_KEY
|
|
165
|
+
xano run env delete API_KEY --force # Skip confirmation
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
#### Secrets
|
|
90
169
|
|
|
91
170
|
```bash
|
|
92
|
-
#
|
|
93
|
-
xano
|
|
94
|
-
|
|
95
|
-
|
|
171
|
+
# List secrets
|
|
172
|
+
xano run secrets list
|
|
173
|
+
|
|
174
|
+
# Set a secret
|
|
175
|
+
xano run secrets set docker-registry -t dockerconfigjson -v '{"auths":{...}}' -r ghcr.io
|
|
176
|
+
xano run secrets set service-key -t service-account-token -v 'token-value'
|
|
177
|
+
|
|
178
|
+
# Get a secret value
|
|
179
|
+
xano run secrets get docker-registry
|
|
96
180
|
|
|
97
|
-
#
|
|
98
|
-
xano
|
|
181
|
+
# Delete a secret
|
|
182
|
+
xano run secrets delete docker-registry
|
|
183
|
+
xano run secrets delete docker-registry --force # Skip confirmation
|
|
99
184
|
```
|
|
100
185
|
|
|
101
186
|
### Static Hosts
|
|
@@ -9,6 +9,8 @@ export default class ProfileCreate extends Command {
|
|
|
9
9
|
access_token: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
10
|
workspace: 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
|
+
project: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
|
+
run_base_url: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
14
|
default: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
13
15
|
};
|
|
14
16
|
static description: string;
|
|
@@ -36,6 +36,16 @@ export default class ProfileCreate extends Command {
|
|
|
36
36
|
description: 'Branch name',
|
|
37
37
|
required: false,
|
|
38
38
|
}),
|
|
39
|
+
project: Flags.string({
|
|
40
|
+
char: 'j',
|
|
41
|
+
description: 'Project name',
|
|
42
|
+
required: false,
|
|
43
|
+
}),
|
|
44
|
+
run_base_url: Flags.string({
|
|
45
|
+
char: 'r',
|
|
46
|
+
description: 'Xano Run API base URL (default: https://app.xano.com/)',
|
|
47
|
+
required: false,
|
|
48
|
+
}),
|
|
39
49
|
default: Flags.boolean({
|
|
40
50
|
description: 'Set this profile as the default',
|
|
41
51
|
required: false,
|
|
@@ -52,6 +62,9 @@ Profile 'staging' created successfully at ~/.xano/credentials.yaml
|
|
|
52
62
|
`,
|
|
53
63
|
`$ xano profile:create dev -i https://dev-instance.xano.com -t token789 -w my-workspace -b feature-branch
|
|
54
64
|
Profile 'dev' created successfully at ~/.xano/credentials.yaml
|
|
65
|
+
`,
|
|
66
|
+
`$ xano profile:create dev -i https://dev-instance.xano.com -t token789 -w my-workspace -b feature-branch -j my-project
|
|
67
|
+
Profile 'dev' created successfully at ~/.xano/credentials.yaml
|
|
55
68
|
`,
|
|
56
69
|
`$ xano profile:create production --account_origin https://account.xano.com --instance_origin https://instance.xano.com --access_token token123 --default
|
|
57
70
|
Profile 'production' created successfully at ~/.xano/credentials.yaml
|
|
@@ -93,6 +106,8 @@ Default profile set to 'production'
|
|
|
93
106
|
access_token: flags.access_token,
|
|
94
107
|
...(flags.workspace && { workspace: flags.workspace }),
|
|
95
108
|
...(flags.branch && { branch: flags.branch }),
|
|
109
|
+
...(flags.project && { project: flags.project }),
|
|
110
|
+
...(flags.run_base_url && { run_base_url: flags.run_base_url }),
|
|
96
111
|
};
|
|
97
112
|
// Set default if flag is provided
|
|
98
113
|
if (flags.default) {
|
|
@@ -9,8 +9,12 @@ export default class ProfileEdit extends BaseCommand {
|
|
|
9
9
|
access_token: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
10
|
workspace: 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
|
+
project: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
13
|
'remove-workspace': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
13
14
|
'remove-branch': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
15
|
+
'remove-project': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
16
|
+
run_base_url: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
17
|
+
'remove-run-base-url': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
14
18
|
profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
15
19
|
};
|
|
16
20
|
static description: string;
|
|
@@ -38,6 +38,11 @@ export default class ProfileEdit extends BaseCommand {
|
|
|
38
38
|
description: 'Update branch name',
|
|
39
39
|
required: false,
|
|
40
40
|
}),
|
|
41
|
+
project: Flags.string({
|
|
42
|
+
char: 'j',
|
|
43
|
+
description: 'Update project name',
|
|
44
|
+
required: false,
|
|
45
|
+
}),
|
|
41
46
|
'remove-workspace': Flags.boolean({
|
|
42
47
|
description: 'Remove workspace from profile',
|
|
43
48
|
required: false,
|
|
@@ -48,6 +53,21 @@ export default class ProfileEdit extends BaseCommand {
|
|
|
48
53
|
required: false,
|
|
49
54
|
default: false,
|
|
50
55
|
}),
|
|
56
|
+
'remove-project': Flags.boolean({
|
|
57
|
+
description: 'Remove project from profile',
|
|
58
|
+
required: false,
|
|
59
|
+
default: false,
|
|
60
|
+
}),
|
|
61
|
+
run_base_url: Flags.string({
|
|
62
|
+
char: 'r',
|
|
63
|
+
description: 'Update Xano Run API base URL',
|
|
64
|
+
required: false,
|
|
65
|
+
}),
|
|
66
|
+
'remove-run-base-url': Flags.boolean({
|
|
67
|
+
description: 'Remove run_base_url from profile (use default)',
|
|
68
|
+
required: false,
|
|
69
|
+
default: false,
|
|
70
|
+
}),
|
|
51
71
|
};
|
|
52
72
|
static description = 'Edit an existing profile configuration';
|
|
53
73
|
static examples = [
|
|
@@ -65,6 +85,12 @@ Profile 'default' updated successfully at ~/.xano/credentials.yaml
|
|
|
65
85
|
`,
|
|
66
86
|
`$ xano profile:edit --remove-branch
|
|
67
87
|
Profile 'default' updated successfully at ~/.xano/credentials.yaml
|
|
88
|
+
`,
|
|
89
|
+
`$ xano profile:edit -j my-project
|
|
90
|
+
Profile 'default' updated successfully at ~/.xano/credentials.yaml
|
|
91
|
+
`,
|
|
92
|
+
`$ xano profile:edit --remove-project
|
|
93
|
+
Profile 'default' updated successfully at ~/.xano/credentials.yaml
|
|
68
94
|
`,
|
|
69
95
|
];
|
|
70
96
|
async run() {
|
|
@@ -98,7 +124,9 @@ Profile 'default' updated successfully at ~/.xano/credentials.yaml
|
|
|
98
124
|
const existingProfile = credentials.profiles[profileName];
|
|
99
125
|
// Check if any flags were provided
|
|
100
126
|
const hasFlags = flags.account_origin || flags.instance_origin || flags.access_token ||
|
|
101
|
-
flags.workspace || flags.branch || flags
|
|
127
|
+
flags.workspace || flags.branch || flags.project || flags.run_base_url ||
|
|
128
|
+
flags['remove-workspace'] || flags['remove-branch'] || flags['remove-project'] ||
|
|
129
|
+
flags['remove-run-base-url'];
|
|
102
130
|
if (!hasFlags) {
|
|
103
131
|
this.error('No fields specified to update. Use at least one flag to edit the profile.');
|
|
104
132
|
}
|
|
@@ -110,6 +138,8 @@ Profile 'default' updated successfully at ~/.xano/credentials.yaml
|
|
|
110
138
|
...(flags.access_token !== undefined && { access_token: flags.access_token }),
|
|
111
139
|
...(flags.workspace !== undefined && { workspace: flags.workspace }),
|
|
112
140
|
...(flags.branch !== undefined && { branch: flags.branch }),
|
|
141
|
+
...(flags.project !== undefined && { project: flags.project }),
|
|
142
|
+
...(flags.run_base_url !== undefined && { run_base_url: flags.run_base_url }),
|
|
113
143
|
};
|
|
114
144
|
// Handle removal flags
|
|
115
145
|
if (flags['remove-workspace']) {
|
|
@@ -118,6 +148,12 @@ Profile 'default' updated successfully at ~/.xano/credentials.yaml
|
|
|
118
148
|
if (flags['remove-branch']) {
|
|
119
149
|
delete updatedProfile.branch;
|
|
120
150
|
}
|
|
151
|
+
if (flags['remove-project']) {
|
|
152
|
+
delete updatedProfile.project;
|
|
153
|
+
}
|
|
154
|
+
if (flags['remove-run-base-url']) {
|
|
155
|
+
delete updatedProfile.run_base_url;
|
|
156
|
+
}
|
|
121
157
|
credentials.profiles[profileName] = updatedProfile;
|
|
122
158
|
// Write the updated credentials back to the file
|
|
123
159
|
try {
|
|
@@ -30,6 +30,7 @@ Profile: default
|
|
|
30
30
|
Access Token: ***...***
|
|
31
31
|
Workspace: my-workspace
|
|
32
32
|
Branch: main
|
|
33
|
+
Project: my-project
|
|
33
34
|
|
|
34
35
|
Profile: production
|
|
35
36
|
Account Origin: https://account.xano.com
|
|
@@ -45,6 +46,7 @@ Profile: default
|
|
|
45
46
|
Access Token: ***...***
|
|
46
47
|
Workspace: my-workspace
|
|
47
48
|
Branch: main
|
|
49
|
+
Project: my-project
|
|
48
50
|
`,
|
|
49
51
|
];
|
|
50
52
|
async run() {
|
|
@@ -93,6 +95,9 @@ Profile: default
|
|
|
93
95
|
if (profile.branch) {
|
|
94
96
|
this.log(` Branch: ${profile.branch}`);
|
|
95
97
|
}
|
|
98
|
+
if (profile.project) {
|
|
99
|
+
this.log(` Project: ${profile.project}`);
|
|
100
|
+
}
|
|
96
101
|
this.log(''); // Empty line between profiles
|
|
97
102
|
}
|
|
98
103
|
}
|
|
@@ -0,0 +1,54 @@
|
|
|
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 ProfileProject extends Command {
|
|
7
|
+
static description = 'Print the project for the default profile';
|
|
8
|
+
static examples = [
|
|
9
|
+
`$ xano profile:project
|
|
10
|
+
my-project-id
|
|
11
|
+
`,
|
|
12
|
+
`$ xano profile:project | pbcopy
|
|
13
|
+
# Copies the project to clipboard on macOS
|
|
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}. Create a profile first using 'profile:create'.`);
|
|
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 the default profile name
|
|
37
|
+
const defaultProfileName = credentials.default;
|
|
38
|
+
if (!defaultProfileName) {
|
|
39
|
+
this.error("No default profile set. Set one using 'profile:set-default <name>'.");
|
|
40
|
+
}
|
|
41
|
+
// Check if the default profile exists
|
|
42
|
+
if (!(defaultProfileName in credentials.profiles)) {
|
|
43
|
+
this.error(`Default profile '${defaultProfileName}' not found. Available profiles: ${Object.keys(credentials.profiles).join(', ')}`);
|
|
44
|
+
}
|
|
45
|
+
const profile = credentials.profiles[defaultProfileName];
|
|
46
|
+
// Get and display the project
|
|
47
|
+
if (profile.project) {
|
|
48
|
+
this.log(profile.project);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
this.error(`Profile '${defaultProfileName}' does not have a project set. Set one using 'profile:edit -j <project>'.`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
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 ProfileToken extends Command {
|
|
7
|
+
static description = 'Print the access token for the default profile';
|
|
8
|
+
static examples = [
|
|
9
|
+
`$ xano profile:token
|
|
10
|
+
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
|
11
|
+
`,
|
|
12
|
+
`$ xano profile:token | pbcopy
|
|
13
|
+
# Copies the token to clipboard on macOS
|
|
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}. Create a profile first using 'profile:create'.`);
|
|
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 the default profile name
|
|
37
|
+
const defaultProfileName = credentials.default;
|
|
38
|
+
if (!defaultProfileName) {
|
|
39
|
+
this.error("No default profile set. Set one using 'profile:set-default <name>'.");
|
|
40
|
+
}
|
|
41
|
+
// Check if the default profile exists
|
|
42
|
+
if (!(defaultProfileName in credentials.profiles)) {
|
|
43
|
+
this.error(`Default profile '${defaultProfileName}' not found. Available profiles: ${Object.keys(credentials.profiles).join(', ')}`);
|
|
44
|
+
}
|
|
45
|
+
const profile = credentials.profiles[defaultProfileName];
|
|
46
|
+
// Get and display the access token
|
|
47
|
+
if (profile.access_token) {
|
|
48
|
+
this.log(profile.access_token);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
this.error(`Profile '${defaultProfileName}' does not have an access token.`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -96,6 +96,7 @@ Profile 'production' created successfully at ~/.xano/credentials.yaml
|
|
|
96
96
|
// Step 5: Workspace selection
|
|
97
97
|
let workspace;
|
|
98
98
|
let branch;
|
|
99
|
+
let project;
|
|
99
100
|
// Fetch workspaces from the selected instance
|
|
100
101
|
this.log('');
|
|
101
102
|
this.log('Fetching available workspaces...');
|
|
@@ -157,6 +158,37 @@ Profile 'production' created successfully at ~/.xano/credentials.yaml
|
|
|
157
158
|
]);
|
|
158
159
|
branch = selectedBranch || undefined;
|
|
159
160
|
}
|
|
161
|
+
// Step 6: Project selection
|
|
162
|
+
this.log('');
|
|
163
|
+
this.log('Fetching available projects...');
|
|
164
|
+
let projects = [];
|
|
165
|
+
try {
|
|
166
|
+
projects = await this.fetchProjects(accessToken, selectedInstance.origin, workspace, branch);
|
|
167
|
+
}
|
|
168
|
+
catch (error) {
|
|
169
|
+
this.warn(`Failed to fetch projects: ${error instanceof Error ? error.message : String(error)}`);
|
|
170
|
+
}
|
|
171
|
+
// If projects were fetched, let user select one
|
|
172
|
+
if (projects.length > 0) {
|
|
173
|
+
this.log('');
|
|
174
|
+
const { selectedProject } = await inquirer.prompt([
|
|
175
|
+
{
|
|
176
|
+
type: 'list',
|
|
177
|
+
name: 'selectedProject',
|
|
178
|
+
message: 'Select a project',
|
|
179
|
+
choices: [
|
|
180
|
+
{ name: '(Skip project)', value: '' },
|
|
181
|
+
...projects.map((proj) => {
|
|
182
|
+
return {
|
|
183
|
+
name: proj.name,
|
|
184
|
+
value: proj.id,
|
|
185
|
+
};
|
|
186
|
+
}),
|
|
187
|
+
],
|
|
188
|
+
},
|
|
189
|
+
]);
|
|
190
|
+
project = selectedProject || undefined;
|
|
191
|
+
}
|
|
160
192
|
}
|
|
161
193
|
}
|
|
162
194
|
// Save profile
|
|
@@ -167,6 +199,7 @@ Profile 'production' created successfully at ~/.xano/credentials.yaml
|
|
|
167
199
|
access_token: accessToken,
|
|
168
200
|
workspace,
|
|
169
201
|
branch,
|
|
202
|
+
project,
|
|
170
203
|
}, true);
|
|
171
204
|
this.log('');
|
|
172
205
|
this.log(`✓ Profile '${profileName}' created successfully!`);
|
|
@@ -288,6 +321,42 @@ Profile 'production' created successfully at ~/.xano/credentials.yaml
|
|
|
288
321
|
}
|
|
289
322
|
return [];
|
|
290
323
|
}
|
|
324
|
+
async fetchProjects(accessToken, origin, workspaceId, branchId) {
|
|
325
|
+
const branchParam = branchId ? `?branch=${branchId}` : '';
|
|
326
|
+
const response = await fetch(`${origin}/api:meta/workspace/${workspaceId}/project${branchParam}`, {
|
|
327
|
+
method: 'GET',
|
|
328
|
+
headers: {
|
|
329
|
+
accept: 'application/json',
|
|
330
|
+
Authorization: `Bearer ${accessToken}`,
|
|
331
|
+
},
|
|
332
|
+
});
|
|
333
|
+
if (!response.ok) {
|
|
334
|
+
if (response.status === 401) {
|
|
335
|
+
throw new Error('Unauthorized. Please check your access token.');
|
|
336
|
+
}
|
|
337
|
+
throw new Error(`API request failed with status ${response.status}`);
|
|
338
|
+
}
|
|
339
|
+
const data = (await response.json());
|
|
340
|
+
// Transform API response to Project format
|
|
341
|
+
// Assuming the API returns an array or object with projects
|
|
342
|
+
if (Array.isArray(data)) {
|
|
343
|
+
return data.map((proj) => ({
|
|
344
|
+
id: proj.id || proj.name,
|
|
345
|
+
name: proj.name,
|
|
346
|
+
}));
|
|
347
|
+
}
|
|
348
|
+
// If it's an object, try to extract projects
|
|
349
|
+
if (data && typeof data === 'object') {
|
|
350
|
+
const projects = data.projects || data.data || [];
|
|
351
|
+
if (Array.isArray(projects)) {
|
|
352
|
+
return projects.map((proj) => ({
|
|
353
|
+
id: proj.id || proj.name,
|
|
354
|
+
name: proj.name,
|
|
355
|
+
}));
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
return [];
|
|
359
|
+
}
|
|
291
360
|
getDefaultProfileName() {
|
|
292
361
|
try {
|
|
293
362
|
const configDir = path.join(os.homedir(), '.xano');
|
|
@@ -334,6 +403,7 @@ Profile 'production' created successfully at ~/.xano/credentials.yaml
|
|
|
334
403
|
access_token: profile.access_token,
|
|
335
404
|
...(profile.workspace && { workspace: profile.workspace }),
|
|
336
405
|
...(profile.branch && { branch: profile.branch }),
|
|
406
|
+
...(profile.project && { project: profile.project }),
|
|
337
407
|
};
|
|
338
408
|
// Set as default if requested
|
|
339
409
|
if (setAsDefault) {
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import BaseRunCommand from '../../../../lib/base-run-command.js';
|
|
2
|
+
export default class RunEnvDelete extends BaseRunCommand {
|
|
3
|
+
static args: {
|
|
4
|
+
name: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
5
|
+
};
|
|
6
|
+
static flags: {
|
|
7
|
+
force: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
8
|
+
profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
};
|
|
10
|
+
static description: string;
|
|
11
|
+
static examples: string[];
|
|
12
|
+
run(): Promise<void>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { Args, Flags } from '@oclif/core';
|
|
2
|
+
import BaseRunCommand from '../../../../lib/base-run-command.js';
|
|
3
|
+
export default class RunEnvDelete extends BaseRunCommand {
|
|
4
|
+
static args = {
|
|
5
|
+
name: Args.string({
|
|
6
|
+
description: 'Environment variable name',
|
|
7
|
+
required: true,
|
|
8
|
+
}),
|
|
9
|
+
};
|
|
10
|
+
static flags = {
|
|
11
|
+
...BaseRunCommand.baseFlags,
|
|
12
|
+
force: Flags.boolean({
|
|
13
|
+
char: 'f',
|
|
14
|
+
description: 'Skip confirmation prompt',
|
|
15
|
+
required: false,
|
|
16
|
+
default: false,
|
|
17
|
+
}),
|
|
18
|
+
};
|
|
19
|
+
static description = 'Delete an environment variable';
|
|
20
|
+
static examples = [
|
|
21
|
+
`$ xano run env delete API_KEY
|
|
22
|
+
Are you sure you want to delete environment variable 'API_KEY'? (y/N)
|
|
23
|
+
Environment variable 'API_KEY' deleted successfully!
|
|
24
|
+
`,
|
|
25
|
+
`$ xano run env delete API_KEY --force
|
|
26
|
+
Environment variable 'API_KEY' deleted successfully!
|
|
27
|
+
`,
|
|
28
|
+
];
|
|
29
|
+
async run() {
|
|
30
|
+
const { args, flags } = await this.parse(RunEnvDelete);
|
|
31
|
+
// Initialize with project required
|
|
32
|
+
await this.initRunCommandWithProject(flags.profile);
|
|
33
|
+
// Confirm deletion unless --force is used
|
|
34
|
+
if (!flags.force) {
|
|
35
|
+
const readline = await import('node:readline');
|
|
36
|
+
const rl = readline.createInterface({
|
|
37
|
+
input: process.stdin,
|
|
38
|
+
output: process.stdout,
|
|
39
|
+
});
|
|
40
|
+
const confirmed = await new Promise((resolve) => {
|
|
41
|
+
rl.question(`Are you sure you want to delete environment variable '${args.name}'? (y/N) `, (answer) => {
|
|
42
|
+
rl.close();
|
|
43
|
+
resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
if (!confirmed) {
|
|
47
|
+
this.log('Deletion cancelled.');
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
const url = this.httpClient.buildProjectUrl('/env');
|
|
53
|
+
await this.httpClient.delete(url, { name: args.name });
|
|
54
|
+
this.log(`Environment variable '${args.name}' deleted successfully!`);
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
if (error instanceof Error) {
|
|
58
|
+
this.error(`Failed to delete environment variable: ${error.message}`);
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
this.error(`Failed to delete environment variable: ${String(error)}`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import BaseRunCommand from '../../../../lib/base-run-command.js';
|
|
2
|
+
export default class RunEnvGet extends BaseRunCommand {
|
|
3
|
+
static args: {
|
|
4
|
+
name: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
5
|
+
};
|
|
6
|
+
static flags: {
|
|
7
|
+
output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
};
|
|
10
|
+
static description: string;
|
|
11
|
+
static examples: string[];
|
|
12
|
+
run(): Promise<void>;
|
|
13
|
+
}
|