@xano/cli 0.0.95-beta.2 → 0.0.95-beta.3

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 (64) hide show
  1. package/README.md +15 -8
  2. package/dist/base-command.d.ts +24 -0
  3. package/dist/base-command.js +37 -0
  4. package/dist/commands/{ephemeral → sandbox}/env/delete/index.d.ts +1 -4
  5. package/dist/commands/{ephemeral → sandbox}/env/delete/index.js +17 -33
  6. package/dist/commands/{ephemeral → sandbox}/env/get/index.d.ts +1 -4
  7. package/dist/commands/{ephemeral → sandbox}/env/get/index.js +13 -29
  8. package/dist/commands/{ephemeral → sandbox}/env/get_all/index.d.ts +1 -4
  9. package/dist/commands/{ephemeral → sandbox}/env/get_all/index.js +16 -32
  10. package/dist/commands/{ephemeral → sandbox}/env/list/index.d.ts +1 -4
  11. package/dist/commands/sandbox/env/list/index.js +67 -0
  12. package/dist/commands/{ephemeral → sandbox}/env/set/index.d.ts +1 -4
  13. package/dist/commands/{ephemeral → sandbox}/env/set/index.js +14 -30
  14. package/dist/commands/{ephemeral → sandbox}/env/set_all/index.d.ts +1 -4
  15. package/dist/commands/{ephemeral → sandbox}/env/set_all/index.js +16 -32
  16. package/dist/commands/{ephemeral → sandbox}/get/index.d.ts +1 -4
  17. package/dist/commands/sandbox/get/index.js +48 -0
  18. package/dist/commands/sandbox/impersonate/index.d.ts +5 -0
  19. package/dist/commands/sandbox/impersonate/index.js +5 -0
  20. package/dist/commands/{ephemeral → sandbox}/license/get/index.d.ts +1 -4
  21. package/dist/commands/{ephemeral → sandbox}/license/get/index.js +16 -32
  22. package/dist/commands/{ephemeral → sandbox}/license/set/index.d.ts +1 -4
  23. package/dist/commands/{ephemeral → sandbox}/license/set/index.js +17 -33
  24. package/dist/commands/{ephemeral → sandbox}/pull/index.d.ts +1 -2
  25. package/dist/commands/{ephemeral → sandbox}/pull/index.js +11 -26
  26. package/dist/commands/{ephemeral → sandbox}/push/index.d.ts +1 -2
  27. package/dist/commands/{ephemeral → sandbox}/push/index.js +13 -28
  28. package/dist/commands/{ephemeral/delete → sandbox/reset}/index.d.ts +1 -5
  29. package/dist/commands/sandbox/reset/index.js +71 -0
  30. package/dist/commands/{ephemeral/impersonate → sandbox/review}/index.d.ts +1 -4
  31. package/dist/commands/{ephemeral/impersonate → sandbox/review}/index.js +15 -31
  32. package/dist/commands/{ephemeral/unit_test/run_all → sandbox/unit_test/list}/index.d.ts +1 -2
  33. package/dist/commands/{ephemeral → sandbox}/unit_test/list/index.js +10 -24
  34. package/dist/commands/{ephemeral → sandbox}/unit_test/run/index.d.ts +1 -2
  35. package/dist/commands/{ephemeral → sandbox}/unit_test/run/index.js +9 -23
  36. package/dist/commands/{ephemeral/unit_test/list → sandbox/unit_test/run_all}/index.d.ts +1 -2
  37. package/dist/commands/{ephemeral → sandbox}/unit_test/run_all/index.js +9 -23
  38. package/dist/commands/{ephemeral/workflow_test/get → sandbox/workflow_test/delete}/index.d.ts +1 -2
  39. package/dist/commands/{ephemeral → sandbox}/workflow_test/delete/index.js +9 -23
  40. package/dist/commands/{ephemeral/workflow_test/run → sandbox/workflow_test/get}/index.d.ts +1 -2
  41. package/dist/commands/{ephemeral → sandbox}/workflow_test/get/index.js +8 -25
  42. package/dist/commands/{ephemeral/workflow_test/run_all → sandbox/workflow_test/list}/index.d.ts +1 -2
  43. package/dist/commands/{ephemeral → sandbox}/workflow_test/list/index.js +11 -25
  44. package/dist/commands/{ephemeral/workflow_test/delete → sandbox/workflow_test/run}/index.d.ts +1 -2
  45. package/dist/commands/{ephemeral → sandbox}/workflow_test/run/index.js +9 -23
  46. package/dist/commands/{ephemeral/workflow_test/list → sandbox/workflow_test/run_all}/index.d.ts +1 -2
  47. package/dist/commands/{ephemeral → sandbox}/workflow_test/run_all/index.js +9 -23
  48. package/dist/commands/tenant/get/index.js +2 -2
  49. package/dist/commands/tenant/list/index.js +2 -2
  50. package/dist/commands/tenant/push/index.js +0 -34
  51. package/dist/commands/workspace/push/index.js +26 -0
  52. package/oclif.manifest.json +2404 -2888
  53. package/package.json +7 -7
  54. package/dist/commands/ephemeral/access/index.d.ts +0 -15
  55. package/dist/commands/ephemeral/access/index.js +0 -78
  56. package/dist/commands/ephemeral/create/index.d.ts +0 -17
  57. package/dist/commands/ephemeral/create/index.js +0 -102
  58. package/dist/commands/ephemeral/delete/index.js +0 -99
  59. package/dist/commands/ephemeral/env/list/index.js +0 -83
  60. package/dist/commands/ephemeral/get/index.js +0 -102
  61. package/dist/commands/ephemeral/list/index.d.ts +0 -15
  62. package/dist/commands/ephemeral/list/index.js +0 -109
  63. package/dist/commands/ephemeral/shared/index.d.ts +0 -15
  64. package/dist/commands/ephemeral/shared/index.js +0 -108
