@xano/cli 0.0.26 → 0.0.27

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 (110) hide show
  1. package/dist/base-command.d.ts +3 -1
  2. package/dist/base-command.js +12 -5
  3. package/dist/commands/auth/index.d.ts +21 -0
  4. package/dist/commands/auth/index.js +533 -0
  5. package/dist/commands/branch/create/index.d.ts +17 -0
  6. package/dist/commands/branch/create/index.js +164 -0
  7. package/dist/commands/branch/delete/index.d.ts +18 -0
  8. package/dist/commands/branch/delete/index.js +156 -0
  9. package/dist/commands/branch/edit/index.d.ts +19 -0
  10. package/dist/commands/branch/edit/index.js +166 -0
  11. package/dist/commands/branch/get/index.d.ts +16 -0
  12. package/dist/commands/branch/get/index.js +135 -0
  13. package/dist/commands/branch/list/index.d.ts +18 -0
  14. package/dist/commands/branch/list/index.js +138 -0
  15. package/dist/commands/branch/set-live/index.d.ts +18 -0
  16. package/dist/commands/branch/set-live/index.js +155 -0
  17. package/dist/commands/function/create/index.d.ts +7 -6
  18. package/dist/commands/function/create/index.js +55 -55
  19. package/dist/commands/function/edit/index.d.ts +11 -10
  20. package/dist/commands/function/edit/index.js +155 -162
  21. package/dist/commands/function/get/index.d.ts +6 -5
  22. package/dist/commands/function/get/index.js +55 -60
  23. package/dist/commands/function/list/index.d.ts +6 -5
  24. package/dist/commands/function/list/index.js +52 -52
  25. package/dist/commands/profile/create/index.d.ts +6 -6
  26. package/dist/commands/profile/create/index.js +37 -37
  27. package/dist/commands/profile/delete/index.d.ts +2 -2
  28. package/dist/commands/profile/delete/index.js +9 -9
  29. package/dist/commands/profile/edit/index.d.ts +8 -7
  30. package/dist/commands/profile/edit/index.js +48 -48
  31. package/dist/commands/profile/get-default/index.js +1 -1
  32. package/dist/commands/profile/list/index.d.ts +2 -2
  33. package/dist/commands/profile/list/index.js +9 -9
  34. package/dist/commands/profile/me/index.d.ts +4 -3
  35. package/dist/commands/profile/me/index.js +21 -21
  36. package/dist/commands/profile/project/index.js +1 -1
  37. package/dist/commands/profile/set-default/index.js +1 -1
  38. package/dist/commands/profile/token/index.js +1 -1
  39. package/dist/commands/profile/wizard/index.d.ts +5 -4
  40. package/dist/commands/profile/wizard/index.js +142 -108
  41. package/dist/commands/run/env/delete/index.d.ts +3 -2
  42. package/dist/commands/run/env/delete/index.js +10 -10
  43. package/dist/commands/run/env/get/index.d.ts +3 -2
  44. package/dist/commands/run/env/get/index.js +11 -11
  45. package/dist/commands/run/env/list/index.d.ts +3 -2
  46. package/dist/commands/run/env/list/index.js +17 -19
  47. package/dist/commands/run/env/set/index.d.ts +3 -2
  48. package/dist/commands/run/env/set/index.js +5 -5
  49. package/dist/commands/run/exec/index.d.ts +19 -8
  50. package/dist/commands/run/exec/index.js +186 -108
  51. package/dist/commands/run/info/index.d.ts +5 -4
  52. package/dist/commands/run/info/index.js +27 -27
  53. package/dist/commands/run/projects/create/index.d.ts +4 -3
  54. package/dist/commands/run/projects/create/index.js +23 -23
  55. package/dist/commands/run/projects/delete/index.d.ts +3 -2
  56. package/dist/commands/run/projects/delete/index.js +10 -10
  57. package/dist/commands/run/projects/list/index.d.ts +3 -2
  58. package/dist/commands/run/projects/list/index.js +12 -12
  59. package/dist/commands/run/projects/update/index.d.ts +4 -3
  60. package/dist/commands/run/projects/update/index.js +21 -21
  61. package/dist/commands/run/secrets/delete/index.d.ts +3 -2
  62. package/dist/commands/run/secrets/delete/index.js +10 -10
  63. package/dist/commands/run/secrets/get/index.d.ts +3 -2
  64. package/dist/commands/run/secrets/get/index.js +11 -11
  65. package/dist/commands/run/secrets/list/index.d.ts +3 -2
  66. package/dist/commands/run/secrets/list/index.js +22 -24
  67. package/dist/commands/run/secrets/set/index.d.ts +4 -3
  68. package/dist/commands/run/secrets/set/index.js +16 -16
  69. package/dist/commands/run/sessions/delete/index.d.ts +3 -2
  70. package/dist/commands/run/sessions/delete/index.js +10 -10
  71. package/dist/commands/run/sessions/get/index.d.ts +3 -2
  72. package/dist/commands/run/sessions/get/index.js +11 -11
  73. package/dist/commands/run/sessions/list/index.d.ts +3 -2
  74. package/dist/commands/run/sessions/list/index.js +11 -11
  75. package/dist/commands/run/sessions/start/index.d.ts +3 -2
  76. package/dist/commands/run/sessions/start/index.js +11 -11
  77. package/dist/commands/run/sessions/stop/index.d.ts +3 -2
  78. package/dist/commands/run/sessions/stop/index.js +11 -11
  79. package/dist/commands/run/sink/get/index.d.ts +3 -2
  80. package/dist/commands/run/sink/get/index.js +11 -11
  81. package/dist/commands/static_host/build/create/index.d.ts +5 -4
  82. package/dist/commands/static_host/build/create/index.js +33 -33
  83. package/dist/commands/static_host/build/get/index.d.ts +5 -4
  84. package/dist/commands/static_host/build/get/index.js +20 -20
  85. package/dist/commands/static_host/build/list/index.d.ts +4 -3
  86. package/dist/commands/static_host/build/list/index.js +31 -31
  87. package/dist/commands/static_host/list/index.d.ts +4 -3
  88. package/dist/commands/static_host/list/index.js +31 -31
  89. package/dist/commands/workspace/create/index.d.ts +14 -0
  90. package/dist/commands/workspace/create/index.js +131 -0
  91. package/dist/commands/workspace/delete/index.d.ts +20 -0
  92. package/dist/commands/workspace/delete/index.js +141 -0
  93. package/dist/commands/workspace/edit/index.d.ts +22 -0
  94. package/dist/commands/workspace/edit/index.js +176 -0
  95. package/dist/commands/workspace/get/index.d.ts +18 -0
  96. package/dist/commands/workspace/get/index.js +136 -0
  97. package/dist/commands/workspace/list/index.d.ts +3 -2
  98. package/dist/commands/workspace/list/index.js +15 -15
  99. package/dist/commands/workspace/pull/index.d.ts +5 -4
  100. package/dist/commands/workspace/pull/index.js +113 -64
  101. package/dist/commands/workspace/push/index.d.ts +1 -0
  102. package/dist/commands/workspace/push/index.js +5 -5
  103. package/dist/help.d.ts +1 -1
  104. package/dist/lib/base-run-command.d.ts +6 -6
  105. package/dist/lib/base-run-command.js +8 -6
  106. package/dist/lib/run-http-client.d.ts +24 -18
  107. package/dist/lib/run-http-client.js +96 -61
  108. package/dist/lib/run-types.d.ts +80 -80
  109. package/oclif.manifest.json +1963 -785
  110. package/package.json +1 -1
