@xano/cli 0.0.95-beta.1 → 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 (66) hide show
  1. package/README.md +20 -8
  2. package/dist/base-command.d.ts +24 -0
  3. package/dist/base-command.js +37 -0
  4. package/dist/commands/release/deploy/index.d.ts +17 -0
  5. package/dist/commands/release/deploy/index.js +107 -0
  6. package/dist/commands/{ephemeral → sandbox}/env/delete/index.d.ts +1 -4
  7. package/dist/commands/{ephemeral → sandbox}/env/delete/index.js +17 -33
  8. package/dist/commands/{ephemeral → sandbox}/env/get/index.d.ts +1 -4
  9. package/dist/commands/{ephemeral → sandbox}/env/get/index.js +13 -29
  10. package/dist/commands/{ephemeral → sandbox}/env/get_all/index.d.ts +1 -4
  11. package/dist/commands/{ephemeral → sandbox}/env/get_all/index.js +16 -32
  12. package/dist/commands/{ephemeral → sandbox}/env/list/index.d.ts +1 -4
  13. package/dist/commands/sandbox/env/list/index.js +67 -0
  14. package/dist/commands/{ephemeral → sandbox}/env/set/index.d.ts +1 -4
  15. package/dist/commands/{ephemeral → sandbox}/env/set/index.js +14 -30
  16. package/dist/commands/{ephemeral → sandbox}/env/set_all/index.d.ts +1 -4
  17. package/dist/commands/{ephemeral → sandbox}/env/set_all/index.js +16 -32
  18. package/dist/commands/{ephemeral → sandbox}/get/index.d.ts +1 -4
  19. package/dist/commands/sandbox/get/index.js +48 -0
  20. package/dist/commands/sandbox/impersonate/index.d.ts +5 -0
  21. package/dist/commands/sandbox/impersonate/index.js +5 -0
  22. package/dist/commands/{ephemeral → sandbox}/license/get/index.d.ts +1 -4
  23. package/dist/commands/{ephemeral → sandbox}/license/get/index.js +16 -32
  24. package/dist/commands/{ephemeral → sandbox}/license/set/index.d.ts +1 -4
  25. package/dist/commands/{ephemeral → sandbox}/license/set/index.js +17 -33
  26. package/dist/commands/{ephemeral → sandbox}/pull/index.d.ts +1 -2
  27. package/dist/commands/{ephemeral → sandbox}/pull/index.js +11 -26
  28. package/dist/commands/{ephemeral → sandbox}/push/index.d.ts +1 -2
  29. package/dist/commands/{ephemeral → sandbox}/push/index.js +13 -28
  30. package/dist/commands/{ephemeral/delete → sandbox/reset}/index.d.ts +1 -5
  31. package/dist/commands/sandbox/reset/index.js +71 -0
  32. package/dist/commands/{ephemeral/impersonate → sandbox/review}/index.d.ts +1 -4
  33. package/dist/commands/{ephemeral/impersonate → sandbox/review}/index.js +15 -31
  34. package/dist/commands/{ephemeral/unit_test/run_all → sandbox/unit_test/list}/index.d.ts +1 -2
  35. package/dist/commands/{ephemeral → sandbox}/unit_test/list/index.js +10 -24
  36. package/dist/commands/{ephemeral → sandbox}/unit_test/run/index.d.ts +1 -2
  37. package/dist/commands/{ephemeral → sandbox}/unit_test/run/index.js +9 -23
  38. package/dist/commands/{ephemeral/unit_test/list → sandbox/unit_test/run_all}/index.d.ts +1 -2
  39. package/dist/commands/{ephemeral → sandbox}/unit_test/run_all/index.js +9 -23
  40. package/dist/commands/{ephemeral/workflow_test/get → sandbox/workflow_test/delete}/index.d.ts +1 -2
  41. package/dist/commands/{ephemeral → sandbox}/workflow_test/delete/index.js +9 -23
  42. package/dist/commands/{ephemeral/workflow_test/run → sandbox/workflow_test/get}/index.d.ts +1 -2
  43. package/dist/commands/{ephemeral → sandbox}/workflow_test/get/index.js +8 -25
  44. package/dist/commands/{ephemeral/workflow_test/run_all → sandbox/workflow_test/list}/index.d.ts +1 -2
  45. package/dist/commands/{ephemeral → sandbox}/workflow_test/list/index.js +11 -25
  46. package/dist/commands/{ephemeral/workflow_test/delete → sandbox/workflow_test/run}/index.d.ts +1 -2
  47. package/dist/commands/{ephemeral → sandbox}/workflow_test/run/index.js +9 -23
  48. package/dist/commands/{ephemeral/workflow_test/list → sandbox/workflow_test/run_all}/index.d.ts +1 -2
  49. package/dist/commands/{ephemeral → sandbox}/workflow_test/run_all/index.js +9 -23
  50. package/dist/commands/tenant/get/index.js +2 -2
  51. package/dist/commands/tenant/list/index.js +2 -2
  52. package/dist/commands/tenant/push/index.js +0 -34
  53. package/dist/commands/workspace/push/index.js +26 -0
  54. package/oclif.manifest.json +2266 -2658
  55. package/package.json +7 -7
  56. package/dist/commands/ephemeral/access/index.d.ts +0 -15
  57. package/dist/commands/ephemeral/access/index.js +0 -78
  58. package/dist/commands/ephemeral/create/index.d.ts +0 -17
  59. package/dist/commands/ephemeral/create/index.js +0 -102
  60. package/dist/commands/ephemeral/delete/index.js +0 -99
  61. package/dist/commands/ephemeral/env/list/index.js +0 -83
  62. package/dist/commands/ephemeral/get/index.js +0 -102
  63. package/dist/commands/ephemeral/list/index.d.ts +0 -15
  64. package/dist/commands/ephemeral/list/index.js +0 -109
  65. package/dist/commands/ephemeral/shared/index.d.ts +0 -15
  66. package/dist/commands/ephemeral/shared/index.js +0 -108