package/README.md CHANGED
@@ -445,18 +445,25 @@ xano tenant cluster license set <cluster_id>
445
445
  xano tenant cluster license set <cluster_id> --file ./kubeconfig.yaml
446
446
  ```
447
447
 
448
- ### Ephemeral
448
+ ### Sandbox
449
449
 
450
- Manage ephemeral tenants. Ephemeral tenants are workspace-agnostic (tier1 only) and do not run background tasks.
450
+ Manage your sandbox tenant. Each user has a single sandbox tenant that is auto-provisioned on first use.
451
451
 
452
452
  ```bash
453
- # Create an ephemeral tenant
454
- xano ephemeral create "My Ephemeral"
455
- xano ephemeral create "CI Tenant" -d "For CI/CD" -o json
453
+ # Get your sandbox tenant (creates if needed)
454
+ xano sandbox get
455
+ xano sandbox get -o json
456
456
 
457
- # Get ephemeral tenant details
458
- xano ephemeral get <tenant_name>
459
- xano ephemeral get <tenant_name> -o json
457
+ # Push/pull workspace data
458
+ xano sandbox push ./my-workspace
459
+ xano sandbox pull ./my-tenant
460
+
461
+ # Impersonate (open in browser)
462
+ xano sandbox impersonate
463
+
464
+ # Reset all workspace data
465
+ xano sandbox reset
466
+ xano sandbox reset --force
460
467
  ```
461
468
 
462
469
  ### Static Hosts
@@ -14,6 +14,16 @@ 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
+ state?: string;
25
+ xano_domain?: string;
26
+ }
17
27
  export default abstract class BaseCommand extends Command {
18
28
  static baseFlags: {
19
29
  profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
@@ -38,6 +48,20 @@ export default abstract class BaseCommand extends Command {
38
48
  * Load and parse the credentials file. Returns null if the file doesn't exist.
39
49
  */
40
50
  protected loadCredentialsFile(): CredentialsFile | null;
51
+ /**
52
+ * Get or create the singleton sandbox environment for the authenticated user.
53
+ * Returns the sandbox object (existing or newly created).
54
+ */
55
+ protected getOrCreateSandbox(profile: ProfileConfig, verbose: boolean): Promise<SandboxTenant>;
56
+ /**
57
+ * Resolve profile from flags, validating instance_origin and access_token exist.
58
+ */
59
+ protected resolveProfile(flags: {
60
+ profile?: string;
61
+ }): {
62
+ profile: ProfileConfig;
63
+ profileName: string;
64
+ };
41
65
  /**
42
66
  * Make an HTTP request with optional verbose logging.
43
67
  * 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.
@@ -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,19 @@ 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);
37
+ const tenant = await this.getOrCreateSandbox(profile, flags.verbose);
38
+ const tenantName = tenant.name;
55
39
  const envName = flags.name;
56
40
  if (!flags.force) {
57
- const confirmed = await this.confirm(`Are you sure you want to delete environment variable '${envName}' from ephemeral tenant ${tenantName}?`);
41
+ const confirmed = await this.confirm(`Are you sure you want to delete environment variable '${envName}' from sandbox environment ${tenantName}?`);
58
42
  if (!confirmed) {
59
43
  this.log('Deletion cancelled.');
60
44
  return;
61
45
  }
62
46
  }
63
- const apiUrl = `${profile.instance_origin}/api:meta/ephemeral/tenant/${tenantName}/env/${envName}`;
47
+ const apiUrl = `${profile.instance_origin}/api:meta/sandbox/tenant/${tenantName}/env/${envName}`;
64
48
  try {
65
49
  const response = await this.verboseFetch(apiUrl, {
66
50
  headers: {
@@ -77,15 +61,15 @@ Environment variable 'DATABASE_URL' deleted from ephemeral tenant my-tenant
77
61
  this.log(JSON.stringify({ deleted: true, env_name: envName, tenant_name: tenantName }, null, 2));
78
62
  }
79
63
  else {
80
- this.log(`Environment variable '${envName}' deleted from ephemeral tenant ${tenantName}`);
64
+ this.log(`Environment variable '${envName}' deleted from sandbox environment ${tenantName}`);
81
65
  }
82
66
  }
83
67
  catch (error) {
84
68
  if (error instanceof Error) {
85
- this.error(`Failed to delete ephemeral tenant environment variable: ${error.message}`);
69
+ this.error(`Failed to delete sandbox environment variable: ${error.message}`);
86
70
  }
87
71
  else {
88
- this.error(`Failed to delete ephemeral tenant environment variable: ${String(error)}`);
72
+ this.error(`Failed to delete sandbox environment variable: ${String(error)}`);
89
73
  }
90
74
  }
91
75
  }
@@ -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,12 @@ 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);
29
+ const tenant = await this.getOrCreateSandbox(profile, flags.verbose);
30
+ const tenantName = tenant.name;
47
31
  const envName = flags.name;
48
- const apiUrl = `${profile.instance_origin}/api:meta/ephemeral/tenant/${tenantName}/env/${envName}`;
32
+ const apiUrl = `${profile.instance_origin}/api:meta/sandbox/tenant/${tenantName}/env/${envName}`;
49
33
  try {
50
34
  const response = await this.verboseFetch(apiUrl, {
51
35
  headers: {
@@ -66,15 +50,15 @@ postgres://localhost:5432/mydb
66
50
  this.log(envVar.value);
67
51
  }
68
52
  else {
69
- this.log(`Environment variable '${envName}' not found for ephemeral tenant ${tenantName}`);
53
+ this.log(`Environment variable '${envName}' not found for sandbox environment ${tenantName}`);
70
54
  }
71
55
  }
72
56
  catch (error) {
73
57
  if (error instanceof Error) {
74
- this.error(`Failed to get ephemeral tenant environment variable: ${error.message}`);
58
+ this.error(`Failed to get sandbox environment variable: ${error.message}`);
75
59
  }
76
60
  else {
77
- this.error(`Failed to get ephemeral tenant environment variable: ${String(error)}`);
61
+ this.error(`Failed to get sandbox environment variable: ${String(error)}`);
78
62
  }
79
63
  }
80
64
  }
@@ -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,11 @@ 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 tenant = await this.getOrCreateSandbox(profile, flags.verbose);
40
+ const tenantName = tenant.name;
41
+ const apiUrl = `${profile.instance_origin}/api:meta/sandbox/tenant/${tenantName}/env_all`;
58
42
  try {
59
43
  const response = await this.verboseFetch(apiUrl, {
60
44
  headers: {
@@ -84,10 +68,10 @@ Environment variables saved to env_my-tenant.yaml
84
68
  }
85
69
  catch (error) {
86
70
  if (error instanceof Error) {
87
- this.error(`Failed to get ephemeral tenant environment variables: ${error.message}`);
71
+ this.error(`Failed to get sandbox environment variables: ${error.message}`);
88
72
  }
89
73
  else {
90
- this.error(`Failed to get ephemeral tenant environment variables: ${String(error)}`);
74
+ this.error(`Failed to get sandbox environment variables: ${String(error)}`);
91
75
  }
92
76
  }
93
77
  }
@@ -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: {
@@ -0,0 +1,67 @@
1
+ import { Flags } from '@oclif/core';
2
+ import BaseCommand from '../../../../base-command.js';
3
+ export default class SandboxEnvList extends BaseCommand {
4
+ static description = 'List environment variable keys for a sandbox environment';
5
+ static examples = [
6
+ `$ xano sandbox env list
7
+ Environment variables for sandbox environment:
8
+ - DATABASE_URL
9
+ - API_KEY
10
+ `,
11
+ `$ xano sandbox env list -o json`,
12
+ ];
13
+ static flags = {
14
+ ...BaseCommand.baseFlags,
15
+ output: Flags.string({
16
+ char: 'o',
17
+ default: 'summary',
18
+ description: 'Output format',
19
+ options: ['summary', 'json'],
20
+ required: false,
21
+ }),
22
+ };
23
+ async run() {
24
+ const { flags } = await this.parse(SandboxEnvList);
25
+ const { profile } = this.resolveProfile(flags);
26
+ const tenant = await this.getOrCreateSandbox(profile, flags.verbose);
27
+ const tenantName = tenant.name;
28
+ const apiUrl = `${profile.instance_origin}/api:meta/sandbox/tenant/${tenantName}/env_key`;
29
+ try {
30
+ const response = await this.verboseFetch(apiUrl, {
31
+ headers: {
32
+ accept: 'application/json',
33
+ Authorization: `Bearer ${profile.access_token}`,
34
+ },
35
+ method: 'GET',
36
+ }, flags.verbose, profile.access_token);
37
+ if (!response.ok) {
38
+ const errorText = await response.text();
39
+ this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
40
+ }
41
+ const data = (await response.json());
42
+ if (flags.output === 'json') {
43
+ this.log(JSON.stringify(data, null, 2));
44
+ }
45
+ else {
46
+ const envVars = data.env || [];
47
+ if (envVars.length === 0) {
48
+ this.log(`No environment variables found for sandbox environment ${tenantName}`);
49
+ }
50
+ else {
51
+ this.log(`Environment variables for sandbox environment ${tenantName}:`);
52
+ for (const envVar of envVars) {
53
+ this.log(` - ${envVar.name}`);
54
+ }
55
+ }
56
+ }
57
+ }
58
+ catch (error) {
59
+ if (error instanceof Error) {
60
+ this.error(`Failed to list sandbox environment variables: ${error.message}`);
61
+ }
62
+ else {
63
+ this.error(`Failed to list sandbox environment variables: ${String(error)}`);
64
+ }
65
+ }
66
+ }
67
+ }
@@ -1,8 +1,5 @@
1
1
  import BaseCommand from '../../../../base-command.js';
2
- export default class EphemeralEnvSet extends BaseCommand {
3
- static args: {
4
- tenant_name: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
5
- };
2
+ export default class SandboxEnvSet 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 EphemeralEnvSet extends BaseCommand {
4
- static args = {
5
- tenant_name: Args.string({
6
- description: 'Ephemeral tenant name',
7
- required: true,
8
- }),
9
- };
10
- static description = 'Set (create or update) an environment variable for an ephemeral tenant';
3
+ export default class SandboxEnvSet extends BaseCommand {
4
+ static description = 'Set (create or update) an environment variable for a sandbox environment';
11
5
  static examples = [
12
- `$ xano ephemeral env set my-tenant --name DATABASE_URL --value postgres://localhost:5432/mydb
13
- Environment variable 'DATABASE_URL' set for ephemeral tenant my-tenant
6
+ `$ xano sandbox env set --name DATABASE_URL --value postgres://localhost:5432/mydb
7
+ Environment variable 'DATABASE_URL' set
14
8
  `,