@@ -1,15 +1,16 @@
1
1
  import BaseCommand from '../../../base-command.js';
2
2
  export default class StaticHostList extends BaseCommand {
3
3
  static args: {};
4
+ static description: string;
5
+ static examples: string[];
4
6
  static flags: {
5
- workspace: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
6
7
  output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
7
8
  page: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
8
9
  per_page: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
10
+ workspace: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
9
11
  profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
12
+ verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
10
13
  };
11
- static description: string;
12
- static examples: string[];
13
14
  run(): Promise<void>;
14
15
  private loadCredentials;
15
16
  }
@@ -1,36 +1,11 @@
1
1
  import { Flags } from '@oclif/core';
2
+ import * as yaml from 'js-yaml';
2
3
  import * as fs from 'node:fs';
3
4
  import * as os from 'node:os';
4
5
  import * as path from 'node:path';
5
- import * as yaml from 'js-yaml';
6
6
  import BaseCommand from '../../../base-command.js';
7
7
  export default class StaticHostList extends BaseCommand {
8
8
  static args = {};
9
- static flags = {
10
- ...BaseCommand.baseFlags,
11
- workspace: Flags.string({
12
- char: 'w',
13
- description: 'Workspace ID (optional if set in profile)',
14
- required: false,
15
- }),
16
- output: Flags.string({
17
- char: 'o',
18
- description: 'Output format',
19
- required: false,
20
- default: 'summary',
21
- options: ['summary', 'json'],
22
- }),
23
- page: Flags.integer({
24
- description: 'Page number for pagination',
25
- required: false,
26
- default: 1,
27
- }),
28
- per_page: Flags.integer({
29
- description: 'Number of results per page',
30
- required: false,
31
- default: 50,
32
- }),
33
- };
34
9
  static description = 'List all static hosts in a workspace from the Xano Metadata API';
35
10
  static examples = [
36
11
  `$ xano static_host:list -w 40
@@ -61,6 +36,31 @@ Available static hosts:
61
36
  ]
62
37
  `,
63
38
  ];
39
+ static flags = {
40
+ ...BaseCommand.baseFlags,
41
+ output: Flags.string({
42
+ char: 'o',
43
+ default: 'summary',
44
+ description: 'Output format',
45
+ options: ['summary', 'json'],
46
+ required: false,
47
+ }),
48
+ page: Flags.integer({
49
+ default: 1,
50
+ description: 'Page number for pagination',
51
+ required: false,
52
+ }),
53
+ per_page: Flags.integer({
54
+ default: 50,
55
+ description: 'Number of results per page',
56
+ required: false,
57
+ }),
58
+ workspace: Flags.string({
59
+ char: 'w',
60
+ description: 'Workspace ID (optional if set in profile)',
61
+ required: false,
62
+ }),
63
+ };
64
64
  async run() {
65
65
  const { flags } = await this.parse(StaticHostList);
66
66
  // Get profile name (default or from flag/env)
@@ -106,11 +106,11 @@ Available static hosts:
106
106
  // Fetch static hosts from the API
107
107
  try {
108
108
  const response = await fetch(apiUrl, {
109
- method: 'GET',
110
109
  headers: {
111
110
  'accept': 'application/json',
112
111
  'Authorization': `Bearer ${profile.access_token}`,
113
112
  },
113
+ method: 'GET',
114
114
  });
115
115
  if (!response.ok) {
116
116
  const errorText = await response.text();
@@ -143,12 +143,12 @@ Available static hosts:
143
143
  else {
144
144
  this.log('Available static hosts:');
145
145
  for (const host of staticHosts) {
146
- if (host.id !== undefined) {
147
- const domainInfo = host.domain ? ` - ${host.domain}` : '';
148
- this.log(` - ${host.name} (ID: ${host.id})${domainInfo}`);
146
+ if (host.id === undefined) {
147
+ this.log(` - ${host.name}`);
149
148
  }
150
149
  else {
151
- this.log(` - ${host.name}`);
150
+ const domainInfo = host.domain ? ` - ${host.domain}` : '';
151
+ this.log(` - ${host.name} (ID: ${host.id})${domainInfo}`);
152
152
  }
153
153
  }
154
154
  }
@@ -0,0 +1,14 @@
1
+ import BaseCommand from '../../../base-command.js';
2
+ export default class WorkspaceCreate extends BaseCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ description: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
7
+ name: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
8
+ output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
9
+ profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
+ verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
11
+ };
12
+ run(): Promise<void>;
13
+ private loadCredentials;
14
+ }
@@ -0,0 +1,131 @@
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 WorkspaceCreate extends BaseCommand {
8
+ static description = 'Create a new workspace via the Xano Metadata API';
9
+ static examples = [
10
+ `$ xano workspace create --name "my-workspace"
11
+ Created workspace: my-workspace (ID: 123)
12
+ `,
13
+ `$ xano workspace create --name "my-app" --description "My application workspace"
14
+ Created workspace: my-app (ID: 456)
15
+ Description: My application workspace
16
+ `,
17
+ `$ xano workspace create -n "new-project" -d "New project workspace" -o json
18
+ {
19
+ "id": 789,
20
+ "name": "new-project",
21
+ "description": "New project workspace"
22
+ }
23
+ `,
24
+ ];
25
+ static flags = {
26
+ ...BaseCommand.baseFlags,
27
+ description: Flags.string({
28
+ char: 'd',
29
+ description: 'Description for the workspace',
30
+ required: false,
31
+ }),
32
+ name: Flags.string({
33
+ char: 'n',
34
+ description: 'Name of the workspace',
35
+ required: true,
36
+ }),
37
+ output: Flags.string({
38
+ char: 'o',
39
+ default: 'summary',
40
+ description: 'Output format',
41
+ options: ['summary', 'json'],
42
+ required: false,
43
+ }),
44
+ };
45
+ async run() {
46
+ const { flags } = await this.parse(WorkspaceCreate);
47
+ // Get profile name (default or from flag/env)
48
+ const profileName = flags.profile || this.getDefaultProfile();
49
+ // Load credentials
50
+ const credentials = this.loadCredentials();
51
+ // Get the profile configuration
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
+ // Validate required fields
58
+ if (!profile.instance_origin) {
59
+ this.error(`Profile '${profileName}' is missing instance_origin`);
60
+ }
61
+ if (!profile.access_token) {
62
+ this.error(`Profile '${profileName}' is missing access_token`);
63
+ }
64
+ // Construct the API URL
65
+ const apiUrl = `${profile.instance_origin}/api:meta/workspace`;
66
+ // Build request body
67
+ const body = {
68
+ name: flags.name,
69
+ };
70
+ if (flags.description) {
71
+ body.description = flags.description;
72
+ }
73
+ // Create workspace via the API
74
+ try {
75
+ const response = await fetch(apiUrl, {
76
+ body: JSON.stringify(body),
77
+ headers: {
78
+ 'accept': 'application/json',
79
+ 'Authorization': `Bearer ${profile.access_token}`,
80
+ 'content-type': 'application/json',
81
+ },
82
+ method: 'POST',
83
+ });
84
+ if (!response.ok) {
85
+ const errorText = await response.text();
86
+ this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
87
+ }
88
+ const workspace = await response.json();
89
+ // Output results
90
+ if (flags.output === 'json') {
91
+ this.log(JSON.stringify(workspace, null, 2));
92
+ }
93
+ else {
94
+ // summary format
95
+ this.log(`Created workspace: ${workspace.name} (ID: ${workspace.id})`);
96
+ if (workspace.description) {
97
+ this.log(` Description: ${workspace.description}`);
98
+ }
99
+ }
100
+ }
101
+ catch (error) {
102
+ if (error instanceof Error) {
103
+ this.error(`Failed to create workspace: ${error.message}`);
104
+ }
105
+ else {
106
+ this.error(`Failed to create workspace: ${String(error)}`);
107
+ }
108
+ }
109
+ }
110
+ loadCredentials() {
111
+ const configDir = path.join(os.homedir(), '.xano');
112
+ const credentialsPath = path.join(configDir, 'credentials.yaml');
113
+ // Check if credentials file exists
114
+ if (!fs.existsSync(credentialsPath)) {
115
+ this.error(`Credentials file not found at ${credentialsPath}\n` +
116
+ `Create a profile using 'xano profile create'`);
117
+ }
118
+ // Read credentials file
119
+ try {
120
+ const fileContent = fs.readFileSync(credentialsPath, 'utf8');
121
+ const parsed = yaml.load(fileContent);
122
+ if (!parsed || typeof parsed !== 'object' || !('profiles' in parsed)) {
123
+ this.error('Credentials file has invalid format.');
124
+ }
125
+ return parsed;
126
+ }
127
+ catch (error) {
128
+ this.error(`Failed to parse credentials file: ${error}`);
129
+ }
130
+ }
131
+ }
@@ -0,0 +1,20 @@
1
+ import BaseCommand from '../../../base-command.js';
2
+ export default class WorkspaceDelete extends BaseCommand {
3
+ static args: {
4
+ workspace_id: import("@oclif/core/interfaces").Arg<number, {
5
+ max?: number;
6
+ min?: number;
7
+ }>;
8
+ };
9
+ static description: string;
10
+ static examples: string[];
11
+ static flags: {
12
+ force: import("@oclif/core/interfaces").BooleanFlag<boolean>;
13
+ output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
14
+ profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
15
+ verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
16
+ };
17
+ run(): Promise<void>;
18
+ private confirm;
19
+ private loadCredentials;
20
+ }
@@ -0,0 +1,141 @@
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 WorkspaceDelete extends BaseCommand {
8
+ static args = {
9
+ workspace_id: Args.integer({
10
+ description: 'Workspace ID to delete',
11
+ required: true,
12
+ }),
13
+ };
14
+ static description = 'Delete a workspace via the Xano Metadata API. Cannot delete workspaces with active tenants.';
15
+ static examples = [
16
+ `$ xano workspace delete 123
17
+ Are you sure you want to delete workspace 123? This action cannot be undone. (y/N) y
18
+ Deleted workspace 123
19
+ `,
20
+ `$ xano workspace delete 123 --force
21
+ Deleted workspace 123
22
+ `,
23
+ `$ xano workspace delete 123 -f -o json
24
+ {
25
+ "deleted": true,
26
+ "workspace_id": 123
27
+ }
28
+ `,
29
+ ];
30
+ static flags = {
31
+ ...BaseCommand.baseFlags,
32
+ force: Flags.boolean({
33
+ char: 'f',
34
+ default: false,
35
+ description: 'Skip confirmation prompt',
36
+ required: false,
37
+ }),
38
+ output: Flags.string({
39
+ char: 'o',
40
+ default: 'summary',
41
+ description: 'Output format',
42
+ options: ['summary', 'json'],
43
+ required: false,
44
+ }),
45
+ };
46
+ async run() {
47
+ const { args, flags } = await this.parse(WorkspaceDelete);
48
+ // Get profile name (default or from flag/env)
49
+ const profileName = flags.profile || this.getDefaultProfile();
50
+ // Load credentials
51
+ const credentials = this.loadCredentials();
52
+ // Get the profile configuration
53
+ if (!(profileName in credentials.profiles)) {
54
+ this.error(`Profile '${profileName}' not found. Available profiles: ${Object.keys(credentials.profiles).join(', ')}\n` +
55
+ `Create a profile using 'xano profile create'`);
56
+ }
57
+ const profile = credentials.profiles[profileName];
58
+ // Validate required fields
59
+ if (!profile.instance_origin) {
60
+ this.error(`Profile '${profileName}' is missing instance_origin`);
61
+ }
62
+ if (!profile.access_token) {
63
+ this.error(`Profile '${profileName}' is missing access_token`);
64
+ }
65
+ const workspaceId = args.workspace_id;
66
+ // Confirmation prompt unless --force is used
67
+ if (!flags.force) {
68
+ const confirmed = await this.confirm(`Are you sure you want to delete workspace ${workspaceId}? This action cannot be undone.`);
69
+ if (!confirmed) {
70
+ this.log('Deletion cancelled.');
71
+ return;
72
+ }
73
+ }
74
+ // Construct the API URL
75
+ const apiUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}`;
76
+ // Delete workspace via the API
77
+ try {
78
+ const response = await fetch(apiUrl, {
79
+ headers: {
80
+ 'accept': 'application/json',
81
+ 'Authorization': `Bearer ${profile.access_token}`,
82
+ },
83
+ method: 'DELETE',
84
+ });
85
+ if (!response.ok) {
86
+ const errorText = await response.text();
87
+ this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
88
+ }
89
+ // Output results
90
+ if (flags.output === 'json') {
91
+ this.log(JSON.stringify({ deleted: true, workspace_id: workspaceId }, null, 2));
92
+ }
93
+ else {
94
+ this.log(`Deleted workspace ${workspaceId}`);
95
+ }
96
+ }
97
+ catch (error) {
98
+ if (error instanceof Error) {
99
+ this.error(`Failed to delete workspace: ${error.message}`);
100
+ }
101
+ else {
102
+ this.error(`Failed to delete workspace: ${String(error)}`);
103
+ }
104
+ }
105
+ }
106
+ async confirm(message) {
107
+ // Use readline for simple yes/no confirmation
108
+ const readline = await import('node:readline');
109
+ const rl = readline.createInterface({
110
+ input: process.stdin,
111
+ output: process.stdout,
112
+ });
113
+ return new Promise((resolve) => {
114
+ rl.question(`${message} (y/N) `, (answer) => {
115
+ rl.close();
116
+ resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');
117
+ });
118
+ });
119
+ }
120
+ loadCredentials() {
121
+ const configDir = path.join(os.homedir(), '.xano');
122
+ const credentialsPath = path.join(configDir, 'credentials.yaml');
123
+ // Check if credentials file exists
124
+ if (!fs.existsSync(credentialsPath)) {
125
+ this.error(`Credentials file not found at ${credentialsPath}\n` +
126
+ `Create a profile using 'xano profile create'`);
127
+ }
128
+ // Read credentials file
129
+ try {
130
+ const fileContent = fs.readFileSync(credentialsPath, 'utf8');
131
+ const parsed = yaml.load(fileContent);
132
+ if (!parsed || typeof parsed !== 'object' || !('profiles' in parsed)) {
133
+ this.error('Credentials file has invalid format.');
134
+ }
135
+ return parsed;
136
+ }
137
+ catch (error) {
138
+ this.error(`Failed to parse credentials file: ${error}`);
139
+ }
140
+ }
141
+ }
@@ -0,0 +1,22 @@
1
+ import BaseCommand from '../../../base-command.js';
2
+ export default class WorkspaceEdit extends BaseCommand {
3
+ static args: {
4
+ workspace_id: import("@oclif/core/interfaces").Arg<number | undefined, {
5
+ max?: number;
6
+ min?: number;
7
+ }>;
8
+ };
9
+ static description: string;
10
+ static examples: string[];
11
+ static flags: {
12
+ description: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
13
+ name: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
14
+ output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
15
+ 'require-token': import("@oclif/core/interfaces").BooleanFlag<boolean>;
16
+ swagger: import("@oclif/core/interfaces").BooleanFlag<boolean>;
17
+ profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
18
+ verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
19
+ };
20
+ run(): Promise<void>;
21
+ private loadCredentials;
22
+ }
@@ -0,0 +1,176 @@
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 WorkspaceEdit extends BaseCommand {
8
+ static args = {
9
+ workspace_id: Args.integer({
10
+ description: 'Workspace ID to edit (uses profile workspace if not provided)',
11
+ required: false,
12
+ }),
13
+ };
14
+ static description = 'Edit an existing workspace via the Xano Metadata API';
15
+ static examples = [
16
+ `$ xano workspace edit 123 --name "new-name"
17
+ Updated workspace: new-name (ID: 123)
18
+ `,
19
+ `$ xano workspace edit --name "updated-workspace" --description "Updated description"
20
+ Updated workspace: updated-workspace (ID: 123)
21
+ Description: Updated description
22
+ `,
23
+ `$ xano workspace edit 123 --swagger --require-token
24
+ Updated workspace: my-workspace (ID: 123)
25
+ Swagger: enabled
26
+ Require Token: true
27
+ `,
28
+ `$ xano workspace edit 123 --no-swagger -o json
29
+ {
30
+ "id": 123,
31
+ "name": "my-workspace",
32
+ "swagger": false
33
+ }
34
+ `,
35
+ ];
36
+ static flags = {
37
+ ...BaseCommand.baseFlags,
38
+ description: Flags.string({
39
+ char: 'd',
40
+ description: 'New description for the workspace',
41
+ required: false,
42
+ }),
43
+ name: Flags.string({
44
+ char: 'n',
45
+ description: 'New name for the workspace',
46
+ required: false,
47
+ }),
48
+ output: Flags.string({
49
+ char: 'o',
50
+ default: 'summary',
51
+ description: 'Output format',
52
+ options: ['summary', 'json'],
53
+ required: false,
54
+ }),
55
+ 'require-token': Flags.boolean({
56
+ allowNo: true,
57
+ description: 'Whether to require a token for documentation access',
58
+ required: false,
59
+ }),
60
+ swagger: Flags.boolean({
61
+ allowNo: true,
62
+ description: 'Enable or disable swagger documentation',
63
+ required: false,
64
+ }),
65
+ };
66
+ async run() {
67
+ const { args, flags } = await this.parse(WorkspaceEdit);
68
+ // Get profile name (default or from flag/env)
69
+ const profileName = flags.profile || this.getDefaultProfile();
70
+ // Load credentials
71
+ const credentials = this.loadCredentials();
72
+ // Get the profile configuration
73
+ if (!(profileName in credentials.profiles)) {
74
+ this.error(`Profile '${profileName}' not found. Available profiles: ${Object.keys(credentials.profiles).join(', ')}\n` +
75
+ `Create a profile using 'xano profile create'`);
76
+ }
77
+ const profile = credentials.profiles[profileName];
78
+ // Validate required fields
79
+ if (!profile.instance_origin) {
80
+ this.error(`Profile '${profileName}' is missing instance_origin`);
81
+ }
82
+ if (!profile.access_token) {
83
+ this.error(`Profile '${profileName}' is missing access_token`);
84
+ }
85
+ // Get workspace ID from args or profile
86
+ const workspaceId = args.workspace_id || profile.workspace;
87
+ if (!workspaceId) {
88
+ this.error('No workspace ID provided. Either pass a workspace ID as an argument or set one in your profile.\n' +
89
+ 'Usage: xano workspace edit <workspace_id> [flags]');
90
+ }
91
+ // Build request body - only include fields that were specified
92
+ const body = {};
93
+ if (flags.name !== undefined) {
94
+ body.name = flags.name;
95
+ }
96
+ if (flags.description !== undefined) {
97
+ body.description = flags.description;
98
+ }
99
+ if (flags.swagger !== undefined) {
100
+ body.swagger = flags.swagger;
101
+ }
102
+ if (flags['require-token'] !== undefined) {
103
+ body.documentation = { require_token: flags['require-token'] };
104
+ }
105
+ // Check if at least one field is being updated
106
+ if (Object.keys(body).length === 0) {
107
+ this.error('No fields specified to update. Use --name, --description, --swagger, or --require-token flags.\n' +
108
+ 'Example: xano workspace edit 123 --name "new-name"');
109
+ }
110
+ // Construct the API URL
111
+ const apiUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}`;
112
+ // Update workspace via the API
113
+ try {
114
+ const response = await fetch(apiUrl, {
115
+ body: JSON.stringify(body),
116
+ headers: {
117
+ 'accept': 'application/json',
118
+ 'Authorization': `Bearer ${profile.access_token}`,
119
+ 'content-type': 'application/json',
120
+ },
121
+ method: 'PUT',
122
+ });
123
+ if (!response.ok) {
124
+ const errorText = await response.text();
125
+ this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
126
+ }
127
+ const workspace = await response.json();
128
+ // Output results
129
+ if (flags.output === 'json') {
130
+ this.log(JSON.stringify(workspace, null, 2));
131
+ }
132
+ else {
133
+ // summary format
134
+ this.log(`Updated workspace: ${workspace.name} (ID: ${workspace.id})`);
135
+ if (workspace.description) {
136
+ this.log(` Description: ${workspace.description}`);
137
+ }
138
+ if (workspace.swagger !== undefined) {
139
+ this.log(` Swagger: ${workspace.swagger ? 'enabled' : 'disabled'}`);
140
+ }
141
+ if (workspace.documentation?.require_token !== undefined) {
142
+ this.log(` Require Token: ${workspace.documentation.require_token}`);
143
+ }
144
+ }
145
+ }
146
+ catch (error) {
147
+ if (error instanceof Error) {
148
+ this.error(`Failed to update workspace: ${error.message}`);
149
+ }
150
+ else {
151
+ this.error(`Failed to update workspace: ${String(error)}`);
152
+ }
153
+ }
154
+ }
155
+ loadCredentials() {
156
+ const configDir = path.join(os.homedir(), '.xano');
157
+ const credentialsPath = path.join(configDir, 'credentials.yaml');
158
+ // Check if credentials file exists
159
+ if (!fs.existsSync(credentialsPath)) {
160
+ this.error(`Credentials file not found at ${credentialsPath}\n` +
161
+ `Create a profile using 'xano profile create'`);
162
+ }
163
+ // Read credentials file
164
+ try {
165
+ const fileContent = fs.readFileSync(credentialsPath, 'utf8');
166
+ const parsed = yaml.load(fileContent);
167
+ if (!parsed || typeof parsed !== 'object' || !('profiles' in parsed)) {
168
+ this.error('Credentials file has invalid format.');
169
+ }
170
+ return parsed;
171
+ }
172
+ catch (error) {
173
+ this.error(`Failed to parse credentials file: ${error}`);
174
+ }
175
+ }
176
+ }
@@ -0,0 +1,18 @@
1
+ import BaseCommand from '../../../base-command.js';
2
+ export default class WorkspaceGet extends BaseCommand {
3
+ static args: {
4
+ workspace_id: import("@oclif/core/interfaces").Arg<number | undefined, {
5
+ max?: number;
6
+ min?: number;
7
+ }>;
8
+ };
9
+ static description: string;
10
+ static examples: string[];
11
+ static flags: {
12
+ output: import("@oclif/core/interfaces").OptionFlag<string, 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
+ }