@xano/cli 0.0.37 → 0.0.39
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 +325 -102
- package/dist/commands/auth/index.d.ts +0 -2
- package/dist/commands/auth/index.js +2 -55
- package/dist/commands/profile/create/index.d.ts +0 -2
- package/dist/commands/profile/create/index.js +0 -15
- package/dist/commands/profile/edit/index.d.ts +0 -4
- package/dist/commands/profile/edit/index.js +7 -38
- package/dist/commands/profile/wizard/index.d.ts +0 -2
- package/dist/commands/profile/wizard/index.js +0 -106
- package/dist/commands/profile/{project → workspace}/index.d.ts +1 -1
- package/dist/commands/profile/{project → workspace}/index.js +10 -10
- package/dist/commands/release/delete/index.d.ts +2 -4
- package/dist/commands/release/delete/index.js +39 -12
- package/dist/commands/release/edit/index.d.ts +2 -4
- package/dist/commands/release/edit/index.js +31 -5
- package/dist/commands/release/export/index.d.ts +2 -4
- package/dist/commands/release/export/index.js +39 -11
- package/dist/commands/release/get/index.d.ts +2 -4
- package/dist/commands/release/get/index.js +31 -5
- package/dist/commands/release/pull/index.d.ts +31 -0
- package/dist/commands/release/pull/index.js +345 -0
- package/dist/commands/release/push/index.d.ts +26 -0
- package/dist/commands/release/push/index.js +230 -0
- package/dist/commands/tenant/backup/delete/index.d.ts +1 -1
- package/dist/commands/tenant/backup/delete/index.js +8 -9
- package/dist/commands/tenant/backup/export/index.d.ts +1 -1
- package/dist/commands/tenant/backup/export/index.js +9 -10
- package/dist/commands/tenant/backup/restore/index.d.ts +1 -1
- package/dist/commands/tenant/backup/restore/index.js +8 -9
- package/dist/commands/tenant/cluster/create/index.d.ts +18 -0
- package/dist/commands/tenant/cluster/create/index.js +149 -0
- package/dist/commands/{run/sessions/start → tenant/cluster/delete}/index.d.ts +9 -3
- package/dist/commands/tenant/cluster/delete/index.js +125 -0
- package/dist/commands/tenant/cluster/edit/index.d.ts +22 -0
- package/dist/commands/tenant/cluster/edit/index.js +128 -0
- package/dist/commands/{run/sessions → tenant/cluster}/get/index.d.ts +7 -3
- package/dist/commands/tenant/cluster/get/index.js +114 -0
- package/dist/commands/{run/info → tenant/cluster/license/get}/index.d.ts +10 -7
- package/dist/commands/tenant/cluster/license/get/index.js +118 -0
- package/dist/commands/tenant/cluster/license/set/index.d.ts +21 -0
- package/dist/commands/tenant/cluster/license/set/index.js +132 -0
- package/dist/commands/{run/env → tenant/cluster}/list/index.d.ts +3 -3
- package/dist/commands/tenant/cluster/list/index.js +109 -0
- package/dist/commands/tenant/create/index.d.ts +6 -3
- package/dist/commands/tenant/create/index.js +28 -20
- package/dist/commands/tenant/deploy_platform/index.d.ts +1 -1
- package/dist/commands/tenant/deploy_platform/index.js +8 -9
- package/dist/commands/tenant/deploy_release/index.d.ts +1 -1
- package/dist/commands/tenant/deploy_release/index.js +8 -9
- package/dist/commands/tenant/env/delete/index.d.ts +19 -0
- package/dist/commands/tenant/env/delete/index.js +139 -0
- package/dist/commands/{run/projects/create → tenant/env/get}/index.d.ts +7 -4
- package/dist/commands/tenant/env/get/index.js +113 -0
- package/dist/commands/{run/projects/update → tenant/env/get_all}/index.d.ts +7 -5
- package/dist/commands/tenant/env/get_all/index.js +123 -0
- package/dist/commands/{run/secrets/get → tenant/env/list}/index.d.ts +5 -3
- package/dist/commands/tenant/env/list/index.js +116 -0
- package/dist/commands/tenant/env/set/index.d.ts +18 -0
- package/dist/commands/tenant/env/set/index.js +122 -0
- package/dist/commands/tenant/env/set_all/index.d.ts +18 -0
- package/dist/commands/tenant/env/set_all/index.js +131 -0
- package/dist/commands/tenant/get/index.js +6 -5
- package/dist/commands/tenant/impersonate/index.d.ts +19 -0
- package/dist/commands/tenant/impersonate/index.js +146 -0
- package/dist/commands/tenant/license/get/index.d.ts +18 -0
- package/dist/commands/tenant/license/get/index.js +127 -0
- package/dist/commands/tenant/license/set/index.d.ts +19 -0
- package/dist/commands/tenant/license/set/index.js +141 -0
- package/dist/commands/tenant/list/index.js +6 -6
- package/dist/commands/tenant/pull/index.d.ts +31 -0
- package/dist/commands/tenant/pull/index.js +327 -0
- package/dist/commands/tenant/push/index.d.ts +24 -0
- package/dist/commands/tenant/push/index.js +245 -0
- package/oclif.manifest.json +2218 -1813
- package/package.json +1 -19
- package/dist/commands/run/env/delete/index.d.ts +0 -14
- package/dist/commands/run/env/delete/index.js +0 -65
- package/dist/commands/run/env/get/index.d.ts +0 -14
- package/dist/commands/run/env/get/index.js +0 -52
- package/dist/commands/run/env/list/index.js +0 -56
- package/dist/commands/run/env/set/index.d.ts +0 -14
- package/dist/commands/run/env/set/index.js +0 -51
- package/dist/commands/run/exec/index.d.ts +0 -31
- package/dist/commands/run/exec/index.js +0 -431
- package/dist/commands/run/info/index.js +0 -160
- package/dist/commands/run/projects/create/index.js +0 -75
- package/dist/commands/run/projects/delete/index.d.ts +0 -14
- package/dist/commands/run/projects/delete/index.js +0 -65
- package/dist/commands/run/projects/list/index.d.ts +0 -13
- package/dist/commands/run/projects/list/index.js +0 -66
- package/dist/commands/run/projects/update/index.js +0 -86
- package/dist/commands/run/secrets/delete/index.d.ts +0 -14
- package/dist/commands/run/secrets/delete/index.js +0 -65
- package/dist/commands/run/secrets/get/index.js +0 -52
- package/dist/commands/run/secrets/list/index.d.ts +0 -12
- package/dist/commands/run/secrets/list/index.js +0 -60
- package/dist/commands/run/secrets/set/index.d.ts +0 -16
- package/dist/commands/run/secrets/set/index.js +0 -74
- package/dist/commands/run/sessions/delete/index.d.ts +0 -14
- package/dist/commands/run/sessions/delete/index.js +0 -65
- package/dist/commands/run/sessions/get/index.js +0 -72
- package/dist/commands/run/sessions/list/index.d.ts +0 -13
- package/dist/commands/run/sessions/list/index.js +0 -64
- package/dist/commands/run/sessions/start/index.js +0 -56
- package/dist/commands/run/sessions/stop/index.d.ts +0 -14
- package/dist/commands/run/sessions/stop/index.js +0 -56
- package/dist/commands/run/sink/get/index.d.ts +0 -14
- package/dist/commands/run/sink/get/index.js +0 -63
- package/dist/lib/base-run-command.d.ts +0 -41
- package/dist/lib/base-run-command.js +0 -75
- package/dist/lib/run-http-client.d.ts +0 -64
- package/dist/lib/run-http-client.js +0 -171
- package/dist/lib/run-types.d.ts +0 -226
- package/dist/lib/run-types.js +0 -5
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { Args, Flags } from '@oclif/core';
|
|
2
|
+
import * as yaml from 'js-yaml';
|
|
3
|
+
import * as fs from 'node:fs';
|
|
4
|
+
import * as os from 'node:os';
|
|
5
|
+
import * as path from 'node:path';
|
|
6
|
+
import BaseCommand from '../../../../../base-command.js';
|
|
7
|
+
export default class TenantClusterLicenseSet extends BaseCommand {
|
|
8
|
+
static args = {
|
|
9
|
+
cluster_id: Args.integer({
|
|
10
|
+
description: 'Tenant cluster ID',
|
|
11
|
+
required: true,
|
|
12
|
+
}),
|
|
13
|
+
};
|
|
14
|
+
static description = 'Set/update the license (kubeconfig) for a tenant cluster';
|
|
15
|
+
static examples = [
|
|
16
|
+
`$ xano tenant cluster license set 1
|
|
17
|
+
Reads from kubeconfig-1.yaml
|
|
18
|
+
`,
|
|
19
|
+
`$ xano tenant cluster license set 1 --file ./kubeconfig.yaml`,
|
|
20
|
+
`$ xano tenant cluster license set 1 --value 'apiVersion: v1...'`,
|
|
21
|
+
`$ xano tenant cluster license set 1 -o json`,
|
|
22
|
+
];
|
|
23
|
+
static flags = {
|
|
24
|
+
...BaseCommand.baseFlags,
|
|
25
|
+
clean: Flags.boolean({
|
|
26
|
+
default: false,
|
|
27
|
+
description: 'Remove the source file after successful upload',
|
|
28
|
+
exclusive: ['value'],
|
|
29
|
+
required: false,
|
|
30
|
+
}),
|
|
31
|
+
file: Flags.string({
|
|
32
|
+
char: 'f',
|
|
33
|
+
description: 'Path to kubeconfig file (default: kubeconfig_<cluster_id>.yaml)',
|
|
34
|
+
exclusive: ['value'],
|
|
35
|
+
required: false,
|
|
36
|
+
}),
|
|
37
|
+
output: Flags.string({
|
|
38
|
+
char: 'o',
|
|
39
|
+
default: 'summary',
|
|
40
|
+
description: 'Output format',
|
|
41
|
+
options: ['summary', 'json'],
|
|
42
|
+
required: false,
|
|
43
|
+
}),
|
|
44
|
+
value: Flags.string({
|
|
45
|
+
description: 'Inline kubeconfig YAML value',
|
|
46
|
+
exclusive: ['file', 'clean'],
|
|
47
|
+
required: false,
|
|
48
|
+
}),
|
|
49
|
+
};
|
|
50
|
+
async run() {
|
|
51
|
+
const { args, flags } = await this.parse(TenantClusterLicenseSet);
|
|
52
|
+
const clusterId = args.cluster_id;
|
|
53
|
+
let licenseValue;
|
|
54
|
+
let sourceFilePath;
|
|
55
|
+
if (flags.value) {
|
|
56
|
+
licenseValue = flags.value;
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
sourceFilePath = path.resolve(flags.file || `kubeconfig_${clusterId}.yaml`);
|
|
60
|
+
if (!fs.existsSync(sourceFilePath)) {
|
|
61
|
+
this.error(`File not found: ${sourceFilePath}`);
|
|
62
|
+
}
|
|
63
|
+
licenseValue = fs.readFileSync(sourceFilePath, 'utf8');
|
|
64
|
+
}
|
|
65
|
+
const profileName = flags.profile || this.getDefaultProfile();
|
|
66
|
+
const credentials = this.loadCredentials();
|
|
67
|
+
if (!(profileName in credentials.profiles)) {
|
|
68
|
+
this.error(`Profile '${profileName}' not found. Available profiles: ${Object.keys(credentials.profiles).join(', ')}\n` +
|
|
69
|
+
`Create a profile using 'xano profile create'`);
|
|
70
|
+
}
|
|
71
|
+
const profile = credentials.profiles[profileName];
|
|
72
|
+
if (!profile.instance_origin) {
|
|
73
|
+
this.error(`Profile '${profileName}' is missing instance_origin`);
|
|
74
|
+
}
|
|
75
|
+
if (!profile.access_token) {
|
|
76
|
+
this.error(`Profile '${profileName}' is missing access_token`);
|
|
77
|
+
}
|
|
78
|
+
const apiUrl = `${profile.instance_origin}/api:meta/tenant/cluster/${clusterId}/license`;
|
|
79
|
+
try {
|
|
80
|
+
const response = await this.verboseFetch(apiUrl, {
|
|
81
|
+
body: JSON.stringify({ value: licenseValue }),
|
|
82
|
+
headers: {
|
|
83
|
+
accept: 'application/json',
|
|
84
|
+
Authorization: `Bearer ${profile.access_token}`,
|
|
85
|
+
'Content-Type': 'application/json',
|
|
86
|
+
},
|
|
87
|
+
method: 'POST',
|
|
88
|
+
}, flags.verbose, profile.access_token);
|
|
89
|
+
if (!response.ok) {
|
|
90
|
+
const errorText = await response.text();
|
|
91
|
+
this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
|
|
92
|
+
}
|
|
93
|
+
const result = await response.json();
|
|
94
|
+
if (flags.output === 'json') {
|
|
95
|
+
this.log(JSON.stringify(result, null, 2));
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
this.log(`Tenant cluster license updated successfully for cluster ${clusterId}`);
|
|
99
|
+
}
|
|
100
|
+
if (flags.clean && sourceFilePath && fs.existsSync(sourceFilePath)) {
|
|
101
|
+
fs.unlinkSync(sourceFilePath);
|
|
102
|
+
this.log(`Removed ${sourceFilePath}`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
if (error instanceof Error) {
|
|
107
|
+
this.error(`Failed to set tenant cluster license: ${error.message}`);
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
this.error(`Failed to set tenant cluster license: ${String(error)}`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
loadCredentials() {
|
|
115
|
+
const configDir = path.join(os.homedir(), '.xano');
|
|
116
|
+
const credentialsPath = path.join(configDir, 'credentials.yaml');
|
|
117
|
+
if (!fs.existsSync(credentialsPath)) {
|
|
118
|
+
this.error(`Credentials file not found at ${credentialsPath}\n` + `Create a profile using 'xano profile create'`);
|
|
119
|
+
}
|
|
120
|
+
try {
|
|
121
|
+
const fileContent = fs.readFileSync(credentialsPath, 'utf8');
|
|
122
|
+
const parsed = yaml.load(fileContent);
|
|
123
|
+
if (!parsed || typeof parsed !== 'object' || !('profiles' in parsed)) {
|
|
124
|
+
this.error('Credentials file has invalid format.');
|
|
125
|
+
}
|
|
126
|
+
return parsed;
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
this.error(`Failed to parse credentials file: ${error}`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
export default class
|
|
3
|
-
static args: {};
|
|
1
|
+
import BaseCommand from '../../../../base-command.js';
|
|
2
|
+
export default class TenantClusterList extends BaseCommand {
|
|
4
3
|
static description: string;
|
|
5
4
|
static examples: string[];
|
|
6
5
|
static flags: {
|
|
@@ -9,4 +8,5 @@ export default class RunEnvList extends BaseRunCommand {
|
|
|
9
8
|
verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
10
9
|
};
|
|
11
10
|
run(): Promise<void>;
|
|
11
|
+
private loadCredentials;
|
|
12
12
|
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { Flags } from '@oclif/core';
|
|
2
|
+
import * as yaml from 'js-yaml';
|
|
3
|
+
import * as fs from 'node:fs';
|
|
4
|
+
import * as os from 'node:os';
|
|
5
|
+
import * as path from 'node:path';
|
|
6
|
+
import BaseCommand from '../../../../base-command.js';
|
|
7
|
+
export default class TenantClusterList extends BaseCommand {
|
|
8
|
+
static description = 'List all tenant clusters';
|
|
9
|
+
static examples = [
|
|
10
|
+
`$ xano tenant cluster list
|
|
11
|
+
Tenant clusters:
|
|
12
|
+
- us-east-1 (standard) [ID: 1]
|
|
13
|
+
- eu-west-1 (run) [ID: 2]
|
|
14
|
+
`,
|
|
15
|
+
`$ xano tenant cluster list --output json`,
|
|
16
|
+
];
|
|
17
|
+
static flags = {
|
|
18
|
+
...BaseCommand.baseFlags,
|
|
19
|
+
output: Flags.string({
|
|
20
|
+
char: 'o',
|
|
21
|
+
default: 'summary',
|
|
22
|
+
description: 'Output format',
|
|
23
|
+
options: ['summary', 'json'],
|
|
24
|
+
required: false,
|
|
25
|
+
}),
|
|
26
|
+
};
|
|
27
|
+
async run() {
|
|
28
|
+
const { flags } = await this.parse(TenantClusterList);
|
|
29
|
+
const profileName = flags.profile || this.getDefaultProfile();
|
|
30
|
+
const credentials = this.loadCredentials();
|
|
31
|
+
if (!(profileName in credentials.profiles)) {
|
|
32
|
+
this.error(`Profile '${profileName}' not found. Available profiles: ${Object.keys(credentials.profiles).join(', ')}\n` +
|
|
33
|
+
`Create a profile using 'xano profile create'`);
|
|
34
|
+
}
|
|
35
|
+
const profile = credentials.profiles[profileName];
|
|
36
|
+
if (!profile.instance_origin) {
|
|
37
|
+
this.error(`Profile '${profileName}' is missing instance_origin`);
|
|
38
|
+
}
|
|
39
|
+
if (!profile.access_token) {
|
|
40
|
+
this.error(`Profile '${profileName}' is missing access_token`);
|
|
41
|
+
}
|
|
42
|
+
const apiUrl = `${profile.instance_origin}/api:meta/tenant/cluster`;
|
|
43
|
+
try {
|
|
44
|
+
const response = await this.verboseFetch(apiUrl, {
|
|
45
|
+
headers: {
|
|
46
|
+
accept: 'application/json',
|
|
47
|
+
Authorization: `Bearer ${profile.access_token}`,
|
|
48
|
+
},
|
|
49
|
+
method: 'GET',
|
|
50
|
+
}, flags.verbose, profile.access_token);
|
|
51
|
+
if (!response.ok) {
|
|
52
|
+
const errorText = await response.text();
|
|
53
|
+
this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
|
|
54
|
+
}
|
|
55
|
+
const data = (await response.json());
|
|
56
|
+
let clusters;
|
|
57
|
+
if (Array.isArray(data)) {
|
|
58
|
+
clusters = data;
|
|
59
|
+
}
|
|
60
|
+
else if (data && typeof data === 'object' && 'items' in data && Array.isArray(data.items)) {
|
|
61
|
+
clusters = data.items;
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
this.error('Unexpected API response format');
|
|
65
|
+
}
|
|
66
|
+
if (flags.output === 'json') {
|
|
67
|
+
this.log(JSON.stringify(clusters, null, 2));
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
if (clusters.length === 0) {
|
|
71
|
+
this.log('No tenant clusters found');
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
this.log('Tenant clusters:');
|
|
75
|
+
for (const cluster of clusters) {
|
|
76
|
+
const type = cluster.type ? ` (${cluster.type})` : '';
|
|
77
|
+
this.log(` - ${cluster.name}${type} [ID: ${cluster.id}]`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
if (error instanceof Error) {
|
|
84
|
+
this.error(`Failed to list tenant clusters: ${error.message}`);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
this.error(`Failed to list tenant clusters: ${String(error)}`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
loadCredentials() {
|
|
92
|
+
const configDir = path.join(os.homedir(), '.xano');
|
|
93
|
+
const credentialsPath = path.join(configDir, 'credentials.yaml');
|
|
94
|
+
if (!fs.existsSync(credentialsPath)) {
|
|
95
|
+
this.error(`Credentials file not found at ${credentialsPath}\n` + `Create a profile using 'xano profile create'`);
|
|
96
|
+
}
|
|
97
|
+
try {
|
|
98
|
+
const fileContent = fs.readFileSync(credentialsPath, 'utf8');
|
|
99
|
+
const parsed = yaml.load(fileContent);
|
|
100
|
+
if (!parsed || typeof parsed !== 'object' || !('profiles' in parsed)) {
|
|
101
|
+
this.error('Credentials file has invalid format.');
|
|
102
|
+
}
|
|
103
|
+
return parsed;
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
this.error(`Failed to parse credentials file: ${error}`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
import BaseCommand from '../../../base-command.js';
|
|
2
2
|
export default class TenantCreate extends BaseCommand {
|
|
3
|
+
static args: {
|
|
4
|
+
display: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
5
|
+
};
|
|
3
6
|
static description: string;
|
|
4
7
|
static examples: string[];
|
|
5
8
|
static flags: {
|
|
6
|
-
|
|
9
|
+
cluster_id: import("@oclif/core/interfaces").OptionFlag<number | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
10
|
description: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
-
display: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
11
|
domain: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
ephemeral: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
10
13
|
ingress: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
11
14
|
license: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
15
|
output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
|
-
|
|
16
|
+
platform_id: import("@oclif/core/interfaces").OptionFlag<number | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
14
17
|
tasks: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
15
18
|
workspace: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
16
19
|
profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
@@ -1,20 +1,26 @@
|
|
|
1
|
-
import { Flags } from '@oclif/core';
|
|
1
|
+
import { Args, Flags } from '@oclif/core';
|
|
2
2
|
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
6
|
import BaseCommand from '../../../base-command.js';
|
|
7
7
|
export default class TenantCreate extends BaseCommand {
|
|
8
|
+
static args = {
|
|
9
|
+
display: Args.string({
|
|
10
|
+
description: 'Display name for the tenant',
|
|
11
|
+
required: true,
|
|
12
|
+
}),
|
|
13
|
+
};
|
|
8
14
|
static description = 'Create a new tenant in a workspace';
|
|
9
15
|
static examples = [
|
|
10
|
-
`$ xano tenant create
|
|
16
|
+
`$ xano tenant create "Production"
|
|
11
17
|
Created tenant: Production (production) - ID: 42
|
|
12
18
|
`,
|
|
13
|
-
`$ xano tenant create
|
|
19
|
+
`$ xano tenant create "Staging" --description "Staging env" --cluster_id 1 --platform_id 1 --license tier2 -o json`,
|
|
14
20
|
];
|
|
15
21
|
static flags = {
|
|
16
22
|
...BaseCommand.baseFlags,
|
|
17
|
-
|
|
23
|
+
cluster_id: Flags.integer({
|
|
18
24
|
description: 'Cluster ID to deploy to (required for tier2/tier3)',
|
|
19
25
|
required: false,
|
|
20
26
|
}),
|
|
@@ -23,14 +29,14 @@ Created tenant: Production (production) - ID: 42
|
|
|
23
29
|
description: 'Tenant description',
|
|
24
30
|
required: false,
|
|
25
31
|
}),
|
|
26
|
-
display: Flags.string({
|
|
27
|
-
description: 'Display name for the tenant',
|
|
28
|
-
required: true,
|
|
29
|
-
}),
|
|
30
32
|
domain: Flags.string({
|
|
31
33
|
description: 'Custom domain for the tenant',
|
|
32
34
|
required: false,
|
|
33
35
|
}),
|
|
36
|
+
ephemeral: Flags.boolean({
|
|
37
|
+
default: false,
|
|
38
|
+
description: 'Mark tenant as ephemeral (allows push operations)',
|
|
39
|
+
}),
|
|
34
40
|
ingress: Flags.boolean({
|
|
35
41
|
allowNo: true,
|
|
36
42
|
default: true,
|
|
@@ -49,7 +55,7 @@ Created tenant: Production (production) - ID: 42
|
|
|
49
55
|
options: ['summary', 'json'],
|
|
50
56
|
required: false,
|
|
51
57
|
}),
|
|
52
|
-
|
|
58
|
+
platform_id: Flags.integer({
|
|
53
59
|
description: 'Platform ID to use',
|
|
54
60
|
required: false,
|
|
55
61
|
}),
|
|
@@ -65,7 +71,7 @@ Created tenant: Production (production) - ID: 42
|
|
|
65
71
|
}),
|
|
66
72
|
};
|
|
67
73
|
async run() {
|
|
68
|
-
const { flags } = await this.parse(TenantCreate);
|
|
74
|
+
const { args, flags } = await this.parse(TenantCreate);
|
|
69
75
|
const profileName = flags.profile || this.getDefaultProfile();
|
|
70
76
|
const credentials = this.loadCredentials();
|
|
71
77
|
if (!(profileName in credentials.profiles)) {
|
|
@@ -84,7 +90,8 @@ Created tenant: Production (production) - ID: 42
|
|
|
84
90
|
this.error('No workspace ID provided. Use --workspace flag or set one in your profile.');
|
|
85
91
|
}
|
|
86
92
|
const body = {
|
|
87
|
-
display:
|
|
93
|
+
display: args.display,
|
|
94
|
+
ephemeral: flags.ephemeral,
|
|
88
95
|
ingress: flags.ingress,
|
|
89
96
|
license: flags.license,
|
|
90
97
|
tag: [],
|
|
@@ -92,10 +99,12 @@ Created tenant: Production (production) - ID: 42
|
|
|
92
99
|
};
|
|
93
100
|
if (flags.description)
|
|
94
101
|
body.description = flags.description;
|
|
95
|
-
if (flags
|
|
96
|
-
body.cluster_id = flags
|
|
97
|
-
|
|
98
|
-
|
|
102
|
+
if (flags.cluster_id) {
|
|
103
|
+
body.cluster_id = flags.cluster_id;
|
|
104
|
+
body.license = 'tier3';
|
|
105
|
+
}
|
|
106
|
+
if (flags.platform_id)
|
|
107
|
+
body.platform_id = flags.platform_id;
|
|
99
108
|
if (flags.domain)
|
|
100
109
|
body.domain = flags.domain;
|
|
101
110
|
const apiUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}/tenant`;
|
|
@@ -103,8 +112,8 @@ Created tenant: Production (production) - ID: 42
|
|
|
103
112
|
const response = await this.verboseFetch(apiUrl, {
|
|
104
113
|
body: JSON.stringify(body),
|
|
105
114
|
headers: {
|
|
106
|
-
|
|
107
|
-
|
|
115
|
+
accept: 'application/json',
|
|
116
|
+
Authorization: `Bearer ${profile.access_token}`,
|
|
108
117
|
'Content-Type': 'application/json',
|
|
109
118
|
},
|
|
110
119
|
method: 'POST',
|
|
@@ -113,7 +122,7 @@ Created tenant: Production (production) - ID: 42
|
|
|
113
122
|
const errorText = await response.text();
|
|
114
123
|
this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
|
|
115
124
|
}
|
|
116
|
-
const tenant = await response.json();
|
|
125
|
+
const tenant = (await response.json());
|
|
117
126
|
if (flags.output === 'json') {
|
|
118
127
|
this.log(JSON.stringify(tenant, null, 2));
|
|
119
128
|
}
|
|
@@ -137,8 +146,7 @@ Created tenant: Production (production) - ID: 42
|
|
|
137
146
|
const configDir = path.join(os.homedir(), '.xano');
|
|
138
147
|
const credentialsPath = path.join(configDir, 'credentials.yaml');
|
|
139
148
|
if (!fs.existsSync(credentialsPath)) {
|
|
140
|
-
this.error(`Credentials file not found at ${credentialsPath}\n` +
|
|
141
|
-
`Create a profile using 'xano profile create'`);
|
|
149
|
+
this.error(`Credentials file not found at ${credentialsPath}\n` + `Create a profile using 'xano profile create'`);
|
|
142
150
|
}
|
|
143
151
|
try {
|
|
144
152
|
const fileContent = fs.readFileSync(credentialsPath, 'utf8');
|
|
@@ -7,7 +7,7 @@ export default class TenantDeployPlatform extends BaseCommand {
|
|
|
7
7
|
static examples: string[];
|
|
8
8
|
static flags: {
|
|
9
9
|
output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
-
|
|
10
|
+
platform_id: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
11
|
workspace: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
12
|
profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
13
|
verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
@@ -13,10 +13,10 @@ export default class TenantDeployPlatform extends BaseCommand {
|
|
|
13
13
|
};
|
|
14
14
|
static description = 'Deploy a platform version to a tenant';
|
|
15
15
|
static examples = [
|
|
16
|
-
`$ xano tenant
|
|
16
|
+
`$ xano tenant deploy_platform t1234-abcd-xyz1 --platform_id 5
|
|
17
17
|
Deployed platform 5 to tenant: My Tenant (my-tenant)
|
|
18
18
|
`,
|
|
19
|
-
`$ xano tenant
|
|
19
|
+
`$ xano tenant deploy_platform t1234-abcd-xyz1 --platform_id 5 -o json`,
|
|
20
20
|
];
|
|
21
21
|
static flags = {
|
|
22
22
|
...BaseCommand.baseFlags,
|
|
@@ -27,7 +27,7 @@ Deployed platform 5 to tenant: My Tenant (my-tenant)
|
|
|
27
27
|
options: ['summary', 'json'],
|
|
28
28
|
required: false,
|
|
29
29
|
}),
|
|
30
|
-
|
|
30
|
+
platform_id: Flags.integer({
|
|
31
31
|
description: 'Platform ID to deploy',
|
|
32
32
|
required: true,
|
|
33
33
|
}),
|
|
@@ -57,14 +57,14 @@ Deployed platform 5 to tenant: My Tenant (my-tenant)
|
|
|
57
57
|
this.error('No workspace ID provided. Use --workspace flag or set one in your profile.');
|
|
58
58
|
}
|
|
59
59
|
const tenantName = args.tenant_name;
|
|
60
|
-
const platformId = flags
|
|
60
|
+
const platformId = flags.platform_id;
|
|
61
61
|
const apiUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}/tenant/${tenantName}/platform/deploy`;
|
|
62
62
|
try {
|
|
63
63
|
const response = await this.verboseFetch(apiUrl, {
|
|
64
64
|
body: JSON.stringify({ platform_id: platformId }),
|
|
65
65
|
headers: {
|
|
66
|
-
|
|
67
|
-
|
|
66
|
+
accept: 'application/json',
|
|
67
|
+
Authorization: `Bearer ${profile.access_token}`,
|
|
68
68
|
'Content-Type': 'application/json',
|
|
69
69
|
},
|
|
70
70
|
method: 'POST',
|
|
@@ -73,7 +73,7 @@ Deployed platform 5 to tenant: My Tenant (my-tenant)
|
|
|
73
73
|
const errorText = await response.text();
|
|
74
74
|
this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
|
|
75
75
|
}
|
|
76
|
-
const tenant = await response.json();
|
|
76
|
+
const tenant = (await response.json());
|
|
77
77
|
if (flags.output === 'json') {
|
|
78
78
|
this.log(JSON.stringify(tenant, null, 2));
|
|
79
79
|
}
|
|
@@ -98,8 +98,7 @@ Deployed platform 5 to tenant: My Tenant (my-tenant)
|
|
|
98
98
|
const configDir = path.join(os.homedir(), '.xano');
|
|
99
99
|
const credentialsPath = path.join(configDir, 'credentials.yaml');
|
|
100
100
|
if (!fs.existsSync(credentialsPath)) {
|
|
101
|
-
this.error(`Credentials file not found at ${credentialsPath}\n` +
|
|
102
|
-
`Create a profile using 'xano profile create'`);
|
|
101
|
+
this.error(`Credentials file not found at ${credentialsPath}\n` + `Create a profile using 'xano profile create'`);
|
|
103
102
|
}
|
|
104
103
|
try {
|
|
105
104
|
const fileContent = fs.readFileSync(credentialsPath, 'utf8');
|
|
@@ -7,7 +7,7 @@ export default class TenantDeployRelease extends BaseCommand {
|
|
|
7
7
|
static examples: string[];
|
|
8
8
|
static flags: {
|
|
9
9
|
output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
-
|
|
10
|
+
release_id: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
11
|
workspace: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
12
|
profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
13
|
verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
@@ -13,10 +13,10 @@ export default class TenantDeployRelease extends BaseCommand {
|
|
|
13
13
|
};
|
|
14
14
|
static description = 'Deploy a release to a tenant';
|
|
15
15
|
static examples = [
|
|
16
|
-
`$ xano tenant
|
|
16
|
+
`$ xano tenant deploy_release t1234-abcd-xyz1 --release_id 10
|
|
17
17
|
Deployed release 10 to tenant: My Tenant (my-tenant)
|
|
18
18
|
`,
|
|
19
|
-
`$ xano tenant
|
|
19
|
+
`$ xano tenant deploy_release t1234-abcd-xyz1 --release_id 10 -o json`,
|
|
20
20
|
];
|
|
21
21
|
static flags = {
|
|
22
22
|
...BaseCommand.baseFlags,
|
|
@@ -27,7 +27,7 @@ Deployed release 10 to tenant: My Tenant (my-tenant)
|
|
|
27
27
|
options: ['summary', 'json'],
|
|
28
28
|
required: false,
|
|
29
29
|
}),
|
|
30
|
-
|
|
30
|
+
release_id: Flags.integer({
|
|
31
31
|
description: 'Release ID to deploy',
|
|
32
32
|
required: true,
|
|
33
33
|
}),
|
|
@@ -57,14 +57,14 @@ Deployed release 10 to tenant: My Tenant (my-tenant)
|
|
|
57
57
|
this.error('No workspace ID provided. Use --workspace flag or set one in your profile.');
|
|
58
58
|
}
|
|
59
59
|
const tenantName = args.tenant_name;
|
|
60
|
-
const releaseId = flags
|
|
60
|
+
const releaseId = flags.release_id;
|
|
61
61
|
const apiUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}/tenant/${tenantName}/deploy`;
|
|
62
62
|
try {
|
|
63
63
|
const response = await this.verboseFetch(apiUrl, {
|
|
64
64
|
body: JSON.stringify({ release_id: releaseId }),
|
|
65
65
|
headers: {
|
|
66
|
-
|
|
67
|
-
|
|
66
|
+
accept: 'application/json',
|
|
67
|
+
Authorization: `Bearer ${profile.access_token}`,
|
|
68
68
|
'Content-Type': 'application/json',
|
|
69
69
|
},
|
|
70
70
|
method: 'POST',
|
|
@@ -73,7 +73,7 @@ Deployed release 10 to tenant: My Tenant (my-tenant)
|
|
|
73
73
|
const errorText = await response.text();
|
|
74
74
|
this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
|
|
75
75
|
}
|
|
76
|
-
const tenant = await response.json();
|
|
76
|
+
const tenant = (await response.json());
|
|
77
77
|
if (flags.output === 'json') {
|
|
78
78
|
this.log(JSON.stringify(tenant, null, 2));
|
|
79
79
|
}
|
|
@@ -98,8 +98,7 @@ Deployed release 10 to tenant: My Tenant (my-tenant)
|
|
|
98
98
|
const configDir = path.join(os.homedir(), '.xano');
|
|
99
99
|
const credentialsPath = path.join(configDir, 'credentials.yaml');
|
|
100
100
|
if (!fs.existsSync(credentialsPath)) {
|
|
101
|
-
this.error(`Credentials file not found at ${credentialsPath}\n` +
|
|
102
|
-
`Create a profile using 'xano profile create'`);
|
|
101
|
+
this.error(`Credentials file not found at ${credentialsPath}\n` + `Create a profile using 'xano profile create'`);
|
|
103
102
|
}
|
|
104
103
|
try {
|
|
105
104
|
const fileContent = fs.readFileSync(credentialsPath, 'utf8');
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import BaseCommand from '../../../../base-command.js';
|
|
2
|
+
export default class TenantEnvDelete extends BaseCommand {
|
|
3
|
+
static args: {
|
|
4
|
+
tenant_name: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
5
|
+
};
|
|
6
|
+
static description: string;
|
|
7
|
+
static examples: string[];
|
|
8
|
+
static flags: {
|
|
9
|
+
force: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
10
|
+
name: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
workspace: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
|
+
profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
14
|
+
verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
15
|
+
};
|
|
16
|
+
run(): Promise<void>;
|
|
17
|
+
private confirm;
|
|
18
|
+
private loadCredentials;
|
|
19
|
+
}
|