15
- `$ xano ephemeral env set my-tenant --name DATABASE_URL --value postgres://localhost:5432/mydb -o json`,
9
+ `$ xano sandbox env set --name DATABASE_URL --value postgres://localhost:5432/mydb -o json`,
16
10
  ];
17
11
  static flags = {
18
12
  ...BaseCommand.baseFlags,
@@ -34,22 +28,12 @@ Environment variable 'DATABASE_URL' set for ephemeral tenant my-tenant
34
28
  }),
35
29
  };
36
30
  async run() {
37
- const { args, flags } = await this.parse(EphemeralEnvSet);
38
- const profileName = flags.profile || this.getDefaultProfile();
39
- const credentials = this.loadCredentialsFile();
40
- if (!credentials || !(profileName in credentials.profiles)) {
41
- this.error(`Profile '${profileName}' not found.\n` + `Create a profile using 'xano profile create'`);
42
- }
43
- const profile = credentials.profiles[profileName];
44
- if (!profile.instance_origin) {
45
- this.error(`Profile '${profileName}' is missing instance_origin`);
46
- }
47
- if (!profile.access_token) {
48
- this.error(`Profile '${profileName}' is missing access_token`);
49
- }
50
- const tenantName = args.tenant_name;
31
+ const { flags } = await this.parse(SandboxEnvSet);
32
+ const { profile } = this.resolveProfile(flags);
33
+ const tenant = await this.getOrCreateSandbox(profile, flags.verbose);
34
+ const tenantName = tenant.name;
51
35
  const envName = flags.name;
52
- const apiUrl = `${profile.instance_origin}/api:meta/ephemeral/tenant/${tenantName}/env/${envName}`;
36
+ const apiUrl = `${profile.instance_origin}/api:meta/sandbox/tenant/${tenantName}/env/${envName}`;
53
37
  const body = {
54
38
  env: {
55
39
  name: envName,
@@ -75,15 +59,15 @@ Environment variable 'DATABASE_URL' set for ephemeral tenant my-tenant
75
59
  this.log(JSON.stringify(result, null, 2));
76
60
  }
77
61
  else {
78
- this.log(`Environment variable '${envName}' set for ephemeral tenant ${tenantName}`);
62
+ this.log(`Environment variable '${envName}' set for sandbox environment ${tenantName}`);
79
63
  }
80
64
  }
81
65
  catch (error) {
82
66
  if (error instanceof Error) {
83
- this.error(`Failed to set ephemeral tenant environment variable: ${error.message}`);
67
+ this.error(`Failed to set sandbox environment variable: ${error.message}`);
84
68
  }
85
69
  else {
86
- this.error(`Failed to set ephemeral tenant environment variable: ${String(error)}`);
70
+ this.error(`Failed to set sandbox environment variable: ${String(error)}`);
87
71
  }
88
72
  }
89
73
  }