@@ -1,19 +1,19 @@
1
1
  import { Args, Flags } from '@oclif/core';
2
2
  import BaseCommand from '../../../../base-command.js';
3
- export default class EphemeralWorkflowTestRun extends BaseCommand {
3
+ export default class SandboxWorkflowTestRun extends BaseCommand {
4
4
  static args = {
5
5
  workflow_test_id: Args.integer({
6
6
  description: 'ID of the workflow test to run',
7
7
  required: true,
8
8
  }),
9
9
  };
10
- static description = 'Run a workflow test for an ephemeral tenant';
10
+ static description = 'Run a workflow test for a sandbox environment';
11
11
  static examples = [
12
- `$ xano ephemeral workflow-test run 42 -t e1a2-b3c4-x5y6
12
+ `$ xano sandbox workflow-test run 42
13
13
  Running workflow test 42...
14
14
  Result: PASS (0.25s)
15
15
  `,
16
- `$ xano ephemeral workflow-test run 42 -t e1a2-b3c4-x5y6 -o json`,
16
+ `$ xano sandbox workflow-test run 42 -o json`,
17
17
  ];
18
18
  static flags = {
19
19
  ...BaseCommand.baseFlags,
@@ -24,27 +24,13 @@ Result: PASS (0.25s)
24
24
  options: ['summary', 'json'],
25
25
  required: false,
26
26
  }),
27
- tenant: Flags.string({
28
- char: 't',
29
- description: 'Ephemeral tenant name',
30
- required: true,
31
- }),
32
27
  };
33
28
  async run() {
34
- const { args, flags } = await this.parse(EphemeralWorkflowTestRun);
35
- const profileName = flags.profile || this.getDefaultProfile();
36
- const credentials = this.loadCredentialsFile();
37
- if (!credentials || !(profileName in credentials.profiles)) {
38
- this.error(`Profile '${profileName}' not found.\nCreate a profile using 'xano profile create'`);
39
- }
40
- const profile = credentials.profiles[profileName];
41
- if (!profile.instance_origin) {
42
- this.error(`Profile '${profileName}' is missing instance_origin`);
43
- }
44
- if (!profile.access_token) {
45
- this.error(`Profile '${profileName}' is missing access_token`);
46
- }
47
- const apiUrl = `${profile.instance_origin}/api:meta/ephemeral/tenant/${encodeURIComponent(flags.tenant)}/workflow_test/${args.workflow_test_id}/run`;
29
+ const { args, flags } = await this.parse(SandboxWorkflowTestRun);
30
+ const { profile } = this.resolveProfile(flags);
31
+ const tenant = await this.getOrCreateSandbox(profile, flags.verbose);
32
+ const tenantName = tenant.name;
33
+ const apiUrl = `${profile.instance_origin}/api:meta/sandbox/tenant/${encodeURIComponent(tenantName)}/workflow_test/${args.workflow_test_id}/run`;
48
34
  try {
49
35
  if (flags.output === 'summary') {
50
36
  this.log(`Running workflow test ${args.workflow_test_id}...`);
@@ -1,11 +1,10 @@
1
1
  import BaseCommand from '../../../../base-command.js';
2
- export default class EphemeralWorkflowTestList extends BaseCommand {
2
+ export default class SandboxWorkflowTestRunAll extends BaseCommand {
3
3
  static description: string;
4
4
  static examples: string[];
5
5
  static flags: {
6
6
  branch: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
7
7
  output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
8
- tenant: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
9
8
  profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
9
  verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
11
10
  };
@@ -1,9 +1,9 @@
1
1
  import { Flags } from '@oclif/core';
2
2
  import BaseCommand from '../../../../base-command.js';
3
- export default class EphemeralWorkflowTestRunAll extends BaseCommand {
4
- static description = 'Run all workflow tests for an ephemeral tenant';
3
+ export default class SandboxWorkflowTestRunAll extends BaseCommand {
4
+ static description = 'Run all workflow tests for a sandbox environment';
5
5
  static examples = [
6
- `$ xano ephemeral workflow-test run-all -t e1a2-b3c4-x5y6
6
+ `$ xano sandbox workflow-test run-all
7
7
  Running 3 workflow tests...
8
8
 
9
9
  PASS my-test (0.25s)
@@ -12,7 +12,7 @@ FAIL data-check (0.10s)
12
12
 
13
13
  Results: 2 passed, 1 failed
14
14
  `,
15
- `$ xano ephemeral workflow-test run-all -t e1a2-b3c4-x5y6 -o json`,
15
+ `$ xano sandbox workflow-test run-all -o json`,
16
16
  ];
17
17
  static flags = {
18
18
  ...BaseCommand.baseFlags,
@@ -28,27 +28,13 @@ Results: 2 passed, 1 failed
28
28
  options: ['summary', 'json'],
29
29
  required: false,
30
30
  }),
31
- tenant: Flags.string({
32
- char: 't',
33
- description: 'Ephemeral tenant name',
34
- required: true,
35
- }),
36
31
  };
