@xano/cli 0.0.95-beta.1 → 0.0.95-beta.10

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 (79) hide show
  1. package/README.md +22 -9
  2. package/dist/base-command.d.ts +25 -0
  3. package/dist/base-command.js +37 -0
  4. package/dist/commands/auth/index.js +1 -1
  5. package/dist/commands/profile/create/index.js +2 -2
  6. package/dist/commands/profile/edit/index.js +2 -2
  7. package/dist/commands/profile/me/index.js +21 -2
  8. package/dist/commands/profile/wizard/index.js +3 -3
  9. package/dist/commands/profile/workspace/set/index.js +1 -1
  10. package/dist/commands/release/deploy/index.d.ts +17 -0
  11. package/dist/commands/release/deploy/index.js +107 -0
  12. package/dist/commands/{ephemeral → sandbox}/env/delete/index.d.ts +1 -4
  13. package/dist/commands/{ephemeral → sandbox}/env/delete/index.js +16 -34
  14. package/dist/commands/{ephemeral → sandbox}/env/get/index.d.ts +1 -4
  15. package/dist/commands/{ephemeral → sandbox}/env/get/index.js +11 -29
  16. package/dist/commands/{ephemeral → sandbox}/env/get_all/index.d.ts +1 -4
  17. package/dist/commands/{ephemeral → sandbox}/env/get_all/index.js +15 -33
  18. package/dist/commands/{ephemeral → sandbox}/env/list/index.d.ts +1 -4
  19. package/dist/commands/sandbox/env/list/index.js +65 -0
  20. package/dist/commands/{ephemeral → sandbox}/env/set/index.d.ts +1 -4
  21. package/dist/commands/{ephemeral → sandbox}/env/set/index.js +12 -30
  22. package/dist/commands/{ephemeral → sandbox}/env/set_all/index.d.ts +1 -4
  23. package/dist/commands/{ephemeral → sandbox}/env/set_all/index.js +15 -33
  24. package/dist/commands/{ephemeral → sandbox}/get/index.d.ts +1 -4
  25. package/dist/commands/sandbox/get/index.js +61 -0
  26. package/dist/commands/sandbox/impersonate/index.d.ts +5 -0
  27. package/dist/commands/sandbox/impersonate/index.js +5 -0
  28. package/dist/commands/{ephemeral → sandbox}/license/get/index.d.ts +1 -4
  29. package/dist/commands/{ephemeral → sandbox}/license/get/index.js +15 -33
  30. package/dist/commands/{ephemeral → sandbox}/license/set/index.d.ts +1 -4
  31. package/dist/commands/{ephemeral → sandbox}/license/set/index.js +16 -34
  32. package/dist/commands/{ephemeral → sandbox}/pull/index.d.ts +1 -2
  33. package/dist/commands/{ephemeral → sandbox}/pull/index.js +9 -26
  34. package/dist/commands/{ephemeral → sandbox}/push/index.d.ts +1 -2
  35. package/dist/commands/{ephemeral → sandbox}/push/index.js +11 -28
  36. package/dist/commands/{ephemeral/delete → sandbox/reset}/index.d.ts +1 -5
  37. package/dist/commands/sandbox/reset/index.js +69 -0
  38. package/dist/commands/{ephemeral/impersonate → sandbox/review}/index.d.ts +1 -4
  39. package/dist/commands/{ephemeral/impersonate → sandbox/review}/index.js +13 -31
  40. package/dist/commands/{ephemeral/unit_test/run_all → sandbox/unit_test/list}/index.d.ts +1 -2
  41. package/dist/commands/{ephemeral → sandbox}/unit_test/list/index.js +8 -24
  42. package/dist/commands/{ephemeral → sandbox}/unit_test/run/index.d.ts +1 -2
  43. package/dist/commands/{ephemeral → sandbox}/unit_test/run/index.js +7 -23
  44. package/dist/commands/{ephemeral/unit_test/list → sandbox/unit_test/run_all}/index.d.ts +1 -2
  45. package/dist/commands/{ephemeral → sandbox}/unit_test/run_all/index.js +7 -23
  46. package/dist/commands/{ephemeral/workflow_test/get → sandbox/workflow_test/delete}/index.d.ts +1 -2
  47. package/dist/commands/{ephemeral → sandbox}/workflow_test/delete/index.js +7 -23
  48. package/dist/commands/{ephemeral/workflow_test/run → sandbox/workflow_test/get}/index.d.ts +1 -2
  49. package/dist/commands/{ephemeral → sandbox}/workflow_test/get/index.js +6 -25
  50. package/dist/commands/{ephemeral/workflow_test/run_all → sandbox/workflow_test/list}/index.d.ts +1 -2
  51. package/dist/commands/{ephemeral → sandbox}/workflow_test/list/index.js +9 -25
  52. package/dist/commands/{ephemeral/workflow_test/delete → sandbox/workflow_test/run}/index.d.ts +1 -2
  53. package/dist/commands/{ephemeral → sandbox}/workflow_test/run/index.js +7 -23
  54. package/dist/commands/{ephemeral/workflow_test/list → sandbox/workflow_test/run_all}/index.d.ts +1 -2
  55. package/dist/commands/{ephemeral → sandbox}/workflow_test/run_all/index.js +7 -23
  56. package/dist/commands/tenant/create/index.d.ts +2 -1
  57. package/dist/commands/tenant/create/index.js +23 -6
  58. package/dist/commands/tenant/get/index.js +2 -2
  59. package/dist/commands/tenant/list/index.js +2 -2
  60. package/dist/commands/tenant/push/index.js +0 -34
  61. package/dist/commands/workspace/edit/index.d.ts +1 -0
  62. package/dist/commands/workspace/edit/index.js +16 -6
  63. package/dist/commands/workspace/get/index.js +9 -7
  64. package/dist/commands/workspace/list/index.d.ts +1 -0
  65. package/dist/commands/workspace/list/index.js +14 -7
  66. package/dist/commands/workspace/push/index.js +30 -2
  67. package/oclif.manifest.json +1985 -2354
  68. package/package.json +8 -8
  69. package/dist/commands/ephemeral/access/index.d.ts +0 -15
  70. package/dist/commands/ephemeral/access/index.js +0 -78
  71. package/dist/commands/ephemeral/create/index.d.ts +0 -17
  72. package/dist/commands/ephemeral/create/index.js +0 -102
  73. package/dist/commands/ephemeral/delete/index.js +0 -99
  74. package/dist/commands/ephemeral/env/list/index.js +0 -83
  75. package/dist/commands/ephemeral/get/index.js +0 -102
  76. package/dist/commands/ephemeral/list/index.d.ts +0 -15
  77. package/dist/commands/ephemeral/list/index.js +0 -109
  78. package/dist/commands/ephemeral/shared/index.d.ts +0 -15
  79. package/dist/commands/ephemeral/shared/index.js +0 -108
