@xano/cli 0.0.36 → 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.
Files changed (115) hide show
  1. package/README.md +325 -102
  2. package/dist/commands/auth/index.d.ts +0 -2
  3. package/dist/commands/auth/index.js +2 -55
  4. package/dist/commands/profile/create/index.d.ts +0 -2
  5. package/dist/commands/profile/create/index.js +0 -15
  6. package/dist/commands/profile/edit/index.d.ts +0 -4
  7. package/dist/commands/profile/edit/index.js +7 -38
  8. package/dist/commands/profile/wizard/index.d.ts +0 -2
  9. package/dist/commands/profile/wizard/index.js +0 -106
  10. package/dist/commands/profile/{project → workspace}/index.d.ts +1 -1
  11. package/dist/commands/profile/{project → workspace}/index.js +10 -10
  12. package/dist/commands/release/delete/index.d.ts +2 -4
  13. package/dist/commands/release/delete/index.js +39 -12
  14. package/dist/commands/release/edit/index.d.ts +2 -4
  15. package/dist/commands/release/edit/index.js +31 -5
  16. package/dist/commands/release/export/index.d.ts +2 -4
  17. package/dist/commands/release/export/index.js +39 -11
  18. package/dist/commands/release/get/index.d.ts +2 -4
  19. package/dist/commands/release/get/index.js +31 -5
  20. package/dist/commands/release/pull/index.d.ts +31 -0
  21. package/dist/commands/release/pull/index.js +345 -0
  22. package/dist/commands/release/push/index.d.ts +26 -0
  23. package/dist/commands/release/push/index.js +230 -0
  24. package/dist/commands/tenant/backup/delete/index.d.ts +1 -1
  25. package/dist/commands/tenant/backup/delete/index.js +8 -9
  26. package/dist/commands/tenant/backup/export/index.d.ts +1 -1
  27. package/dist/commands/tenant/backup/export/index.js +9 -10
  28. package/dist/commands/tenant/backup/restore/index.d.ts +1 -1
  29. package/dist/commands/tenant/backup/restore/index.js +8 -9
  30. package/dist/commands/tenant/cluster/create/index.d.ts +18 -0
  31. package/dist/commands/tenant/cluster/create/index.js +149 -0
  32. package/dist/commands/{run/sessions/start → tenant/cluster/delete}/index.d.ts +9 -3
  33. package/dist/commands/tenant/cluster/delete/index.js +125 -0
  34. package/dist/commands/tenant/cluster/edit/index.d.ts +22 -0
  35. package/dist/commands/tenant/cluster/edit/index.js +128 -0
  36. package/dist/commands/{run/sessions → tenant/cluster}/get/index.d.ts +7 -3
  37. package/dist/commands/tenant/cluster/get/index.js +114 -0
  38. package/dist/commands/{run/info → tenant/cluster/license/get}/index.d.ts +10 -7
  39. package/dist/commands/tenant/cluster/license/get/index.js +118 -0
  40. package/dist/commands/tenant/cluster/license/set/index.d.ts +21 -0
  41. package/dist/commands/tenant/cluster/license/set/index.js +132 -0
  42. package/dist/commands/{run/env → tenant/cluster}/list/index.d.ts +3 -3
  43. package/dist/commands/tenant/cluster/list/index.js +109 -0
  44. package/dist/commands/tenant/create/index.d.ts +6 -3
  45. package/dist/commands/tenant/create/index.js +28 -20
  46. package/dist/commands/tenant/deploy_platform/index.d.ts +1 -1
  47. package/dist/commands/tenant/deploy_platform/index.js +8 -9
  48. package/dist/commands/tenant/deploy_release/index.d.ts +1 -1
  49. package/dist/commands/tenant/deploy_release/index.js +8 -9
  50. package/dist/commands/tenant/env/delete/index.d.ts +19 -0
  51. package/dist/commands/tenant/env/delete/index.js +139 -0
  52. package/dist/commands/{run/projects/create → tenant/env/get}/index.d.ts +7 -4
  53. package/dist/commands/tenant/env/get/index.js +113 -0
  54. package/dist/commands/{run/projects/update → tenant/env/get_all}/index.d.ts +7 -5
  55. package/dist/commands/tenant/env/get_all/index.js +123 -0
  56. package/dist/commands/{run/secrets/get → tenant/env/list}/index.d.ts +5 -3
  57. package/dist/commands/tenant/env/list/index.js +116 -0
  58. package/dist/commands/tenant/env/set/index.d.ts +18 -0
  59. package/dist/commands/tenant/env/set/index.js +122 -0
  60. package/dist/commands/tenant/env/set_all/index.d.ts +18 -0
  61. package/dist/commands/tenant/env/set_all/index.js +131 -0
  62. package/dist/commands/tenant/get/index.js +6 -5
  63. package/dist/commands/tenant/impersonate/index.d.ts +19 -0
  64. package/dist/commands/tenant/impersonate/index.js +146 -0
  65. package/dist/commands/tenant/license/get/index.d.ts +18 -0
  66. package/dist/commands/tenant/license/get/index.js +127 -0
  67. package/dist/commands/tenant/license/set/index.d.ts +19 -0
  68. package/dist/commands/tenant/license/set/index.js +141 -0
  69. package/dist/commands/tenant/list/index.js +6 -6
  70. package/dist/commands/tenant/pull/index.d.ts +31 -0
  71. package/dist/commands/tenant/pull/index.js +327 -0
  72. package/dist/commands/tenant/push/index.d.ts +24 -0
  73. package/dist/commands/tenant/push/index.js +245 -0
  74. package/dist/commands/workspace/push/index.js +21 -6
  75. package/oclif.manifest.json +2323 -1918
  76. package/package.json +1 -19
  77. package/dist/commands/run/env/delete/index.d.ts +0 -14
  78. package/dist/commands/run/env/delete/index.js +0 -65
  79. package/dist/commands/run/env/get/index.d.ts +0 -14
  80. package/dist/commands/run/env/get/index.js +0 -52
  81. package/dist/commands/run/env/list/index.js +0 -56
  82. package/dist/commands/run/env/set/index.d.ts +0 -14
  83. package/dist/commands/run/env/set/index.js +0 -51
  84. package/dist/commands/run/exec/index.d.ts +0 -31
  85. package/dist/commands/run/exec/index.js +0 -431
  86. package/dist/commands/run/info/index.js +0 -160
  87. package/dist/commands/run/projects/create/index.js +0 -75
  88. package/dist/commands/run/projects/delete/index.d.ts +0 -14
  89. package/dist/commands/run/projects/delete/index.js +0 -65
  90. package/dist/commands/run/projects/list/index.d.ts +0 -13
  91. package/dist/commands/run/projects/list/index.js +0 -66
  92. package/dist/commands/run/projects/update/index.js +0 -86
  93. package/dist/commands/run/secrets/delete/index.d.ts +0 -14
  94. package/dist/commands/run/secrets/delete/index.js +0 -65
  95. package/dist/commands/run/secrets/get/index.js +0 -52
  96. package/dist/commands/run/secrets/list/index.d.ts +0 -12
  97. package/dist/commands/run/secrets/list/index.js +0 -60
  98. package/dist/commands/run/secrets/set/index.d.ts +0 -16
  99. package/dist/commands/run/secrets/set/index.js +0 -74
  100. package/dist/commands/run/sessions/delete/index.d.ts +0 -14
  101. package/dist/commands/run/sessions/delete/index.js +0 -65
  102. package/dist/commands/run/sessions/get/index.js +0 -72
  103. package/dist/commands/run/sessions/list/index.d.ts +0 -13
  104. package/dist/commands/run/sessions/list/index.js +0 -64
  105. package/dist/commands/run/sessions/start/index.js +0 -56
  106. package/dist/commands/run/sessions/stop/index.d.ts +0 -14
  107. package/dist/commands/run/sessions/stop/index.js +0 -56
  108. package/dist/commands/run/sink/get/index.d.ts +0 -14
  109. package/dist/commands/run/sink/get/index.js +0 -63
  110. package/dist/lib/base-run-command.d.ts +0 -41
  111. package/dist/lib/base-run-command.js +0 -75
  112. package/dist/lib/run-http-client.d.ts +0 -64
  113. package/dist/lib/run-http-client.js +0 -171
  114. package/dist/lib/run-types.d.ts +0 -226
  115. package/dist/lib/run-types.js +0 -5