@@ -1,8 +1,5 @@
1
1
  import BaseCommand from '../../../../base-command.js';
2
- export default class EphemeralEnvSetAll extends BaseCommand {
3
- static args: {
4
- tenant_name: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
5
- };
2
+ export default class SandboxEnvSetAll extends BaseCommand {
6
3
  static description: string;
7
4
  static examples: string[];
8
5
  static flags: {
@@ -1,22 +1,16 @@
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 EphemeralEnvSetAll extends BaseCommand {
7
- static args = {
8
- tenant_name: Args.string({
9
- description: 'Ephemeral tenant name',
10
- required: true,
11
- }),
12
- };
13
- static description = 'Set all environment variables for an ephemeral tenant from a YAML file (replaces all existing)';
6
+ export default class SandboxEnvSetAll extends BaseCommand {
7
+ static description = 'Set all environment variables for a sandbox environment from a YAML file (replaces all existing)';
14
8
  static examples = [
15
- `$ xano ephemeral env set_all my-tenant
16
- Reads from env_my-tenant.yaml
9
+ `$ xano sandbox env set_all
10
+ Reads from env_<tenant>.yaml
17
11
  `,
18
- `$ xano ephemeral env set_all my-tenant --file ./my-env.yaml`,
19
- `$ xano ephemeral env set_all my-tenant -o json`,
12
+ `$ xano sandbox env set_all --file ./my-env.yaml`,
13
+ `$ xano sandbox env set_all -o json`,
20
14
  ];
21
15
  static flags = {
22
16
  ...BaseCommand.baseFlags,
@@ -27,7 +21,7 @@ Reads from env_my-tenant.yaml
27
21
  }),
28
22
  file: Flags.string({
29
23
  char: 'f',
30
- description: 'Path to env file (default: env_<tenant_name>.yaml)',
24
+ description: 'Path to env file (default: env_<sandbox_name>.yaml)',
31
25
  required: false,
32
26
  }),
33
27
  output: Flags.string({
@@ -39,8 +33,10 @@ Reads from env_my-tenant.yaml
39
33
  }),
40
34
  };
41
35
  async run() {
42
- const { args, flags } = await this.parse(EphemeralEnvSetAll);
43
- const tenantName = args.tenant_name;
36
+ const { flags } = await this.parse(SandboxEnvSetAll);
37
+ const { profile } = this.resolveProfile(flags);
38
+ const tenant = await this.getOrCreateSandbox(profile, flags.verbose);
39
+ const tenantName = tenant.name;
44
40
  const sourceFilePath = path.resolve(flags.file || `env_${tenantName}.yaml`);
45
41
  if (!fs.existsSync(sourceFilePath)) {
46
42
  this.error(`File not found: ${sourceFilePath}`);
@@ -51,19 +47,7 @@ Reads from env_my-tenant.yaml
51
47
  this.error('Invalid env file format. Expected a YAML map of key: value pairs.');
52
48
  }
53
49
  const envs = Object.entries(envMap).map(([name, value]) => ({ name, value: String(value) }));
54
- const profileName = flags.profile || this.getDefaultProfile();
55
- const credentials = this.loadCredentialsFile();
56
- if (!credentials || !(profileName in credentials.profiles)) {
57
- this.error(`Profile '${profileName}' not found.\n` + `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 apiUrl = `${profile.instance_origin}/api:meta/ephemeral/tenant/${tenantName}/env_all`;
50
+ const apiUrl = `${profile.instance_origin}/api:meta/sandbox/tenant/${tenantName}/env_all`;
67
51
  try {
68
52
  const response = await this.verboseFetch(apiUrl, {
69
53
  body: JSON.stringify({ envs }),
@@ -83,7 +67,7 @@ Reads from env_my-tenant.yaml
83
67
  this.log(JSON.stringify(result, null, 2));
84
68
  }
85
69
  else {
86
- this.log(`All environment variables updated for ephemeral tenant ${tenantName} (${envs.length} variables)`);
70
+ this.log(`All environment variables updated for sandbox environment ${tenantName} (${envs.length} variables)`);
87
71
  }
88
72
  if (flags.clean && fs.existsSync(sourceFilePath)) {
89
73
  fs.unlinkSync(sourceFilePath);
@@ -92,10 +76,10 @@ Reads from env_my-tenant.yaml
92
76
  }
93
77
  catch (error) {
94
78
  if (error instanceof Error) {
95
- this.error(`Failed to set ephemeral tenant environment variables: ${error.message}`);
79
+ this.error(`Failed to set sandbox environment variables: ${error.message}`);
96
80
  }
97
81
  else {
98
- this.error(`Failed to set ephemeral tenant environment variables: ${String(error)}`);
82
+ this.error(`Failed to set sandbox environment variables: ${String(error)}`);
99
83
  }
100
84
  }
101
85
  }