37
32
  async run() {
38
- const { flags } = await this.parse(EphemeralWorkflowTestRunAll);
39
- const profileName = flags.profile || this.getDefaultProfile();
40
- const credentials = this.loadCredentialsFile();
41
- if (!credentials || !(profileName in credentials.profiles)) {
42
- this.error(`Profile '${profileName}' not found.\nCreate a profile using 'xano profile create'`);
43
- }
44
- const profile = credentials.profiles[profileName];
45
- if (!profile.instance_origin) {
46
- this.error(`Profile '${profileName}' is missing instance_origin`);
47
- }
48
- if (!profile.access_token) {
49
- this.error(`Profile '${profileName}' is missing access_token`);
50
- }
51
- const baseUrl = `${profile.instance_origin}/api:meta/ephemeral/tenant/${encodeURIComponent(flags.tenant)}/workflow_test`;
33
+ const { flags } = await this.parse(SandboxWorkflowTestRunAll);
34
+ const { profile } = this.resolveProfile(flags);
35
+ const tenant = await this.getOrCreateSandbox(profile, flags.verbose);
36
+ const tenantName = tenant.name;
37
+ const baseUrl = `${profile.instance_origin}/api:meta/sandbox/tenant/${encodeURIComponent(tenantName)}/workflow_test`;
52
38
  try {
53
39
  // Step 1: List all workflow tests
54
40
  const listParams = new URLSearchParams();
@@ -99,8 +99,8 @@ Tenant: My Tenant (my-tenant)
99
99
  this.log(` Tasks: ${tenant.tasks}`);
100
100
  if (tenant.ingress !== undefined)
101
101
  this.log(` Ingress: ${tenant.ingress}`);
102
- if (tenant.ephemeral)
103
- this.log(` Ephemeral: ${tenant.ephemeral}`);
102
+ if (tenant.type)
103
+ this.log(` Type: ${tenant.type}`);
104
104
  if (tenant.deployed_at) {
105
105
  const d = new Date(tenant.deployed_at);
106
106
  const deployedDate = Number.isNaN(d.getTime()) ? tenant.deployed_at : d.toISOString().split('T')[0];
@@ -92,8 +92,8 @@ Tenants in workspace 5:
92
92
  for (const tenant of tenants) {
93
93
  const state = tenant.state ? ` [${tenant.state}]` : '';
94
94
  const license = tenant.license ? ` - ${tenant.license}` : '';
95
- const ephemeral = tenant.ephemeral ? ' [ephemeral]' : '';
96
- this.log(` - ${tenant.display || tenant.name} (${tenant.name})${state}${license}${ephemeral}`);
95
+ const typeLabel = tenant.type && tenant.type !== 'standard' ? ` [${tenant.type}]` : '';
96
+ this.log(` - ${tenant.display || tenant.name} (${tenant.name})${state}${license}${typeLabel}`);
97
97
  if (tenant.cluster?.name)
98
98
  this.log(` Cluster: ${tenant.cluster.name}`);
99
99
  const releaseName = typeof tenant.release === 'string' ? tenant.release : tenant.release?.name;
@@ -100,40 +100,6 @@ Truncate all table records before importing
100
100
  ` 2. Set it in your profile using: xano profile:edit ${profileName} -w <workspace_id>`);
101
101
  }
102
102
  const tenantName = flags.tenant;
103
- // Fetch tenant details and verify it's ephemeral
104
- const tenantApiUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}/tenant/${tenantName}`;
105
- try {
106
- const tenantResponse = await this.verboseFetch(tenantApiUrl, {
107
- headers: {
108
- accept: 'application/json',
109
- Authorization: `Bearer ${profile.access_token}`,
110
- },
111
- method: 'GET',
112
- }, flags.verbose, profile.access_token);
113
- if (!tenantResponse.ok) {
114
- const errorText = await tenantResponse.text();
115
- this.error(`Failed to fetch tenant '${tenantName}' (${tenantResponse.status}): ${errorText}`);
116
- }
117
- const tenantData = (await tenantResponse.json());
118
- if (!tenantData.ephemeral) {
119
- this.error(`Tenant '${tenantName}' is not ephemeral. Push is only allowed for ephemeral tenants.\n` +
120
- `Create an ephemeral tenant with: xano ephemeral create "name"`);
121
- }
122
- }
123
- catch (error) {
124
- if (error instanceof Error && error.message.includes('is not ephemeral')) {
125
- throw error;
126
- }
127
- if (error instanceof Error && error.message.includes('Failed to fetch tenant')) {
128
- throw error;
129
- }
130
- if (error instanceof Error) {
131
- this.error(`Failed to verify tenant: ${error.message}`);
132
- }
133
- else {
134
- this.error(`Failed to verify tenant: ${String(error)}`);
135
- }
136
- }
137
103
  // Resolve the input directory
138
104
  const inputDir = path.resolve(args.directory);
139
105
  if (!fs.existsSync(inputDir)) {
@@ -282,6 +282,24 @@ Push functions but exclude test files
282
282
  }
283
283
  else {
284
284
  const errorText = await dryRunResponse.text();
285
+ // Check if push is disabled on this workspace
286
+ try {
287
+ const errorJson = JSON.parse(errorText);
288
+ if (errorJson.message?.includes('Push is disabled')) {
289
+ this.log('');
290
+ this.log(ux.colorize('red', ux.colorize('bold', 'Direct push to this workspace is disabled.')));
291
+ this.log(ux.colorize('dim', 'To apply changes to the workspace, use the sandbox review flow:'));
292
+ this.log(` ${ux.colorize('cyan', 'xano sandbox push')} ${ux.colorize('dim', '— push changes to your sandbox')}`);
293
+ this.log(` ${ux.colorize('cyan', 'xano sandbox review')} ${ux.colorize('dim', '— edit any logic, inspect the snapshot diff, and promote changes to the workspace')}`);
294
+ this.log('');
295
+ this.log(ux.colorize('dim', 'To enable direct push, go to Workspace Settings → CLI → Allow Direct Workspace Push.'));
296
+ this.log('');
297
+ return;
298
+ }
299
+ }
300
+ catch {
301
+ // Not JSON, fall through
302
+ }
285
303
  this.warn(`Push preview failed (${dryRunResponse.status}). Skipping preview.`);
286
304
  if (flags.verbose) {
287
305
  this.log(ux.colorize('dim', errorText));
@@ -465,6 +483,14 @@ Push functions but exclude test files
465
483
  if (errorJson.payload?.param) {
466
484
  errorMessage += `\n Parameter: ${errorJson.payload.param}`;
467
485
  }
486
+ // Provide clear guidance when push is disabled
487
+ if (errorJson.message?.includes('Push is disabled')) {
488
+ this.error(`Push is disabled for this workspace.\n\n` +
489
+ `To enable, go to Workspace Settings and turn on "Allow Push".\n\n` +
490
+ `Alternatively, use sandbox commands:\n` +
491
+ ` xano sandbox push ${args.directory}\n` +
492
+ ` xano sandbox impersonate`);
493
+ }
468
494
  }
469
495
  catch {
470
496
  errorMessage += `\n${errorText}`;