@@ -0,0 +1,139 @@
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 TenantEnvDelete extends BaseCommand {
8
+ static args = {
9
+ tenant_name: Args.string({
10
+ description: 'Tenant name',
11
+ required: true,
12
+ }),
13
+ };
14
+ static description = 'Delete an environment variable from a tenant';
15
+ static examples = [
16
+ `$ xano tenant env delete my-tenant --name DATABASE_URL
17
+ Are you sure you want to delete environment variable 'DATABASE_URL' from tenant my-tenant? (y/N) y
18
+ Environment variable 'DATABASE_URL' deleted from tenant my-tenant
19
+ `,
20
+ `$ xano tenant env delete my-tenant --name DATABASE_URL --force
21
+ Environment variable 'DATABASE_URL' deleted from tenant my-tenant
22
+ `,
23
+ `$ xano tenant env delete my-tenant --name DATABASE_URL -f -w 5 -o json`,
24
+ ];
25
+ static flags = {
26
+ ...BaseCommand.baseFlags,
27
+ force: Flags.boolean({
28
+ char: 'f',
29
+ default: false,
30
+ description: 'Skip confirmation prompt',
31
+ required: false,
32
+ }),
33
+ name: Flags.string({
34
+ char: 'n',
35
+ description: 'Environment variable name',
36
+ required: true,
37
+ }),
38
+ output: Flags.string({
39
+ char: 'o',
40
+ default: 'summary',
41
+ description: 'Output format',
42
+ options: ['summary', 'json'],
43
+ required: false,
44
+ }),
45
+ workspace: Flags.string({
46
+ char: 'w',
47
+ description: 'Workspace ID (uses profile workspace if not provided)',
48
+ required: false,
49
+ }),
50
+ };
51
+ async run() {
52
+ const { args, flags } = await this.parse(TenantEnvDelete);
53
+ const profileName = flags.profile || this.getDefaultProfile();
54
+ const credentials = this.loadCredentials();
55
+ if (!(profileName in credentials.profiles)) {
56
+ this.error(`Profile '${profileName}' not found. Available profiles: ${Object.keys(credentials.profiles).join(', ')}\n` +
57
+ `Create a profile using 'xano profile create'`);
58
+ }
59
+ const profile = credentials.profiles[profileName];
60
+ if (!profile.instance_origin) {
61
+ this.error(`Profile '${profileName}' is missing instance_origin`);
62
+ }
63
+ if (!profile.access_token) {
64
+ this.error(`Profile '${profileName}' is missing access_token`);
65
+ }
66
+ const workspaceId = flags.workspace || profile.workspace;
67
+ if (!workspaceId) {
68
+ this.error('No workspace ID provided. Use --workspace flag or set one in your profile.');
69
+ }
70
+ const tenantName = args.tenant_name;
71
+ const envName = flags.name;
72
+ if (!flags.force) {
73
+ const confirmed = await this.confirm(`Are you sure you want to delete environment variable '${envName}' from tenant ${tenantName}?`);
74
+ if (!confirmed) {
75
+ this.log('Deletion cancelled.');
76
+ return;
77
+ }
78
+ }
79
+ const apiUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}/tenant/${tenantName}/env/${envName}`;
80
+ try {
81
+ const response = await this.verboseFetch(apiUrl, {
82
+ headers: {
83
+ accept: 'application/json',
84
+ Authorization: `Bearer ${profile.access_token}`,
85
+ },
86
+ method: 'DELETE',
87
+ }, flags.verbose, profile.access_token);
88
+ if (!response.ok) {
89
+ const errorText = await response.text();
90
+ this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
91
+ }
92
+ if (flags.output === 'json') {
93
+ this.log(JSON.stringify({ deleted: true, env_name: envName, tenant_name: tenantName }, null, 2));
94
+ }
95
+ else {
96
+ this.log(`Environment variable '${envName}' deleted from tenant ${tenantName}`);
97
+ }
98
+ }
99
+ catch (error) {
100
+ if (error instanceof Error) {
101
+ this.error(`Failed to delete tenant environment variable: ${error.message}`);
102
+ }
103
+ else {
104
+ this.error(`Failed to delete tenant environment variable: ${String(error)}`);
105
+ }
106
+ }
107
+ }
108
+ async confirm(message) {
109
+ const readline = await import('node:readline');
110
+ const rl = readline.createInterface({
111
+ input: process.stdin,
112
+ output: process.stdout,
113
+ });
114
+ return new Promise((resolve) => {
115
+ rl.question(`${message} (y/N) `, (answer) => {
116
+ rl.close();
117
+ resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');
118
+ });
119
+ });
120
+ }
121
+ loadCredentials() {
122
+ const configDir = path.join(os.homedir(), '.xano');
123
+ const credentialsPath = path.join(configDir, 'credentials.yaml');
124
+ if (!fs.existsSync(credentialsPath)) {
125
+ this.error(`Credentials file not found at ${credentialsPath}\n` + `Create a profile using 'xano profile create'`);
126
+ }
127
+ try {
128
+ const fileContent = fs.readFileSync(credentialsPath, 'utf8');
129
+ const parsed = yaml.load(fileContent);
130
+ if (!parsed || typeof parsed !== 'object' || !('profiles' in parsed)) {
131
+ this.error('Credentials file has invalid format.');
132
+ }
133
+ return parsed;
134
+ }
135
+ catch (error) {
136
+ this.error(`Failed to parse credentials file: ${error}`);
137
+ }
138
+ }
139
+ }
@@ -1,14 +1,17 @@
1
- import BaseRunCommand from '../../../../lib/base-run-command.js';
2
- export default class RunProjectsCreate extends BaseRunCommand {
3
- static args: {};
1
+ import BaseCommand from '../../../../base-command.js';
2
+ export default class TenantEnvGet extends BaseCommand {
3
+ static args: {
4
+ tenant_name: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
5
+ };
4
6
  static description: string;
5
7
  static examples: string[];
6
8
  static flags: {
7
- description: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
8
9
  name: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
9
10
  output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
11
+ workspace: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
12
  profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
13
  verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
12
14
  };
13
15
  run(): Promise<void>;
16
+ private loadCredentials;
14
17
  }
@@ -0,0 +1,113 @@
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 TenantEnvGet extends BaseCommand {
8
+ static args = {
9
+ tenant_name: Args.string({
10
+ description: 'Tenant name',
11
+ required: true,
12
+ }),
13
+ };
14
+ static description = 'Get a single environment variable for a tenant';
15
+ static examples = [
16
+ `$ xano tenant env get my-tenant --name DATABASE_URL
17
+ postgres://localhost:5432/mydb
18
+ `,
19
+ `$ xano tenant env get my-tenant --name DATABASE_URL -w 5 -o json`,
20
+ ];
21
+ static flags = {
22
+ ...BaseCommand.baseFlags,
23
+ name: Flags.string({
24
+ char: 'n',
25
+ description: 'Environment variable name',
26
+ required: true,
27
+ }),
28
+ output: Flags.string({
29
+ char: 'o',
30
+ default: 'summary',
31
+ description: 'Output format',
32
+ options: ['summary', 'json'],
33
+ required: false,
34
+ }),
35
+ workspace: Flags.string({
36
+ char: 'w',
37
+ description: 'Workspace ID (uses profile workspace if not provided)',
38
+ required: false,
39
+ }),
40
+ };
41
+ async run() {
42
+ const { args, flags } = await this.parse(TenantEnvGet);
43
+ const profileName = flags.profile || this.getDefaultProfile();
44
+ const credentials = this.loadCredentials();
45
+ if (!(profileName in credentials.profiles)) {
46
+ this.error(`Profile '${profileName}' not found. Available profiles: ${Object.keys(credentials.profiles).join(', ')}\n` +
47
+ `Create a profile using 'xano profile create'`);
48
+ }
49
+ const profile = credentials.profiles[profileName];
50
+ if (!profile.instance_origin) {
51
+ this.error(`Profile '${profileName}' is missing instance_origin`);
52
+ }
53
+ if (!profile.access_token) {
54
+ this.error(`Profile '${profileName}' is missing access_token`);
55
+ }
56
+ const workspaceId = flags.workspace || profile.workspace;
57
+ if (!workspaceId) {
58
+ this.error('No workspace ID provided. Use --workspace flag or set one in your profile.');
59
+ }
60
+ const tenantName = args.tenant_name;
61
+ const envName = flags.name;
62
+ const apiUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}/tenant/${tenantName}/env/${envName}`;
63
+ try {
64
+ const response = await this.verboseFetch(apiUrl, {
65
+ headers: {
66
+ accept: 'application/json',
67
+ Authorization: `Bearer ${profile.access_token}`,
68
+ },
69
+ method: 'GET',
70
+ }, flags.verbose, profile.access_token);
71
+ if (!response.ok) {
72
+ const errorText = await response.text();
73
+ this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
74
+ }
75
+ const envVar = (await response.json());
76
+ if (flags.output === 'json') {
77
+ this.log(JSON.stringify(envVar, null, 2));
78
+ }
79
+ else if (envVar) {
80
+ this.log(envVar.value);
81
+ }
82
+ else {
83
+ this.log(`Environment variable '${envName}' not found for tenant ${tenantName}`);
84
+ }
85
+ }
86
+ catch (error) {
87
+ if (error instanceof Error) {
88
+ this.error(`Failed to get tenant environment variable: ${error.message}`);
89
+ }
90
+ else {
91
+ this.error(`Failed to get tenant environment variable: ${String(error)}`);
92
+ }
93
+ }
94
+ }
95
+ loadCredentials() {
96
+ const configDir = path.join(os.homedir(), '.xano');
97
+ const credentialsPath = path.join(configDir, 'credentials.yaml');
98
+ if (!fs.existsSync(credentialsPath)) {
99
+ this.error(`Credentials file not found at ${credentialsPath}\n` + `Create a profile using 'xano profile create'`);
100
+ }
101
+ try {
102
+ const fileContent = fs.readFileSync(credentialsPath, 'utf8');
103
+ const parsed = yaml.load(fileContent);
104
+ if (!parsed || typeof parsed !== 'object' || !('profiles' in parsed)) {
105
+ this.error('Credentials file has invalid format.');
106
+ }
107
+ return parsed;
108
+ }
109
+ catch (error) {
110
+ this.error(`Failed to parse credentials file: ${error}`);
111
+ }
112
+ }
113
+ }
@@ -1,16 +1,18 @@
1
- import BaseRunCommand from '../../../../lib/base-run-command.js';
2
- export default class RunProjectsUpdate extends BaseRunCommand {
1
+ import BaseCommand from '../../../../base-command.js';
2
+ export default class TenantEnvGetAll extends BaseCommand {
3
3
  static args: {
4
- projectId: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
4
+ tenant_name: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
5
5
  };
6
6
  static description: string;
7
7
  static examples: string[];
8
8
  static flags: {
9
- description: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
- name: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
9
+ file: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
10
  output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
11
+ view: import("@oclif/core/interfaces").BooleanFlag<boolean>;
12
+ workspace: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
12
13
  profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
13
14
  verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
14
15
  };
15
16
  run(): Promise<void>;
17
+ private loadCredentials;
16
18
  }
@@ -0,0 +1,123 @@
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 TenantEnvGetAll extends BaseCommand {
8
+ static args = {
9
+ tenant_name: Args.string({
10
+ description: 'Tenant name',
11
+ required: true,
12
+ }),
13
+ };
14
+ static description = 'Get all environment variables for a tenant and save to a YAML file';
15
+ static examples = [
16
+ `$ xano tenant env get_all my-tenant
17
+ Environment variables saved to env_my-tenant.yaml
18
+ `,
19
+ `$ xano tenant env get_all my-tenant --file ./my-env.yaml`,
20
+ `$ xano tenant env get_all my-tenant --view`,
21
+ `$ xano tenant env get_all my-tenant -o json`,
22
+ ];
23
+ static flags = {
24
+ ...BaseCommand.baseFlags,
25
+ file: Flags.string({
26
+ char: 'f',
27
+ description: 'Output file path (default: env_<tenant_name>.yaml)',
28
+ required: false,
29
+ }),
30
+ output: Flags.string({
31
+ char: 'o',
32
+ default: 'summary',
33
+ description: 'Output format',
34
+ options: ['summary', 'json'],
35
+ required: false,
36
+ }),
37
+ view: Flags.boolean({
38
+ default: false,
39
+ description: 'Print environment variables to stdout instead of saving to file',
40
+ required: false,
41
+ }),
42
+ workspace: Flags.string({
43
+ char: 'w',
44
+ description: 'Workspace ID (uses profile workspace if not provided)',
45
+ required: false,
46
+ }),
47
+ };
48
+ async run() {
49
+ const { args, flags } = await this.parse(TenantEnvGetAll);
50
+ const profileName = flags.profile || this.getDefaultProfile();
51
+ const credentials = this.loadCredentials();
52
+ if (!(profileName in credentials.profiles)) {
53
+ this.error(`Profile '${profileName}' not found. Available profiles: ${Object.keys(credentials.profiles).join(', ')}\n` +
54
+ `Create a profile using 'xano profile create'`);
55
+ }
56
+ const profile = credentials.profiles[profileName];
57
+ if (!profile.instance_origin) {
58
+ this.error(`Profile '${profileName}' is missing instance_origin`);
59
+ }
60
+ if (!profile.access_token) {
61
+ this.error(`Profile '${profileName}' is missing access_token`);
62
+ }
63
+ const workspaceId = flags.workspace || profile.workspace;
64
+ if (!workspaceId) {
65
+ this.error('No workspace ID provided. Use --workspace flag or set one in your profile.');
66
+ }
67
+ const tenantName = args.tenant_name;
68
+ const apiUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}/tenant/${tenantName}/env_all`;
69
+ try {
70
+ const response = await this.verboseFetch(apiUrl, {
71
+ headers: {
72
+ accept: 'application/json',
73
+ Authorization: `Bearer ${profile.access_token}`,
74
+ },
75
+ method: 'GET',
76
+ }, flags.verbose, profile.access_token);
77
+ if (!response.ok) {
78
+ const errorText = await response.text();
79
+ this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
80
+ }
81
+ const envMap = (await response.json());
82
+ if (flags.output === 'json') {
83
+ this.log(JSON.stringify(envMap, null, 2));
84
+ }
85
+ else if (flags.view) {
86
+ const envYaml = yaml.dump(envMap, { lineWidth: -1, sortKeys: true });
87
+ this.log(envYaml.trimEnd());
88
+ }
89
+ else {
90
+ const filePath = path.resolve(flags.file || `env_${tenantName}.yaml`);
91
+ const envYaml = yaml.dump(envMap, { lineWidth: -1, sortKeys: true });
92
+ fs.writeFileSync(filePath, envYaml, 'utf8');
93
+ this.log(`Environment variables saved to ${filePath}`);
94
+ }
95
+ }
96
+ catch (error) {
97
+ if (error instanceof Error) {
98
+ this.error(`Failed to get tenant environment variables: ${error.message}`);
99
+ }
100
+ else {
101
+ this.error(`Failed to get tenant environment variables: ${String(error)}`);
102
+ }
103
+ }
104
+ }
105
+ loadCredentials() {
106
+ const configDir = path.join(os.homedir(), '.xano');
107
+ const credentialsPath = path.join(configDir, 'credentials.yaml');
108
+ if (!fs.existsSync(credentialsPath)) {
109
+ this.error(`Credentials file not found at ${credentialsPath}\n` + `Create a profile using 'xano profile create'`);
110
+ }
111
+ try {
112
+ const fileContent = fs.readFileSync(credentialsPath, 'utf8');
113
+ const parsed = yaml.load(fileContent);
114
+ if (!parsed || typeof parsed !== 'object' || !('profiles' in parsed)) {
115
+ this.error('Credentials file has invalid format.');
116
+ }
117
+ return parsed;
118
+ }
119
+ catch (error) {
120
+ this.error(`Failed to parse credentials file: ${error}`);
121
+ }
122
+ }
123
+ }
@@ -1,14 +1,16 @@
1
- import BaseRunCommand from '../../../../lib/base-run-command.js';
2
- export default class RunSecretsGet extends BaseRunCommand {
1
+ import BaseCommand from '../../../../base-command.js';
2
+ export default class TenantEnvList extends BaseCommand {
3
3
  static args: {
4
- name: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
4
+ tenant_name: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
5
5
  };
6
6
  static description: string;
7
7
  static examples: string[];
8
8
  static flags: {
9
9
  output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
10
+ workspace: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
11
  profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
12
  verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
12
13
  };
13
14
  run(): Promise<void>;
15
+ private loadCredentials;
14
16
  }
@@ -0,0 +1,116 @@
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 TenantEnvList extends BaseCommand {
8
+ static args = {
9
+ tenant_name: Args.string({
10
+ description: 'Tenant name',
11
+ required: true,
12
+ }),
13
+ };
14
+ static description = 'List environment variable keys for a tenant';
15
+ static examples = [
16
+ `$ xano tenant env list my-tenant
17
+ Environment variables for tenant my-tenant:
18
+ - DATABASE_URL
19
+ - API_KEY
20
+ - SECRET_TOKEN
21
+ `,
22
+ `$ xano tenant env list my-tenant -w 5 -o json`,
23
+ ];
24
+ static flags = {
25
+ ...BaseCommand.baseFlags,
26
+ output: Flags.string({
27
+ char: 'o',
28
+ default: 'summary',
29
+ description: 'Output format',
30
+ options: ['summary', 'json'],
31
+ required: false,
32
+ }),
33
+ workspace: Flags.string({
34
+ char: 'w',
35
+ description: 'Workspace ID (uses profile workspace if not provided)',
36
+ required: false,
37
+ }),
38
+ };
39
+ async run() {
40
+ const { args, flags } = await this.parse(TenantEnvList);
41
+ const profileName = flags.profile || this.getDefaultProfile();
42
+ const credentials = this.loadCredentials();
43
+ if (!(profileName in credentials.profiles)) {
44
+ this.error(`Profile '${profileName}' not found. Available profiles: ${Object.keys(credentials.profiles).join(', ')}\n` +
45
+ `Create a profile using 'xano profile create'`);
46
+ }
47
+ const profile = credentials.profiles[profileName];
48
+ if (!profile.instance_origin) {
49
+ this.error(`Profile '${profileName}' is missing instance_origin`);
50
+ }
51
+ if (!profile.access_token) {
52
+ this.error(`Profile '${profileName}' is missing access_token`);
53
+ }
54
+ const workspaceId = flags.workspace || profile.workspace;
55
+ if (!workspaceId) {
56
+ this.error('No workspace ID provided. Use --workspace flag or set one in your profile.');
57
+ }
58
+ const tenantName = args.tenant_name;
59
+ const apiUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}/tenant/${tenantName}/env_key`;
60
+ try {
61
+ const response = await this.verboseFetch(apiUrl, {
62
+ headers: {
63
+ accept: 'application/json',
64
+ Authorization: `Bearer ${profile.access_token}`,
65
+ },
66
+ method: 'GET',
67
+ }, flags.verbose, profile.access_token);
68
+ if (!response.ok) {
69
+ const errorText = await response.text();
70
+ this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
71
+ }
72
+ const data = (await response.json());
73
+ if (flags.output === 'json') {
74
+ this.log(JSON.stringify(data, null, 2));
75
+ }
76
+ else {
77
+ const envVars = data.env || [];
78
+ if (envVars.length === 0) {
79
+ this.log(`No environment variables found for tenant ${tenantName}`);
80
+ }
81
+ else {
82
+ this.log(`Environment variables for tenant ${tenantName}:`);
83
+ for (const envVar of envVars) {
84
+ this.log(` - ${envVar.name}`);
85
+ }
86
+ }
87
+ }
88
+ }
89
+ catch (error) {
90
+ if (error instanceof Error) {
91
+ this.error(`Failed to list tenant environment variables: ${error.message}`);
92
+ }
93
+ else {
94
+ this.error(`Failed to list tenant environment variables: ${String(error)}`);
95
+ }
96
+ }
97
+ }
98
+ loadCredentials() {
99
+ const configDir = path.join(os.homedir(), '.xano');
100
+ const credentialsPath = path.join(configDir, 'credentials.yaml');
101
+ if (!fs.existsSync(credentialsPath)) {
102
+ this.error(`Credentials file not found at ${credentialsPath}\n` + `Create a profile using 'xano profile create'`);
103
+ }
104
+ try {
105
+ const fileContent = fs.readFileSync(credentialsPath, 'utf8');
106
+ const parsed = yaml.load(fileContent);
107
+ if (!parsed || typeof parsed !== 'object' || !('profiles' in parsed)) {
108
+ this.error('Credentials file has invalid format.');
109
+ }
110
+ return parsed;
111
+ }
112
+ catch (error) {
113
+ this.error(`Failed to parse credentials file: ${error}`);
114
+ }
115
+ }
116
+ }
@@ -0,0 +1,18 @@
1
+ import BaseCommand from '../../../../base-command.js';
2
+ export default class TenantEnvSet 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
+ name: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
10
+ output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
11
+ value: 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 loadCredentials;
18
+ }