@xano/cli 0.0.30 → 0.0.32
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.
- package/dist/base-command.js +1 -1
- package/dist/commands/platform/get/index.d.ts +18 -0
- package/dist/commands/platform/get/index.js +126 -0
- package/dist/commands/platform/list/index.d.ts +12 -0
- package/dist/commands/platform/list/index.js +113 -0
- package/dist/commands/release/create/index.d.ts +18 -0
- package/dist/commands/release/create/index.js +138 -0
- package/dist/commands/release/delete/index.d.ts +21 -0
- package/dist/commands/release/delete/index.js +134 -0
- package/dist/commands/release/edit/index.d.ts +21 -0
- package/dist/commands/release/edit/index.js +137 -0
- package/dist/commands/release/export/index.d.ts +20 -0
- package/dist/commands/release/export/index.js +142 -0
- package/dist/commands/release/get/index.d.ts +19 -0
- package/dist/commands/release/get/index.js +123 -0
- package/dist/commands/release/import/index.d.ts +15 -0
- package/dist/commands/release/import/index.js +114 -0
- package/dist/commands/release/list/index.d.ts +13 -0
- package/dist/commands/release/list/index.js +120 -0
- package/dist/commands/tenant/backup/create/index.d.ts +20 -0
- package/dist/commands/tenant/backup/create/index.js +113 -0
- package/dist/commands/tenant/backup/delete/index.d.ts +22 -0
- package/dist/commands/tenant/backup/delete/index.js +137 -0
- package/dist/commands/tenant/backup/export/index.d.ts +21 -0
- package/dist/commands/tenant/backup/export/index.js +147 -0
- package/dist/commands/tenant/backup/import/index.d.ts +21 -0
- package/dist/commands/tenant/backup/import/index.js +127 -0
- package/dist/commands/tenant/backup/list/index.d.ts +20 -0
- package/dist/commands/tenant/backup/list/index.js +137 -0
- package/dist/commands/tenant/backup/restore/index.d.ts +22 -0
- package/dist/commands/tenant/backup/restore/index.js +141 -0
- package/dist/commands/tenant/create/index.d.ts +21 -0
- package/dist/commands/tenant/create/index.js +155 -0
- package/dist/commands/tenant/delete/index.d.ts +21 -0
- package/dist/commands/tenant/delete/index.js +134 -0
- package/dist/commands/tenant/deploy-platform/index.d.ts +20 -0
- package/dist/commands/tenant/deploy-platform/index.js +116 -0
- package/dist/commands/tenant/deploy-release/index.d.ts +20 -0
- package/dist/commands/tenant/deploy-release/index.js +116 -0
- package/dist/commands/tenant/edit/index.d.ts +26 -0
- package/dist/commands/tenant/edit/index.js +167 -0
- package/dist/commands/tenant/get/index.d.ts +19 -0
- package/dist/commands/tenant/get/index.js +135 -0
- package/dist/commands/tenant/list/index.d.ts +13 -0
- package/dist/commands/tenant/list/index.js +123 -0
- package/dist/commands/workspace/pull/index.d.ts +1 -0
- package/dist/commands/workspace/pull/index.js +38 -4
- package/dist/commands/workspace/push/index.d.ts +3 -0
- package/dist/commands/workspace/push/index.js +33 -1
- package/oclif.manifest.json +3006 -1049
- package/package.json +10 -1
|
@@ -0,0 +1,135 @@
|
|
|
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 TenantGet extends BaseCommand {
|
|
8
|
+
static args = {
|
|
9
|
+
tenant_id: Args.integer({
|
|
10
|
+
description: 'Tenant ID to retrieve',
|
|
11
|
+
required: true,
|
|
12
|
+
}),
|
|
13
|
+
};
|
|
14
|
+
static description = 'Get details of a specific tenant';
|
|
15
|
+
static examples = [
|
|
16
|
+
`$ xano tenant get 42
|
|
17
|
+
Tenant: My Tenant (my-tenant) - ID: 42
|
|
18
|
+
State: ok
|
|
19
|
+
License: tier1
|
|
20
|
+
Domain: my-tenant.xano.io
|
|
21
|
+
Cluster: default
|
|
22
|
+
Release: v1.0
|
|
23
|
+
`,
|
|
24
|
+
`$ xano tenant get 42 -w 5 -o json`,
|
|
25
|
+
];
|
|
26
|
+
static flags = {
|
|
27
|
+
...BaseCommand.baseFlags,
|
|
28
|
+
output: Flags.string({
|
|
29
|
+
char: 'o',
|
|
30
|
+
default: 'summary',
|
|
31
|
+
description: 'Output format',
|
|
32
|
+
options: ['summary', 'json'],
|
|
33
|
+
required: false,
|
|
34
|
+
}),
|
|
35
|
+
workspace: Flags.string({
|
|
36
|
+
char: 'w',
|
|
37
|
+
description: 'Workspace ID (uses profile workspace if not provided)',
|
|
38
|
+
required: false,
|
|
39
|
+
}),
|
|
40
|
+
};
|
|
41
|
+
async run() {
|
|
42
|
+
const { args, flags } = await this.parse(TenantGet);
|
|
43
|
+
const profileName = flags.profile || this.getDefaultProfile();
|
|
44
|
+
const credentials = this.loadCredentials();
|
|
45
|
+
if (!(profileName in credentials.profiles)) {
|
|
46
|
+
this.error(`Profile '${profileName}' not found. Available profiles: ${Object.keys(credentials.profiles).join(', ')}\n` +
|
|
47
|
+
`Create a profile using 'xano profile create'`);
|
|
48
|
+
}
|
|
49
|
+
const profile = credentials.profiles[profileName];
|
|
50
|
+
if (!profile.instance_origin) {
|
|
51
|
+
this.error(`Profile '${profileName}' is missing instance_origin`);
|
|
52
|
+
}
|
|
53
|
+
if (!profile.access_token) {
|
|
54
|
+
this.error(`Profile '${profileName}' is missing access_token`);
|
|
55
|
+
}
|
|
56
|
+
const workspaceId = flags.workspace || profile.workspace;
|
|
57
|
+
if (!workspaceId) {
|
|
58
|
+
this.error('No workspace ID provided. Use --workspace flag or set one in your profile.');
|
|
59
|
+
}
|
|
60
|
+
const tenantId = args.tenant_id;
|
|
61
|
+
const apiUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}/tenant/${tenantId}`;
|
|
62
|
+
try {
|
|
63
|
+
const response = await this.verboseFetch(apiUrl, {
|
|
64
|
+
headers: {
|
|
65
|
+
'accept': 'application/json',
|
|
66
|
+
'Authorization': `Bearer ${profile.access_token}`,
|
|
67
|
+
},
|
|
68
|
+
method: 'GET',
|
|
69
|
+
}, flags.verbose, profile.access_token);
|
|
70
|
+
if (!response.ok) {
|
|
71
|
+
const errorText = await response.text();
|
|
72
|
+
this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
|
|
73
|
+
}
|
|
74
|
+
const tenant = await response.json();
|
|
75
|
+
if (flags.output === 'json') {
|
|
76
|
+
this.log(JSON.stringify(tenant, null, 2));
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
this.log(`Tenant: ${tenant.display || tenant.name} (${tenant.name}) - ID: ${tenant.id}`);
|
|
80
|
+
if (tenant.state)
|
|
81
|
+
this.log(` State: ${tenant.state}`);
|
|
82
|
+
if (tenant.license)
|
|
83
|
+
this.log(` License: ${tenant.license}`);
|
|
84
|
+
if (tenant.xano_domain)
|
|
85
|
+
this.log(` Domain: ${tenant.xano_domain}`);
|
|
86
|
+
if (tenant.domain)
|
|
87
|
+
this.log(` Custom Domain: ${tenant.domain}`);
|
|
88
|
+
if (tenant.cluster?.name)
|
|
89
|
+
this.log(` Cluster: ${tenant.cluster.name}`);
|
|
90
|
+
if (tenant.release?.name)
|
|
91
|
+
this.log(` Release: ${tenant.release.name}`);
|
|
92
|
+
if (tenant.platform?.name)
|
|
93
|
+
this.log(` Platform: ${tenant.platform.name}`);
|
|
94
|
+
if (tenant.version !== undefined)
|
|
95
|
+
this.log(` Version: ${tenant.version}`);
|
|
96
|
+
if (tenant.tasks !== undefined)
|
|
97
|
+
this.log(` Tasks: ${tenant.tasks}`);
|
|
98
|
+
if (tenant.ingress !== undefined)
|
|
99
|
+
this.log(` Ingress: ${tenant.ingress}`);
|
|
100
|
+
if (tenant.deployed_at) {
|
|
101
|
+
const d = new Date(tenant.deployed_at);
|
|
102
|
+
const deployedDate = Number.isNaN(d.getTime()) ? tenant.deployed_at : d.toISOString().split('T')[0];
|
|
103
|
+
this.log(` Deployed: ${deployedDate}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
if (error instanceof Error) {
|
|
109
|
+
this.error(`Failed to get tenant: ${error.message}`);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
this.error(`Failed to get tenant: ${String(error)}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
loadCredentials() {
|
|
117
|
+
const configDir = path.join(os.homedir(), '.xano');
|
|
118
|
+
const credentialsPath = path.join(configDir, 'credentials.yaml');
|
|
119
|
+
if (!fs.existsSync(credentialsPath)) {
|
|
120
|
+
this.error(`Credentials file not found at ${credentialsPath}\n` +
|
|
121
|
+
`Create a profile using 'xano profile create'`);
|
|
122
|
+
}
|
|
123
|
+
try {
|
|
124
|
+
const fileContent = fs.readFileSync(credentialsPath, 'utf8');
|
|
125
|
+
const parsed = yaml.load(fileContent);
|
|
126
|
+
if (!parsed || typeof parsed !== 'object' || !('profiles' in parsed)) {
|
|
127
|
+
this.error('Credentials file has invalid format.');
|
|
128
|
+
}
|
|
129
|
+
return parsed;
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
this.error(`Failed to parse credentials file: ${error}`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import BaseCommand from '../../../base-command.js';
|
|
2
|
+
export default class TenantList extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
workspace: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
8
|
+
profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
10
|
+
};
|
|
11
|
+
run(): Promise<void>;
|
|
12
|
+
private loadCredentials;
|
|
13
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
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 TenantList extends BaseCommand {
|
|
8
|
+
static description = 'List all tenants in a workspace';
|
|
9
|
+
static examples = [
|
|
10
|
+
`$ xano tenant list
|
|
11
|
+
Tenants in workspace 5:
|
|
12
|
+
- My Tenant (my-tenant) [ok] - tier1
|
|
13
|
+
- Staging (staging) [ok] - tier1
|
|
14
|
+
`,
|
|
15
|
+
`$ xano tenant list -w 5 --output json`,
|
|
16
|
+
];
|
|
17
|
+
static flags = {
|
|
18
|
+
...BaseCommand.baseFlags,
|
|
19
|
+
output: Flags.string({
|
|
20
|
+
char: 'o',
|
|
21
|
+
default: 'summary',
|
|
22
|
+
description: 'Output format',
|
|
23
|
+
options: ['summary', 'json'],
|
|
24
|
+
required: false,
|
|
25
|
+
}),
|
|
26
|
+
workspace: Flags.string({
|
|
27
|
+
char: 'w',
|
|
28
|
+
description: 'Workspace ID (uses profile workspace if not provided)',
|
|
29
|
+
required: false,
|
|
30
|
+
}),
|
|
31
|
+
};
|
|
32
|
+
async run() {
|
|
33
|
+
const { flags } = await this.parse(TenantList);
|
|
34
|
+
const profileName = flags.profile || this.getDefaultProfile();
|
|
35
|
+
const credentials = this.loadCredentials();
|
|
36
|
+
if (!(profileName in credentials.profiles)) {
|
|
37
|
+
this.error(`Profile '${profileName}' not found. Available profiles: ${Object.keys(credentials.profiles).join(', ')}\n` +
|
|
38
|
+
`Create 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 workspaceId = flags.workspace || profile.workspace;
|
|
48
|
+
if (!workspaceId) {
|
|
49
|
+
this.error('No workspace ID provided. Use --workspace flag or set one in your profile.');
|
|
50
|
+
}
|
|
51
|
+
const apiUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}/tenant`;
|
|
52
|
+
try {
|
|
53
|
+
const response = await this.verboseFetch(apiUrl, {
|
|
54
|
+
headers: {
|
|
55
|
+
'accept': 'application/json',
|
|
56
|
+
'Authorization': `Bearer ${profile.access_token}`,
|
|
57
|
+
},
|
|
58
|
+
method: 'GET',
|
|
59
|
+
}, flags.verbose, profile.access_token);
|
|
60
|
+
if (!response.ok) {
|
|
61
|
+
const errorText = await response.text();
|
|
62
|
+
this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
|
|
63
|
+
}
|
|
64
|
+
const data = await response.json();
|
|
65
|
+
let tenants;
|
|
66
|
+
if (Array.isArray(data)) {
|
|
67
|
+
tenants = data;
|
|
68
|
+
}
|
|
69
|
+
else if (data && typeof data === 'object' && 'items' in data && Array.isArray(data.items)) {
|
|
70
|
+
tenants = data.items;
|
|
71
|
+
}
|
|
72
|
+
else if (data && typeof data === 'object' && 'tenants' in data && Array.isArray(data.tenants)) {
|
|
73
|
+
tenants = data.tenants;
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
this.error('Unexpected API response format');
|
|
77
|
+
}
|
|
78
|
+
if (flags.output === 'json') {
|
|
79
|
+
this.log(JSON.stringify(tenants, null, 2));
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
if (tenants.length === 0) {
|
|
83
|
+
this.log('No tenants found');
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
this.log(`Tenants in workspace ${workspaceId}:`);
|
|
87
|
+
for (const tenant of tenants) {
|
|
88
|
+
const state = tenant.state ? ` [${tenant.state}]` : '';
|
|
89
|
+
const license = tenant.license ? ` - ${tenant.license}` : '';
|
|
90
|
+
this.log(` - ${tenant.display || tenant.name} (${tenant.name}) (ID: ${tenant.id})${state}${license}`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
if (error instanceof Error) {
|
|
97
|
+
this.error(`Failed to list tenants: ${error.message}`);
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
this.error(`Failed to list tenants: ${String(error)}`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
loadCredentials() {
|
|
105
|
+
const configDir = path.join(os.homedir(), '.xano');
|
|
106
|
+
const credentialsPath = path.join(configDir, 'credentials.yaml');
|
|
107
|
+
if (!fs.existsSync(credentialsPath)) {
|
|
108
|
+
this.error(`Credentials file not found at ${credentialsPath}\n` +
|
|
109
|
+
`Create a profile using 'xano profile create'`);
|
|
110
|
+
}
|
|
111
|
+
try {
|
|
112
|
+
const fileContent = fs.readFileSync(credentialsPath, 'utf8');
|
|
113
|
+
const parsed = yaml.load(fileContent);
|
|
114
|
+
if (!parsed || typeof parsed !== 'object' || !('profiles' in parsed)) {
|
|
115
|
+
this.error('Credentials file has invalid format.');
|
|
116
|
+
}
|
|
117
|
+
return parsed;
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
this.error(`Failed to parse credentials file: ${error}`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
@@ -8,6 +8,7 @@ export default class Pull extends BaseCommand {
|
|
|
8
8
|
static flags: {
|
|
9
9
|
branch: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
10
|
env: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
11
|
+
draft: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
11
12
|
records: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
12
13
|
workspace: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
14
|
profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
@@ -22,6 +22,9 @@ Pulled 15 documents to ./output
|
|
|
22
22
|
`,
|
|
23
23
|
`$ xano workspace pull ./backup --profile production --env --records
|
|
24
24
|
Pulled 58 documents to ./backup
|
|
25
|
+
`,
|
|
26
|
+
`$ xano workspace pull ./my-workspace --draft
|
|
27
|
+
Pulled 42 documents to ./my-workspace
|
|
25
28
|
`,
|
|
26
29
|
`$ xano workspace pull ./my-workspace -b dev
|
|
27
30
|
Pulled 42 documents to ./my-workspace
|
|
@@ -39,6 +42,11 @@ Pulled 42 documents to ./my-workspace
|
|
|
39
42
|
description: 'Include environment variables',
|
|
40
43
|
required: false,
|
|
41
44
|
}),
|
|
45
|
+
draft: Flags.boolean({
|
|
46
|
+
default: false,
|
|
47
|
+
description: 'Include draft versions',
|
|
48
|
+
required: false,
|
|
49
|
+
}),
|
|
42
50
|
records: Flags.boolean({
|
|
43
51
|
default: false,
|
|
44
52
|
description: 'Include records',
|
|
@@ -88,6 +96,7 @@ Pulled 42 documents to ./my-workspace
|
|
|
88
96
|
const queryParams = new URLSearchParams({
|
|
89
97
|
branch,
|
|
90
98
|
env: flags.env.toString(),
|
|
99
|
+
include_draft: flags.draft.toString(),
|
|
91
100
|
records: flags.records.toString(),
|
|
92
101
|
});
|
|
93
102
|
// Construct the API URL
|
|
@@ -155,14 +164,29 @@ Pulled 42 documents to ./my-workspace
|
|
|
155
164
|
typeDir = path.join(outputDir, 'workspace', 'trigger');
|
|
156
165
|
baseName = this.sanitizeFilename(doc.name);
|
|
157
166
|
}
|
|
167
|
+
else if (doc.type === 'agent') {
|
|
168
|
+
// agent → ai/agent/{name}.xs
|
|
169
|
+
typeDir = path.join(outputDir, 'ai', 'agent');
|
|
170
|
+
baseName = this.sanitizeFilename(doc.name);
|
|
171
|
+
}
|
|
172
|
+
else if (doc.type === 'mcp_server') {
|
|
173
|
+
// mcp_server → ai/mcp_server/{name}.xs
|
|
174
|
+
typeDir = path.join(outputDir, 'ai', 'mcp_server');
|
|
175
|
+
baseName = this.sanitizeFilename(doc.name);
|
|
176
|
+
}
|
|
177
|
+
else if (doc.type === 'tool') {
|
|
178
|
+
// tool → ai/tool/{name}.xs
|
|
179
|
+
typeDir = path.join(outputDir, 'ai', 'tool');
|
|
180
|
+
baseName = this.sanitizeFilename(doc.name);
|
|
181
|
+
}
|
|
158
182
|
else if (doc.type === 'agent_trigger') {
|
|
159
|
-
// agent_trigger → agent/trigger/{name}.xs
|
|
160
|
-
typeDir = path.join(outputDir, 'agent', 'trigger');
|
|
183
|
+
// agent_trigger → ai/agent/trigger/{name}.xs
|
|
184
|
+
typeDir = path.join(outputDir, 'ai', 'agent', 'trigger');
|
|
161
185
|
baseName = this.sanitizeFilename(doc.name);
|
|
162
186
|
}
|
|
163
187
|
else if (doc.type === 'mcp_server_trigger') {
|
|
164
|
-
// mcp_server_trigger → mcp_server/trigger/{name}.xs
|
|
165
|
-
typeDir = path.join(outputDir, 'mcp_server', 'trigger');
|
|
188
|
+
// mcp_server_trigger → ai/mcp_server/trigger/{name}.xs
|
|
189
|
+
typeDir = path.join(outputDir, 'ai', 'mcp_server', 'trigger');
|
|
166
190
|
baseName = this.sanitizeFilename(doc.name);
|
|
167
191
|
}
|
|
168
192
|
else if (doc.type === 'table_trigger') {
|
|
@@ -170,6 +194,16 @@ Pulled 42 documents to ./my-workspace
|
|
|
170
194
|
typeDir = path.join(outputDir, 'table', 'trigger');
|
|
171
195
|
baseName = this.sanitizeFilename(doc.name);
|
|
172
196
|
}
|
|
197
|
+
else if (doc.type === 'realtime_channel') {
|
|
198
|
+
// realtime_channel → realtime/channel/{name}.xs
|
|
199
|
+
typeDir = path.join(outputDir, 'realtime', 'channel');
|
|
200
|
+
baseName = this.sanitizeFilename(doc.name);
|
|
201
|
+
}
|
|
202
|
+
else if (doc.type === 'realtime_trigger') {
|
|
203
|
+
// realtime_trigger → realtime/trigger/{name}.xs
|
|
204
|
+
typeDir = path.join(outputDir, 'realtime', 'trigger');
|
|
205
|
+
baseName = this.sanitizeFilename(doc.name);
|
|
206
|
+
}
|
|
173
207
|
else if (doc.type === 'api_group') {
|
|
174
208
|
// api_group "test" → api/test/api_group.xs
|
|
175
209
|
const groupFolder = snakeCase(doc.name);
|
|
@@ -7,6 +7,9 @@ export default class Push extends BaseCommand {
|
|
|
7
7
|
static examples: string[];
|
|
8
8
|
static flags: {
|
|
9
9
|
branch: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
env: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
11
|
+
records: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
12
|
+
truncate: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
10
13
|
workspace: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
14
|
profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
15
|
verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
@@ -24,6 +24,21 @@ Pushed 58 documents from ./backup
|
|
|
24
24
|
`,
|
|
25
25
|
`$ xano workspace push ./my-workspace -b dev
|
|
26
26
|
Pushed 42 documents from ./my-workspace
|
|
27
|
+
`,
|
|
28
|
+
`$ xano workspace push ./my-workspace --no-records
|
|
29
|
+
Push schema only, skip importing table records
|
|
30
|
+
`,
|
|
31
|
+
`$ xano workspace push ./my-workspace --no-env
|
|
32
|
+
Push without overwriting environment variables
|
|
33
|
+
`,
|
|
34
|
+
`$ xano workspace push ./my-workspace --truncate
|
|
35
|
+
Truncate all table records before importing
|
|
36
|
+
`,
|
|
37
|
+
`$ xano workspace push ./my-workspace --truncate --no-records
|
|
38
|
+
Truncate all table records without importing new ones
|
|
39
|
+
`,
|
|
40
|
+
`$ xano workspace push ./my-workspace --no-records --no-env
|
|
41
|
+
Push schema only, skip records and environment variables
|
|
27
42
|
`,
|
|
28
43
|
];
|
|
29
44
|
static flags = {
|
|
@@ -33,6 +48,23 @@ Pushed 42 documents from ./my-workspace
|
|
|
33
48
|
description: 'Branch name (optional if set in profile, defaults to live)',
|
|
34
49
|
required: false,
|
|
35
50
|
}),
|
|
51
|
+
env: Flags.boolean({
|
|
52
|
+
allowNo: true,
|
|
53
|
+
default: true,
|
|
54
|
+
description: 'Include environment variables in import (default: true, use --no-env to exclude)',
|
|
55
|
+
required: false,
|
|
56
|
+
}),
|
|
57
|
+
records: Flags.boolean({
|
|
58
|
+
allowNo: true,
|
|
59
|
+
default: true,
|
|
60
|
+
description: 'Include records in import (default: true, use --no-records to exclude)',
|
|
61
|
+
required: false,
|
|
62
|
+
}),
|
|
63
|
+
truncate: Flags.boolean({
|
|
64
|
+
default: false,
|
|
65
|
+
description: 'Truncate all table records before importing',
|
|
66
|
+
required: false,
|
|
67
|
+
}),
|
|
36
68
|
workspace: Flags.string({
|
|
37
69
|
char: 'w',
|
|
38
70
|
description: 'Workspace ID (optional if set in profile)',
|
|
@@ -99,7 +131,7 @@ Pushed 42 documents from ./my-workspace
|
|
|
99
131
|
// Determine branch from flag or profile
|
|
100
132
|
const branch = flags.branch || profile.branch || '';
|
|
101
133
|
// Construct the API URL
|
|
102
|
-
const queryParams = new URLSearchParams({ branch });
|
|
134
|
+
const queryParams = new URLSearchParams({ branch, env: flags.env.toString(), records: flags.records.toString(), truncate: flags.truncate.toString() });
|
|
103
135
|
const apiUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}/multidoc?${queryParams.toString()}`;
|
|
104
136
|
// POST the multidoc to the API
|
|
105
137
|
const requestHeaders = {
|