package/README.md CHANGED
@@ -235,6 +235,11 @@ xano release pull ./my-release -r v1.0 --env --records
235
235
  xano release push ./my-release -n "v2.0"
236
236
  xano release push ./my-release -n "v2.0" --hotfix -d "Critical fix"
237
237
  xano release push ./my-release -n "v2.0" --no-records --no-env
238
+
239
+ # Deploy a release to its workspace as a new branch
240
+ xano release deploy "v1.0"
241
+ xano release deploy "v1.0" --branch "restore-v1" --no-set_live
242
+ xano release deploy "v1.0" -w 40 -o json
238
243
  ```
239
244
 
240
245
  ### Platforms
@@ -302,7 +307,8 @@ xano tenant get <tenant_name>
302
307
 
303
308
  # Create a tenant
304
309
  xano tenant create "My Tenant"
305
- xano tenant create "My Tenant" -d "Description" --cluster_id 1 --platform_id 5
310
+ xano tenant create "My Tenant" -d "Description" --type tier2 --cluster_id 1 --platform_id 5
311
+ xano tenant create "My Tenant" --type tier2 --cluster_id 1 --license ./license.yaml
306
312
 
307
313
  # Edit a tenant
308
314
  xano tenant edit <tenant_name> --display "New Name" -d "New description"
@@ -440,18 +446,25 @@ xano tenant cluster license set <cluster_id>
440
446
  xano tenant cluster license set <cluster_id> --file ./kubeconfig.yaml
441
447
  ```
442
448
 
443
- ### Ephemeral
449
+ ### Sandbox
444
450
 
445
- Manage ephemeral tenants. Ephemeral tenants are workspace-agnostic (tier1 only) and do not run background tasks.
451
+ Manage your sandbox tenant. Each user has a single sandbox tenant that is auto-provisioned on first use.
446
452
 
447
453
  ```bash
448
- # Create an ephemeral tenant
449
- xano ephemeral create "My Ephemeral"
450
- xano ephemeral create "CI Tenant" -d "For CI/CD" -o json
454
+ # Get your sandbox tenant (creates if needed)
455
+ xano sandbox get
456
+ xano sandbox get -o json
457
+
458
+ # Push/pull workspace data
459
+ xano sandbox push ./my-workspace
460
+ xano sandbox pull ./my-tenant
461
+
462
+ # Impersonate (open in browser)
463
+ xano sandbox impersonate
451
464
 
452
- # Get ephemeral tenant details
453
- xano ephemeral get <tenant_name>
454
- xano ephemeral get <tenant_name> -o json
465
+ # Reset all workspace data
466
+ xano sandbox reset
467
+ xano sandbox reset --force
455
468
  ```
456
469
 
457
470
  ### Static Hosts
@@ -14,6 +14,17 @@ export interface CredentialsFile {
14
14
  };
15
15
  }
16
16
  export declare function buildUserAgent(version: string): string;
17
+ export interface SandboxTenant {
18
+ created_at?: string;
19
+ description?: string;
20
+ display?: string;
21
+ ephemeral?: boolean;
22
+ id: number;
23
+ name: string;
24
+ sandbox_expires_at?: string | number;
25
+ state?: string;
26
+ xano_domain?: string;
27
+ }
17
28
  export default abstract class BaseCommand extends Command {
18
29
  static baseFlags: {
19
30
  profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
@@ -38,6 +49,20 @@ export default abstract class BaseCommand extends Command {
38
49
  * Load and parse the credentials file. Returns null if the file doesn't exist.
39
50
  */
40
51
  protected loadCredentialsFile(): CredentialsFile | null;
52
+ /**
53
+ * Get or create the singleton sandbox environment for the authenticated user.
54
+ * Returns the sandbox object (existing or newly created).
55
+ */
56
+ protected getOrCreateSandbox(profile: ProfileConfig, verbose: boolean): Promise<SandboxTenant>;
57
+ /**
58
+ * Resolve profile from flags, validating instance_origin and access_token exist.
59
+ */
60
+ protected resolveProfile(flags: {
61
+ profile?: string;
62
+ }): {
63
+ profile: ProfileConfig;
64
+ profileName: string;
65
+ };
41
66
  /**
42
67
  * Make an HTTP request with optional verbose logging.
43
68
  * Use this for all Metadata API calls to support the --verbose flag.
@@ -103,6 +103,43 @@ export default class BaseCommand extends Command {
103
103
  }
104
104
  return null;
105
105
  }
106
+ /**
107
+ * Get or create the singleton sandbox environment for the authenticated user.
108
+ * Returns the sandbox object (existing or newly created).
109
+ */
110
+ async getOrCreateSandbox(profile, verbose) {
111
+ const apiUrl = `${profile.instance_origin}/api:meta/sandbox/me`;
112
+ const response = await this.verboseFetch(apiUrl, {
113
+ headers: {
114
+ accept: 'application/json',
115
+ Authorization: `Bearer ${profile.access_token}`,
116
+ },
117
+ method: 'GET',
118
+ }, verbose, profile.access_token);
119
+ if (!response.ok) {
120
+ const errorText = await response.text();
121
+ this.error(`Failed to get sandbox environment: ${response.status} ${response.statusText}\n${errorText}`);
122
+ }
123
+ return (await response.json());
124
+ }
125
+ /**
126
+ * Resolve profile from flags, validating instance_origin and access_token exist.
127
+ */
128
+ resolveProfile(flags) {
129
+ const profileName = flags.profile || this.getDefaultProfile();
130
+ const credentials = this.loadCredentialsFile();
131
+ if (!credentials || !(profileName in credentials.profiles)) {
132
+ this.error(`Profile '${profileName}' not found.\n` + `Create a profile using 'xano profile create'`);
133
+ }
134
+ const profile = credentials.profiles[profileName];
135
+ if (!profile.instance_origin) {
136
+ this.error(`Profile '${profileName}' is missing instance_origin`);
137
+ }
138
+ if (!profile.access_token) {
139
+ this.error(`Profile '${profileName}' is missing access_token`);
140
+ }
141
+ return { profile, profileName };
142
+ }
106
143
  /**
107
144
  * Make an HTTP request with optional verbose logging.
108
145
  * Use this for all Metadata API calls to support the --verbose flag.
@@ -283,7 +283,7 @@ Opening browser for Xano login at https://custom.xano.com...`,
283
283
  choices: [
284
284
  { name: '(Skip workspace)', value: '' },
285
285
  ...workspaces.map((ws) => ({
286
- name: ws.name,
286
+ name: `${ws.name} (${ws.id})`,
287
287
  value: ws.id,
288
288
  })),
289
289
  ],
@@ -98,8 +98,8 @@ Profile 'selfhosted' created successfully at ~/.xano/credentials.yaml
98
98
  const profileExists = args.name in credentials.profiles;
99
99
  credentials.profiles[args.name] = {
100
100
  access_token: flags.access_token,
101
- account_origin: flags.account_origin ?? '',
102
- instance_origin: flags.instance_origin,
101
+ account_origin: (flags.account_origin ?? '').replace(/\/+$/, ''),
102
+ instance_origin: flags.instance_origin.replace(/\/+$/, ''),
103
103
  ...(flags.workspace && { workspace: flags.workspace }),
104
104
  ...(flags.branch && { branch: flags.branch }),
105
105
  ...(flags.insecure && { insecure: true }),
@@ -128,8 +128,8 @@ Profile 'default' updated successfully at ~/.xano/credentials.yaml
128
128
  // Update only the fields that were provided
129
129
  const updatedProfile = {
130
130
  ...existingProfile,
131
- ...(flags.account_origin !== undefined && { account_origin: flags.account_origin }),
132
- ...(flags.instance_origin !== undefined && { instance_origin: flags.instance_origin }),
131
+ ...(flags.account_origin !== undefined && { account_origin: flags.account_origin.replace(/\/+$/, '') }),
132
+ ...(flags.instance_origin !== undefined && { instance_origin: flags.instance_origin.replace(/\/+$/, '') }),
133
133
  ...(flags.access_token !== undefined && { access_token: flags.access_token }),
134
134
  ...(flags.workspace !== undefined && { workspace: flags.workspace }),
135
135
  ...(flags.branch !== undefined && { branch: flags.branch }),
@@ -111,8 +111,27 @@ User Information:
111
111
  this.log(` Name: ${inst.name}`);
112
112
  if (inst.display)
113
113
  this.log(` Display: ${inst.display}`);
114
- if (profile.workspace)
115
- this.log(` Workspace: ${profile.workspace}`);
114
+ if (profile.workspace) {
115
+ let wsLabel = String(profile.workspace);
116
+ try {
117
+ const wsResponse = await this.verboseFetch(`${profile.instance_origin}/api:meta/workspace/${profile.workspace}`, {
118
+ headers: {
119
+ accept: 'application/json',
120
+ Authorization: `Bearer ${profile.access_token}`,
121
+ },
122
+ method: 'GET',
123
+ }, false, profile.access_token);
124
+ if (wsResponse.ok) {
125
+ const ws = (await wsResponse.json());
126
+ if (ws.name)
127
+ wsLabel = `${ws.name} (ID: ${profile.workspace})`;
128
+ }
129
+ }
130
+ catch {
131
+ // Fall back to just showing the ID
132
+ }
133
+ this.log(` Workspace: ${wsLabel}`);
134
+ }
116
135
  if (profile.branch)
117
136
  this.log(` Branch: ${profile.branch}`);
118
137
  }
@@ -126,7 +126,7 @@ Profile 'production' created successfully at ~/.xano/credentials.yaml
126
126
  choices: [
127
127
  { name: '(Skip workspace)', value: '' },
128
128
  ...workspaces.map((ws) => ({
129
- name: ws.name,
129
+ name: `${ws.name} (${ws.id})`,
130
130
  value: ws.id,
131
131
  })),
132
132
  ],
@@ -339,8 +339,8 @@ Profile 'production' created successfully at ~/.xano/credentials.yaml
339
339
  // Add or update the profile
340
340
  credentials.profiles[profile.name] = {
341
341
  access_token: profile.access_token,
342
- account_origin: profile.account_origin,
343
- instance_origin: profile.instance_origin,
342
+ account_origin: (profile.account_origin || '').replace(/\/+$/, ''),
343
+ instance_origin: profile.instance_origin.replace(/\/+$/, ''),
344
344
  ...(profile.workspace && { workspace: profile.workspace }),
345
345
  ...(profile.branch && { branch: profile.branch }),
346
346
  ...(profile.insecure && { insecure: true }),
@@ -40,7 +40,7 @@ Workspace updated to 'Production API' (xyz789) on profile 'production'
40
40
  const { selectedWorkspace } = await inquirer.prompt([
41
41
  {
42
42
  choices: workspaces.map((ws) => ({
43
- name: String(ws.id) === String(profile.workspace) ? `${ws.name} (current)` : ws.name,
43
+ name: String(ws.id) === String(profile.workspace) ? `${ws.name} (${ws.id}) (current)` : `${ws.name} (${ws.id})`,
44
44
  value: ws.id,
45
45
  })),
46
46
  message: 'Select a workspace',
@@ -0,0 +1,17 @@
1
+ import BaseCommand from '../../../base-command.js';
2
+ export default class ReleaseDeploy extends BaseCommand {
3
+ static args: {
4
+ release_name: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
5
+ };
6
+ static description: string;
7
+ static examples: string[];
8
+ static flags: {
9
+ branch: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
+ output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
11
+ set_live: import("@oclif/core/interfaces").BooleanFlag<boolean>;
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
+ }
@@ -0,0 +1,107 @@
1
+ import { Args, Flags } from '@oclif/core';
2
+ import BaseCommand from '../../../base-command.js';
3
+ export default class ReleaseDeploy extends BaseCommand {
4
+ static args = {
5
+ release_name: Args.string({
6
+ description: 'Name of the release to deploy',
7
+ required: true,
8
+ }),
9
+ };
10
+ static description = 'Deploy a release to its workspace as a new branch';
11
+ static examples = [
12
+ `$ xano release deploy "v1.0"
13
+ Deployed release "v1.0" to workspace 40 (branch: v1.0, set live)
14
+ `,
15
+ `$ xano release deploy "v1.0" --branch "restore-v1" --no-set_live`,
16
+ `$ xano release deploy "v1.0" -w 40 -o json`,
17
+ ];
18
+ static flags = {
19
+ ...BaseCommand.baseFlags,
20
+ branch: Flags.string({
21
+ char: 'b',
22
+ description: 'Branch label for the new branch (defaults to release branch name)',
23
+ required: false,
24
+ }),
25
+ output: Flags.string({
26
+ char: 'o',
27
+ default: 'summary',
28
+ description: 'Output format',
29
+ options: ['summary', 'json'],
30
+ required: false,
31
+ }),
32
+ set_live: Flags.boolean({
33
+ default: false,
34
+ description: 'Set the new branch as live',
35
+ required: false,
36
+ }),
37
+ workspace: Flags.string({
38
+ char: 'w',
39
+ description: 'Workspace ID (uses profile workspace if not provided)',
40
+ required: false,
41
+ }),
42
+ };
43
+ async run() {
44
+ const { args, flags } = await this.parse(ReleaseDeploy);
45
+ const profileName = flags.profile || this.getDefaultProfile();
46
+ const credentials = this.loadCredentialsFile();
47
+ if (!credentials || !(profileName in credentials.profiles)) {
48
+ this.error(`Profile '${profileName}' not found.\n` + `Create a profile using 'xano profile create'`);
49
+ }
50
+ const profile = credentials.profiles[profileName];
51
+ if (!profile.instance_origin) {
52
+ this.error(`Profile '${profileName}' is missing instance_origin`);
53
+ }
54
+ if (!profile.access_token) {
55
+ this.error(`Profile '${profileName}' is missing access_token`);
56
+ }
57
+ const workspaceId = flags.workspace || profile.workspace;
58
+ if (!workspaceId) {
59
+ this.error('No workspace ID provided. Use --workspace flag or set one in your profile.');
60
+ }
61
+ const releaseName = encodeURIComponent(args.release_name);
62
+ const apiUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}/release/${releaseName}/deploy`;
63
+ const body = {
64
+ set_live: flags.set_live,
65
+ };
66
+ if (flags.branch)
67
+ body.branch = flags.branch;
68
+ this.warn('This may take a few minutes. Please be patient.');
69
+ const startTime = Date.now();
70
+ try {
71
+ const response = await this.verboseFetch(apiUrl, {
72
+ body: JSON.stringify(body),
73
+ headers: {
74
+ accept: 'application/json',
75
+ Authorization: `Bearer ${profile.access_token}`,
76
+ 'Content-Type': 'application/json',
77
+ },
78
+ method: 'POST',
79
+ }, flags.verbose, profile.access_token);
80
+ if (!response.ok) {
81
+ const errorText = await response.text();
82
+ this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
83
+ }
84
+ const release = (await response.json());
85
+ if (flags.output === 'json') {
86
+ this.log(JSON.stringify(release, null, 2));
87
+ }
88
+ else {
89
+ const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
90
+ const branchLabel = flags.branch || release.branch || 'default';
91
+ const liveStatus = flags.set_live ? ', set live' : '';
92
+ this.log(`Deployed release "${release.name}" to workspace ${workspaceId} (branch: ${branchLabel}${liveStatus})`);
93
+ if (release.description)
94
+ this.log(` Description: ${release.description}`);
95
+ this.log(` Time: ${elapsed}s`);
96
+ }
97
+ }
98
+ catch (error) {
99
+ if (error instanceof Error) {
100
+ this.error(`Failed to deploy release: ${error.message}`);
101
+ }
102
+ else {
103
+ this.error(`Failed to deploy release: ${String(error)}`);
104
+ }
105
+ }
106
+ }
107
+ }
@@ -1,8 +1,5 @@
1
1
  import BaseCommand from '../../../../base-command.js';
2
- export default class EphemeralEnvDelete extends BaseCommand {
3
- static args: {
4
- tenant_name: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
5
- };
2
+ export default class SandboxEnvDelete extends BaseCommand {
6
3
  static description: string;
7
4
  static examples: string[];
8
5
  static flags: {
@@ -1,20 +1,14 @@
1
- import { Args, Flags } from '@oclif/core';
1
+ import { Flags } from '@oclif/core';
2
2
  import BaseCommand from '../../../../base-command.js';
3
- export default class EphemeralEnvDelete extends BaseCommand {
4
- static args = {
5
- tenant_name: Args.string({
6
- description: 'Ephemeral tenant name',
7
- required: true,
8
- }),
9
- };
10
- static description = 'Delete an environment variable from an ephemeral tenant';
3
+ export default class SandboxEnvDelete extends BaseCommand {
4
+ static description = 'Delete an environment variable from a sandbox environment';
11
5
  static examples = [
12
- `$ xano ephemeral env delete my-tenant --name DATABASE_URL
13
- Are you sure you want to delete environment variable 'DATABASE_URL' from ephemeral tenant my-tenant? (y/N) y
14
- Environment variable 'DATABASE_URL' deleted from ephemeral tenant my-tenant
6
+ `$ xano sandbox env delete --name DATABASE_URL
7
+ Are you sure you want to delete environment variable 'DATABASE_URL'? (y/N) y
8
+ Environment variable 'DATABASE_URL' deleted
15
9
  `,
16
- `$ xano ephemeral env delete my-tenant --name DATABASE_URL --force`,
17
- `$ xano ephemeral env delete my-tenant --name DATABASE_URL -f -o json`,
10
+ `$ xano sandbox env delete --name DATABASE_URL --force`,
11
+ `$ xano sandbox env delete --name DATABASE_URL -f -o json`,
18
12
  ];
19
13
  static flags = {
20
14
  ...BaseCommand.baseFlags,
@@ -38,29 +32,17 @@ Environment variable 'DATABASE_URL' deleted from ephemeral tenant my-tenant
38
32
  }),
39
33
  };
40
34
  async run() {
41
- const { args, flags } = await this.parse(EphemeralEnvDelete);
42
- const profileName = flags.profile || this.getDefaultProfile();
43
- const credentials = this.loadCredentialsFile();
44
- if (!credentials || !(profileName in credentials.profiles)) {
45
- this.error(`Profile '${profileName}' not found.\n` + `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 tenantName = args.tenant_name;
35
+ const { flags } = await this.parse(SandboxEnvDelete);
36
+ const { profile } = this.resolveProfile(flags);
55
37
  const envName = flags.name;
56
38
  if (!flags.force) {
57
- const confirmed = await this.confirm(`Are you sure you want to delete environment variable '${envName}' from ephemeral tenant ${tenantName}?`);
39
+ const confirmed = await this.confirm(`Are you sure you want to delete environment variable '${envName}' from sandbox environment?`);
58
40
  if (!confirmed) {
59
41
  this.log('Deletion cancelled.');
60
42
  return;
61
43
  }
62
44
  }
63
- const apiUrl = `${profile.instance_origin}/api:meta/ephemeral/tenant/${tenantName}/env/${envName}`;
45
+ const apiUrl = `${profile.instance_origin}/api:meta/sandbox/env/${envName}`;
64
46
  try {
65
47
  const response = await this.verboseFetch(apiUrl, {
66
48
  headers: {
@@ -74,18 +56,18 @@ Environment variable 'DATABASE_URL' deleted from ephemeral tenant my-tenant
74
56
  this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
75
57
  }
76
58
  if (flags.output === 'json') {
77
- this.log(JSON.stringify({ deleted: true, env_name: envName, tenant_name: tenantName }, null, 2));
59
+ this.log(JSON.stringify({ deleted: true, env_name: envName }, null, 2));
78
60
  }
79
61
  else {
80
- this.log(`Environment variable '${envName}' deleted from ephemeral tenant ${tenantName}`);
62
+ this.log(`Environment variable '${envName}' deleted from sandbox environment`);
81
63
  }
82
64
  }
83
65
  catch (error) {
84
66
  if (error instanceof Error) {
85
- this.error(`Failed to delete ephemeral tenant environment variable: ${error.message}`);
67
+ this.error(`Failed to delete sandbox environment variable: ${error.message}`);
86
68
  }
87
69
  else {
88
- this.error(`Failed to delete ephemeral tenant environment variable: ${String(error)}`);
70
+ this.error(`Failed to delete sandbox environment variable: ${String(error)}`);
89
71
  }
90
72
  }
91
73
  }
@@ -1,8 +1,5 @@
1
1
  import BaseCommand from '../../../../base-command.js';
2
- export default class EphemeralEnvGet extends BaseCommand {
3
- static args: {
4
- tenant_name: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
5
- };
2
+ export default class SandboxEnvGet extends BaseCommand {
6
3
  static description: string;
7
4
  static examples: string[];
8
5
  static flags: {
@@ -1,18 +1,12 @@
1
- import { Args, Flags } from '@oclif/core';
1
+ import { Flags } from '@oclif/core';
2
2
  import BaseCommand from '../../../../base-command.js';
3
- export default class EphemeralEnvGet extends BaseCommand {
4
- static args = {
5
- tenant_name: Args.string({
6
- description: 'Ephemeral tenant name',
7
- required: true,
8
- }),
9
- };
10
- static description = 'Get a single environment variable for an ephemeral tenant';
3
+ export default class SandboxEnvGet extends BaseCommand {
4
+ static description = 'Get a single environment variable for a sandbox environment';
11
5
  static examples = [
12
- `$ xano ephemeral env get my-tenant --name DATABASE_URL
6
+ `$ xano sandbox env get --name DATABASE_URL
13
7
  postgres://localhost:5432/mydb
14
8
  `,
15
- `$ xano ephemeral env get my-tenant --name DATABASE_URL -o json`,
9
+ `$ xano sandbox env get --name DATABASE_URL -o json`,
16
10
  ];
17
11
  static flags = {
18
12
  ...BaseCommand.baseFlags,
@@ -30,22 +24,10 @@ postgres://localhost:5432/mydb
30
24
  }),
31
25
  };
32
26
  async run() {
33
- const { args, flags } = await this.parse(EphemeralEnvGet);
34
- const profileName = flags.profile || this.getDefaultProfile();
35
- const credentials = this.loadCredentialsFile();
36
- if (!credentials || !(profileName in credentials.profiles)) {
37
- this.error(`Profile '${profileName}' not found.\n` + `Create a profile using 'xano profile create'`);
38
- }
39
- const profile = credentials.profiles[profileName];
40
- if (!profile.instance_origin) {
41
- this.error(`Profile '${profileName}' is missing instance_origin`);
42
- }
43
- if (!profile.access_token) {
44
- this.error(`Profile '${profileName}' is missing access_token`);
45
- }
46
- const tenantName = args.tenant_name;
27
+ const { flags } = await this.parse(SandboxEnvGet);
28
+ const { profile } = this.resolveProfile(flags);
47
29
  const envName = flags.name;
48
- const apiUrl = `${profile.instance_origin}/api:meta/ephemeral/tenant/${tenantName}/env/${envName}`;
30
+ const apiUrl = `${profile.instance_origin}/api:meta/sandbox/env/${envName}`;
49
31
  try {
50
32
  const response = await this.verboseFetch(apiUrl, {
51
33
  headers: {
@@ -66,15 +48,15 @@ postgres://localhost:5432/mydb
66
48
  this.log(envVar.value);
67
49
  }
68
50
  else {
69
- this.log(`Environment variable '${envName}' not found for ephemeral tenant ${tenantName}`);
51
+ this.log(`Environment variable '${envName}' not found for sandbox environment`);
70
52
  }
71
53
  }
72
54
  catch (error) {
73
55
  if (error instanceof Error) {
74
- this.error(`Failed to get ephemeral tenant environment variable: ${error.message}`);
56
+ this.error(`Failed to get sandbox environment variable: ${error.message}`);
75
57
  }
76
58
  else {
77
- this.error(`Failed to get ephemeral tenant environment variable: ${String(error)}`);
59
+ this.error(`Failed to get sandbox environment variable: ${String(error)}`);
78
60
  }
79
61
  }
80
62
  }
@@ -1,8 +1,5 @@
1
1
  import BaseCommand from '../../../../base-command.js';
2
- export default class EphemeralEnvGetAll extends BaseCommand {
3
- static args: {
4
- tenant_name: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
5
- };
2
+ export default class SandboxEnvGetAll extends BaseCommand {
6
3
  static description: string;
7
4
  static examples: string[];
8
5
  static flags: {
@@ -1,29 +1,23 @@
1
- import { Args, Flags } from '@oclif/core';
1
+ import { Flags } from '@oclif/core';
2
2
  import * as yaml from 'js-yaml';
3
3
  import * as fs from 'node:fs';
4
4
  import * as path from 'node:path';
5
5
  import BaseCommand from '../../../../base-command.js';
6
- export default class EphemeralEnvGetAll extends BaseCommand {
7
- static args = {
8
- tenant_name: Args.string({
9
- description: 'Ephemeral tenant name',
10
- required: true,
11
- }),
12
- };
13
- static description = 'Get all environment variables for an ephemeral tenant and save to a YAML file';
6
+ export default class SandboxEnvGetAll extends BaseCommand {
7
+ static description = 'Get all environment variables for a sandbox environment and save to a YAML file';
14
8
  static examples = [
15
- `$ xano ephemeral env get_all my-tenant
16
- Environment variables saved to env_my-tenant.yaml
9
+ `$ xano sandbox env get_all
10
+ Environment variables saved to env_<tenant>.yaml
17
11
  `,
18
- `$ xano ephemeral env get_all my-tenant --file ./my-env.yaml`,
19
- `$ xano ephemeral env get_all my-tenant --view`,
20
- `$ xano ephemeral env get_all my-tenant -o json`,
12
+ `$ xano sandbox env get_all --file ./my-env.yaml`,
13
+ `$ xano sandbox env get_all --view`,
14
+ `$ xano sandbox env get_all -o json`,
21
15
  ];
22
16
  static flags = {
23
17
  ...BaseCommand.baseFlags,
24
18
  file: Flags.string({
25
19
  char: 'f',
26
- description: 'Output file path (default: env_<tenant_name>.yaml)',
20
+ description: 'Output file path (default: env_<sandbox_name>.yaml)',
27
21
  required: false,
28
22
  }),
29
23
  output: Flags.string({
@@ -40,21 +34,9 @@ Environment variables saved to env_my-tenant.yaml
40
34
  }),
41
35
  };
42
36
  async run() {
43
- const { args, flags } = await this.parse(EphemeralEnvGetAll);
44
- const profileName = flags.profile || this.getDefaultProfile();
45
- const credentials = this.loadCredentialsFile();
46
- if (!credentials || !(profileName in credentials.profiles)) {
47
- this.error(`Profile '${profileName}' not found.\n` + `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 tenantName = args.tenant_name;
57
- const apiUrl = `${profile.instance_origin}/api:meta/ephemeral/tenant/${tenantName}/env_all`;
37
+ const { flags } = await this.parse(SandboxEnvGetAll);
38
+ const { profile } = this.resolveProfile(flags);
39
+ const apiUrl = `${profile.instance_origin}/api:meta/sandbox/env_all`;
58
40
  try {
59
41
  const response = await this.verboseFetch(apiUrl, {
60
42
  headers: {
@@ -76,7 +58,7 @@ Environment variables saved to env_my-tenant.yaml
76
58
  this.log(envYaml.trimEnd());
77
59
  }
78
60
  else {
79
- const filePath = path.resolve(flags.file || `env_${tenantName}.yaml`);
61
+ const filePath = path.resolve(flags.file || `env.yaml`);
80
62
  const envYaml = yaml.dump(envMap, { lineWidth: -1, sortKeys: true });
81
63
  fs.writeFileSync(filePath, envYaml, 'utf8');
82
64
  this.log(`Environment variables saved to ${filePath}`);
@@ -84,10 +66,10 @@ Environment variables saved to env_my-tenant.yaml
84
66
  }
85
67
  catch (error) {
86
68
  if (error instanceof Error) {
87
- this.error(`Failed to get ephemeral tenant environment variables: ${error.message}`);
69
+ this.error(`Failed to get sandbox environment variables: ${error.message}`);
88
70
  }
89
71
  else {
90
- this.error(`Failed to get ephemeral tenant environment variables: ${String(error)}`);
72
+ this.error(`Failed to get sandbox environment variables: ${String(error)}`);
91
73
  }
92
74
  }
93
75
  }
@@ -1,8 +1,5 @@
1
1
  import BaseCommand from '../../../../base-command.js';
2
- export default class EphemeralEnvList extends BaseCommand {
3
- static args: {
4
- tenant_name: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
5
- };
2
+ export default class SandboxEnvList extends BaseCommand {
6
3
  static description: string;
7
4
  static examples: string[];
8
5
  static flags: {