@xano/cli 1.0.3 → 1.0.4-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.
- package/README.md +100 -3
- package/dist/base-command.d.ts +27 -0
- package/dist/base-command.js +124 -1
- package/dist/commands/auth/index.d.ts +48 -1
- package/dist/commands/auth/index.js +259 -27
- package/dist/commands/function/run/index.d.ts +40 -0
- package/dist/commands/function/run/index.js +244 -0
- package/dist/commands/sandbox/pull/index.js +12 -2
- package/dist/commands/sandbox/push/index.d.ts +1 -1
- package/dist/commands/sandbox/push/index.js +17 -13
- package/dist/commands/static_host/build/create/index.d.ts +9 -1
- package/dist/commands/static_host/build/create/index.js +54 -4
- package/dist/commands/static_host/build/delete/index.d.ts +19 -0
- package/dist/commands/static_host/build/delete/index.js +114 -0
- package/dist/commands/static_host/build/get/index.d.ts +1 -1
- package/dist/commands/static_host/build/get/index.js +16 -10
- package/dist/commands/static_host/build/pull/index.d.ts +52 -0
- package/dist/commands/static_host/build/pull/index.js +300 -0
- package/dist/commands/static_host/build/push/index.d.ts +23 -0
- package/dist/commands/static_host/build/push/index.js +228 -0
- package/dist/commands/static_host/create/index.d.ts +17 -0
- package/dist/commands/static_host/create/index.js +86 -0
- package/dist/commands/static_host/deploy/index.d.ts +18 -0
- package/dist/commands/static_host/deploy/index.js +105 -0
- package/dist/commands/static_host/edit/index.d.ts +23 -0
- package/dist/commands/static_host/edit/index.js +151 -0
- package/dist/commands/static_host/get/index.d.ts +18 -0
- package/dist/commands/static_host/get/index.js +94 -0
- package/dist/commands/static_host/migrate/index.d.ts +44 -0
- package/dist/commands/static_host/migrate/index.js +205 -0
- package/dist/commands/tenant/snapshot/create/index.d.ts +17 -0
- package/dist/commands/tenant/snapshot/create/index.js +78 -0
- package/dist/commands/tenant/snapshot/delete/index.d.ts +19 -0
- package/dist/commands/tenant/snapshot/delete/index.js +102 -0
- package/dist/commands/tenant/snapshot/list/index.d.ts +16 -0
- package/dist/commands/tenant/snapshot/list/index.js +96 -0
- package/dist/commands/tenant/snapshot/swap/index.d.ts +19 -0
- package/dist/commands/tenant/snapshot/swap/index.js +103 -0
- package/dist/commands/tenant/unit_test/run/index.d.ts +1 -0
- package/dist/commands/tenant/unit_test/run/index.js +7 -0
- package/dist/commands/tenant/unit_test/run_all/index.js +7 -3
- package/dist/commands/unit_test/run/index.d.ts +1 -0
- package/dist/commands/unit_test/run/index.js +8 -0
- package/dist/commands/unit_test/run_all/index.js +7 -3
- package/dist/commands/workspace/pull/index.js +13 -2
- package/dist/commands/workspace/push/index.d.ts +1 -1
- package/dist/commands/workspace/push/index.js +15 -5
- package/dist/utils/function-input.d.ts +77 -0
- package/dist/utils/function-input.js +148 -0
- package/dist/utils/knowledge-sync.d.ts +113 -0
- package/dist/utils/knowledge-sync.js +404 -0
- package/dist/utils/multidoc-push.d.ts +22 -0
- package/dist/utils/multidoc-push.js +262 -107
- package/dist/utils/reference-checker.js +2 -2
- package/dist/utils/static-host-files.d.ts +21 -0
- package/dist/utils/static-host-files.js +41 -0
- package/oclif.manifest.json +4179 -2636
- package/package.json +4 -1
|
@@ -2,6 +2,7 @@ import { Flags } from '@oclif/core';
|
|
|
2
2
|
import snakeCase from 'lodash.snakecase';
|
|
3
3
|
import BaseCommand from '../../../base-command.js';
|
|
4
4
|
import { buildApiGroupFolderResolver, parseDocument } from '../../../utils/document-parser.js';
|
|
5
|
+
import { fetchKnowledge, writeKnowledge } from '../../../utils/knowledge-sync.js';
|
|
5
6
|
import * as fs from 'node:fs';
|
|
6
7
|
import * as path from 'node:path';
|
|
7
8
|
export default class SandboxPull extends BaseCommand {
|
|
@@ -87,7 +88,6 @@ Pulled 42 documents from sandbox environment to ./my-sandbox
|
|
|
87
88
|
}
|
|
88
89
|
if (documents.length === 0) {
|
|
89
90
|
this.log('No documents found in response');
|
|
90
|
-
return;
|
|
91
91
|
}
|
|
92
92
|
const outputDir = path.resolve(flags.directory);
|
|
93
93
|
fs.mkdirSync(outputDir, { recursive: true });
|
|
@@ -182,7 +182,17 @@ Pulled 42 documents from sandbox environment to ./my-sandbox
|
|
|
182
182
|
fs.writeFileSync(filePath, doc.content, 'utf8');
|
|
183
183
|
writtenCount++;
|
|
184
184
|
}
|
|
185
|
-
|
|
185
|
+
// ── Pull knowledge ────────────────────────────────────────────────────
|
|
186
|
+
const knowledgeUrl = `${profile.instance_origin}/api:meta/sandbox/knowledge/sync`;
|
|
187
|
+
const knowledgeObjects = await fetchKnowledge(knowledgeUrl, '', profile.access_token, this.verboseFetch.bind(this), flags.verbose);
|
|
188
|
+
let knowledgeCount = 0;
|
|
189
|
+
if (knowledgeObjects.length > 0) {
|
|
190
|
+
knowledgeCount = writeKnowledge(knowledgeObjects, outputDir);
|
|
191
|
+
}
|
|
192
|
+
const parts = [`${writtenCount} documents`];
|
|
193
|
+
if (knowledgeCount > 0)
|
|
194
|
+
parts.push(`${knowledgeCount} knowledge file${knowledgeCount === 1 ? '' : 's'}`);
|
|
195
|
+
this.log(`Pulled ${parts.join(' + ')} from sandbox environment to ${flags.directory}`);
|
|
186
196
|
}
|
|
187
197
|
sanitizeFilename(name) {
|
|
188
198
|
return snakeCase(name.replaceAll('"', ''));
|
|
@@ -130,12 +130,29 @@ Push and open sandbox review in the browser
|
|
|
130
130
|
branch: '',
|
|
131
131
|
command: this,
|
|
132
132
|
inputDir,
|
|
133
|
+
knowledge: {
|
|
134
|
+
listUrl: () => `${baseUrl}/knowledge/sync`,
|
|
135
|
+
rootDir: inputDir,
|
|
136
|
+
},
|
|
133
137
|
verboseFetch: this.verboseFetch.bind(this),
|
|
134
138
|
}, target, pushFlags);
|
|
135
139
|
if (flags.review) {
|
|
136
140
|
await this.openReview(profile.instance_origin, profile.access_token, flags.verbose);
|
|
137
141
|
}
|
|
138
142
|
}
|
|
143
|
+
getFrontendUrl(instanceOrigin) {
|
|
144
|
+
try {
|
|
145
|
+
const url = new URL(instanceOrigin);
|
|
146
|
+
if (url.hostname === 'localhost' || url.hostname === '127.0.0.1') {
|
|
147
|
+
url.port = '4200';
|
|
148
|
+
return url.origin;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
// fall through
|
|
153
|
+
}
|
|
154
|
+
return instanceOrigin;
|
|
155
|
+
}
|
|
139
156
|
async openReview(instanceOrigin, accessToken, verbose) {
|
|
140
157
|
const response = await this.verboseFetch(`${instanceOrigin}/api:meta/sandbox/impersonate`, {
|
|
141
158
|
headers: {
|
|
@@ -158,17 +175,4 @@ Push and open sandbox review in the browser
|
|
|
158
175
|
this.log('Opening sandbox review...');
|
|
159
176
|
await open(reviewUrl);
|
|
160
177
|
}
|
|
161
|
-
getFrontendUrl(instanceOrigin) {
|
|
162
|
-
try {
|
|
163
|
-
const url = new URL(instanceOrigin);
|
|
164
|
-
if (url.hostname === 'localhost' || url.hostname === '127.0.0.1') {
|
|
165
|
-
url.port = '4200';
|
|
166
|
-
return url.origin;
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
catch {
|
|
170
|
-
// fall through
|
|
171
|
-
}
|
|
172
|
-
return instanceOrigin;
|
|
173
|
-
}
|
|
174
178
|
}
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import BaseCommand from '../../../../base-command.js';
|
|
2
|
+
/**
|
|
3
|
+
* Generate a default build name from a compact timestamp: `YYYYMMDD-HHmmss`
|
|
4
|
+
* (e.g. `20260531-143022`). Sortable, distinct down to the second, and uses
|
|
5
|
+
* local time so it lines up with when the user ran the command.
|
|
6
|
+
*/
|
|
7
|
+
export declare function generateBuildName(date?: Date): string;
|
|
2
8
|
export default class StaticHostBuildCreate extends BaseCommand {
|
|
9
|
+
static hidden: boolean;
|
|
3
10
|
static args: {
|
|
4
11
|
static_host: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
5
12
|
};
|
|
@@ -8,7 +15,8 @@ export default class StaticHostBuildCreate extends BaseCommand {
|
|
|
8
15
|
static flags: {
|
|
9
16
|
description: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
17
|
file: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
-
name: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
18
|
+
name: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
19
|
+
'no-wait': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
12
20
|
output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
21
|
workspace: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
14
22
|
config: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
@@ -2,20 +2,42 @@ import { Args, Flags } from '@oclif/core';
|
|
|
2
2
|
import * as fs from 'node:fs';
|
|
3
3
|
import * as path from 'node:path';
|
|
4
4
|
import BaseCommand from '../../../../base-command.js';
|
|
5
|
+
const pad2 = (n) => String(n).padStart(2, '0');
|
|
6
|
+
/**
|
|
7
|
+
* Generate a default build name from a compact timestamp: `YYYYMMDD-HHmmss`
|
|
8
|
+
* (e.g. `20260531-143022`). Sortable, distinct down to the second, and uses
|
|
9
|
+
* local time so it lines up with when the user ran the command.
|
|
10
|
+
*/
|
|
11
|
+
export function generateBuildName(date = new Date()) {
|
|
12
|
+
const y = date.getFullYear();
|
|
13
|
+
const mo = pad2(date.getMonth() + 1);
|
|
14
|
+
const d = pad2(date.getDate());
|
|
15
|
+
const h = pad2(date.getHours());
|
|
16
|
+
const mi = pad2(date.getMinutes());
|
|
17
|
+
const s = pad2(date.getSeconds());
|
|
18
|
+
return `${y}${mo}${d}-${h}${mi}${s}`;
|
|
19
|
+
}
|
|
5
20
|
export default class StaticHostBuildCreate extends BaseCommand {
|
|
21
|
+
static hidden = true;
|
|
6
22
|
static args = {
|
|
7
23
|
static_host: Args.string({
|
|
8
24
|
description: 'Static Host name',
|
|
9
25
|
required: true,
|
|
10
26
|
}),
|
|
11
27
|
};
|
|
12
|
-
static description = 'Create a new build
|
|
28
|
+
static description = '[Deprecated: use "static_host build push -f <file>" instead] Create a new build from a zip file';
|
|
13
29
|
static examples = [
|
|
14
30
|
`$ xano static_host:build:create default -f ./build.zip -n "v1.0.0"
|
|
15
31
|
Build created successfully!
|
|
16
32
|
ID: 123
|
|
17
33
|
Name: v1.0.0
|
|
18
34
|
Status: pending
|
|
35
|
+
`,
|
|
36
|
+
`$ xano static_host:build:create default -f ./build.zip
|
|
37
|
+
Build created successfully!
|
|
38
|
+
ID: 123
|
|
39
|
+
Name: 20260531-143022
|
|
40
|
+
Status: pending
|
|
19
41
|
`,
|
|
20
42
|
`$ xano static_host:build:create default -w 40 -f ./dist.zip -n "production" -d "Production build"
|
|
21
43
|
Build created successfully!
|
|
@@ -45,8 +67,13 @@ Description: Production build
|
|
|
45
67
|
}),
|
|
46
68
|
name: Flags.string({
|
|
47
69
|
char: 'n',
|
|
48
|
-
description: 'Build name',
|
|
49
|
-
required:
|
|
70
|
+
description: 'Build name (auto-generated from the current timestamp if omitted)',
|
|
71
|
+
required: false,
|
|
72
|
+
}),
|
|
73
|
+
'no-wait': Flags.boolean({
|
|
74
|
+
default: false,
|
|
75
|
+
description: 'Return immediately after upload instead of waiting for the build to finish',
|
|
76
|
+
required: false,
|
|
50
77
|
}),
|
|
51
78
|
output: Flags.string({
|
|
52
79
|
char: 'o',
|
|
@@ -62,6 +89,7 @@ Description: Production build
|
|
|
62
89
|
}),
|
|
63
90
|
};
|
|
64
91
|
async run() {
|
|
92
|
+
this.warn('`static_host build create` is deprecated. Use `static_host build push -f <file>` instead.');
|
|
65
93
|
const { args, flags } = await this.parse(StaticHostBuildCreate);
|
|
66
94
|
const { profile, profileName } = this.resolveProfile(flags);
|
|
67
95
|
// Determine workspace_id from flag or profile
|
|
@@ -102,7 +130,10 @@ Description: Production build
|
|
|
102
130
|
const fileBuffer = fs.readFileSync(filePath);
|
|
103
131
|
const blob = new Blob([fileBuffer], { type: 'application/zip' });
|
|
104
132
|
formData.append('file', blob, path.basename(filePath));
|
|
105
|
-
|
|
133
|
+
// Name is optional — fall back to a timestamped name so builds can be
|
|
134
|
+
// created without thinking up a label each time.
|
|
135
|
+
const buildName = flags.name ?? generateBuildName();
|
|
136
|
+
formData.append('name', buildName);
|
|
106
137
|
if (flags.description) {
|
|
107
138
|
formData.append('description', flags.description);
|
|
108
139
|
}
|
|
@@ -141,6 +172,25 @@ Description: Production build
|
|
|
141
172
|
this.log(`Description: ${flags.description}`);
|
|
142
173
|
}
|
|
143
174
|
}
|
|
175
|
+
// Async (package.json) builds keep running after upload. Unless --no-wait,
|
|
176
|
+
// poll until the build finishes so the CLI mirrors the UI's progress.
|
|
177
|
+
const inProgress = result.status !== undefined && !['error', 'ok'].includes(result.status);
|
|
178
|
+
if (inProgress && !flags['no-wait']) {
|
|
179
|
+
const finalStatus = await this.waitForBuild({
|
|
180
|
+
buildId: result.id,
|
|
181
|
+
profile,
|
|
182
|
+
quiet: flags.output === 'json',
|
|
183
|
+
staticHost: args.static_host,
|
|
184
|
+
verbose: flags.verbose,
|
|
185
|
+
workspaceId,
|
|
186
|
+
});
|
|
187
|
+
if (finalStatus === 'error') {
|
|
188
|
+
this.error(`Build ${result.id} failed (status: error). Check the build log with: xano static_host build get ${args.static_host} --build_id ${result.id}`);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
if (flags.output !== 'json') {
|
|
192
|
+
await this.logStaticHostUrls({ profile, staticHost: args.static_host, verbose: flags.verbose, workspaceId });
|
|
193
|
+
}
|
|
144
194
|
}
|
|
145
195
|
catch (error) {
|
|
146
196
|
if (error instanceof Error) {
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import BaseCommand from '../../../../base-command.js';
|
|
2
|
+
export default class StaticHostBuildDelete extends BaseCommand {
|
|
3
|
+
static args: {
|
|
4
|
+
static_host: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
5
|
+
};
|
|
6
|
+
static description: string;
|
|
7
|
+
static examples: string[];
|
|
8
|
+
static flags: {
|
|
9
|
+
build_id: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
force: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
11
|
+
output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
workspace: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
|
+
config: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
14
|
+
profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
15
|
+
verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
16
|
+
};
|
|
17
|
+
run(): Promise<void>;
|
|
18
|
+
private confirm;
|
|
19
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { Args, Flags } from '@oclif/core';
|
|
2
|
+
import BaseCommand from '../../../../base-command.js';
|
|
3
|
+
export default class StaticHostBuildDelete extends BaseCommand {
|
|
4
|
+
static args = {
|
|
5
|
+
static_host: Args.string({
|
|
6
|
+
description: 'Static Host name',
|
|
7
|
+
required: true,
|
|
8
|
+
}),
|
|
9
|
+
};
|
|
10
|
+
static description = 'Delete a static host build permanently. This action cannot be undone.';
|
|
11
|
+
static examples = [
|
|
12
|
+
`$ xano static_host build delete default --build_id 52
|
|
13
|
+
Are you sure you want to delete build 52 from static host 'default'? This action cannot be undone. (y/N) y
|
|
14
|
+
Deleted build 52 from static host 'default'
|
|
15
|
+
`,
|
|
16
|
+
`$ xano static_host build delete default --build_id 52 --force
|
|
17
|
+
Deleted build 52 from static host 'default'
|
|
18
|
+
`,
|
|
19
|
+
`$ xano static_host build delete myhost --build_id 123 -w 40 -f
|
|
20
|
+
Deleted build 123 from static host 'myhost'
|
|
21
|
+
`,
|
|
22
|
+
`$ xano static_host build delete default --build_id 52 -f -o json`,
|
|
23
|
+
];
|
|
24
|
+
static flags = {
|
|
25
|
+
...BaseCommand.baseFlags,
|
|
26
|
+
build_id: Flags.string({
|
|
27
|
+
description: 'Build ID to delete',
|
|
28
|
+
required: true,
|
|
29
|
+
}),
|
|
30
|
+
force: Flags.boolean({
|
|
31
|
+
char: 'f',
|
|
32
|
+
default: false,
|
|
33
|
+
description: '[CRITICAL] NEVER run without explicit user confirmation. Skips the confirmation prompt.',
|
|
34
|
+
required: false,
|
|
35
|
+
}),
|
|
36
|
+
output: Flags.string({
|
|
37
|
+
char: 'o',
|
|
38
|
+
default: 'summary',
|
|
39
|
+
description: 'Output format',
|
|
40
|
+
options: ['summary', 'json'],
|
|
41
|
+
required: false,
|
|
42
|
+
}),
|
|
43
|
+
workspace: Flags.string({
|
|
44
|
+
char: 'w',
|
|
45
|
+
description: 'Workspace ID (optional if set in profile)',
|
|
46
|
+
required: false,
|
|
47
|
+
}),
|
|
48
|
+
};
|
|
49
|
+
async run() {
|
|
50
|
+
const { args, flags } = await this.parse(StaticHostBuildDelete);
|
|
51
|
+
const { profile, profileName } = this.resolveProfile(flags);
|
|
52
|
+
// Determine workspace_id from flag or profile
|
|
53
|
+
let workspaceId;
|
|
54
|
+
if (flags.workspace) {
|
|
55
|
+
workspaceId = flags.workspace;
|
|
56
|
+
}
|
|
57
|
+
else if (profile.workspace) {
|
|
58
|
+
workspaceId = profile.workspace;
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
this.error(`Workspace ID is required. Either:\n` +
|
|
62
|
+
` 1. Provide it as a flag: xano static_host build delete <static_host> --build_id <id> -w <workspace_id>\n` +
|
|
63
|
+
` 2. Set it in your profile using: xano profile edit ${profileName} -w <workspace_id>`);
|
|
64
|
+
}
|
|
65
|
+
if (!flags.force) {
|
|
66
|
+
const confirmed = await this.confirm(`Are you sure you want to delete build ${flags.build_id} from static host '${args.static_host}'? This action cannot be undone.`);
|
|
67
|
+
if (!confirmed) {
|
|
68
|
+
this.log('Deletion cancelled.');
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
const apiUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}/static_host/${args.static_host}/build/${flags.build_id}`;
|
|
73
|
+
try {
|
|
74
|
+
const response = await this.verboseFetch(apiUrl, {
|
|
75
|
+
headers: {
|
|
76
|
+
'accept': 'application/json',
|
|
77
|
+
'Authorization': `Bearer ${profile.access_token}`,
|
|
78
|
+
},
|
|
79
|
+
method: 'DELETE',
|
|
80
|
+
}, flags.verbose, profile.access_token);
|
|
81
|
+
if (!response.ok) {
|
|
82
|
+
const errorText = await response.text();
|
|
83
|
+
this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
|
|
84
|
+
}
|
|
85
|
+
if (flags.output === 'json') {
|
|
86
|
+
this.log(JSON.stringify({ build_id: flags.build_id, deleted: true, static_host: args.static_host }, null, 2));
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
this.log(`Deleted build ${flags.build_id} from static host '${args.static_host}'`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
if (error instanceof Error) {
|
|
94
|
+
this.error(`Failed to delete build: ${error.message}`);
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
this.error(`Failed to delete build: ${String(error)}`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
async confirm(message) {
|
|
102
|
+
const readline = await import('node:readline');
|
|
103
|
+
const rl = readline.createInterface({
|
|
104
|
+
input: process.stdin,
|
|
105
|
+
output: process.stdout,
|
|
106
|
+
});
|
|
107
|
+
return new Promise((resolve) => {
|
|
108
|
+
rl.question(`${message} (y/N) `, (answer) => {
|
|
109
|
+
rl.close();
|
|
110
|
+
resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import BaseCommand from '../../../../base-command.js';
|
|
2
2
|
export default class StaticHostBuildGet extends BaseCommand {
|
|
3
3
|
static args: {
|
|
4
|
-
build_id: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
5
4
|
static_host: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
6
5
|
};
|
|
7
6
|
static description: string;
|
|
8
7
|
static examples: string[];
|
|
9
8
|
static flags: {
|
|
9
|
+
build_id: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
10
|
output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
11
|
workspace: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
12
|
config: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
@@ -2,10 +2,6 @@ import { Args, Flags } from '@oclif/core';
|
|
|
2
2
|
import BaseCommand from '../../../../base-command.js';
|
|
3
3
|
export default class StaticHostBuildGet extends BaseCommand {
|
|
4
4
|
static args = {
|
|
5
|
-
build_id: Args.string({
|
|
6
|
-
description: 'Build ID',
|
|
7
|
-
required: true,
|
|
8
|
-
}),
|
|
9
5
|
static_host: Args.string({
|
|
10
6
|
description: 'Static Host name',
|
|
11
7
|
required: true,
|
|
@@ -13,24 +9,24 @@ export default class StaticHostBuildGet extends BaseCommand {
|
|
|
13
9
|
};
|
|
14
10
|
static description = 'Get details of a specific build for a static host';
|
|
15
11
|
static examples = [
|
|
16
|
-
`$ xano static_host:build:get default 52
|
|
12
|
+
`$ xano static_host:build:get default --build_id 52
|
|
17
13
|
Build Details:
|
|
18
14
|
ID: 52
|
|
19
15
|
Name: v1.0.0
|
|
20
16
|
Status: completed
|
|
21
17
|
`,
|
|
22
|
-
`$ xano static_host:build:get default 52 -w 40
|
|
18
|
+
`$ xano static_host:build:get default --build_id 52 -w 40
|
|
23
19
|
Build Details:
|
|
24
20
|
ID: 52
|
|
25
21
|
Name: v1.0.0
|
|
26
22
|
Status: completed
|
|
27
23
|
`,
|
|
28
|
-
`$ xano static_host:build:get myhost 123 --profile production
|
|
24
|
+
`$ xano static_host:build:get myhost --build_id 123 --profile production
|
|
29
25
|
Build Details:
|
|
30
26
|
ID: 123
|
|
31
27
|
Name: production-build
|
|
32
28
|
`,
|
|
33
|
-
`$ xano static_host:build:get default 52 -o json
|
|
29
|
+
`$ xano static_host:build:get default --build_id 52 -o json
|
|
34
30
|
{
|
|
35
31
|
"id": 52,
|
|
36
32
|
"name": "v1.0.0",
|
|
@@ -40,6 +36,10 @@ Name: production-build
|
|
|
40
36
|
];
|
|
41
37
|
static flags = {
|
|
42
38
|
...BaseCommand.baseFlags,
|
|
39
|
+
build_id: Flags.string({
|
|
40
|
+
description: 'Build ID',
|
|
41
|
+
required: true,
|
|
42
|
+
}),
|
|
43
43
|
output: Flags.string({
|
|
44
44
|
char: 'o',
|
|
45
45
|
default: 'summary',
|
|
@@ -66,11 +66,11 @@ Name: production-build
|
|
|
66
66
|
}
|
|
67
67
|
else {
|
|
68
68
|
this.error(`Workspace ID is required. Either:\n` +
|
|
69
|
-
` 1. Provide it as a flag: xano static_host:build:get <static_host> <
|
|
69
|
+
` 1. Provide it as a flag: xano static_host:build:get <static_host> --build_id <id> -w <workspace_id>\n` +
|
|
70
70
|
` 2. Set it in your profile using: xano profile:edit ${profileName} -w <workspace_id>`);
|
|
71
71
|
}
|
|
72
72
|
// Construct the API URL
|
|
73
|
-
const apiUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}/static_host/${args.static_host}/build/${
|
|
73
|
+
const apiUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}/static_host/${args.static_host}/build/${flags.build_id}`;
|
|
74
74
|
// Fetch build from the API
|
|
75
75
|
try {
|
|
76
76
|
const response = await this.verboseFetch(apiUrl, {
|
|
@@ -104,6 +104,12 @@ Name: production-build
|
|
|
104
104
|
if (build.status) {
|
|
105
105
|
this.log(`Status: ${build.status}`);
|
|
106
106
|
}
|
|
107
|
+
if (typeof build.file_count === 'number') {
|
|
108
|
+
this.log(`Files: ${build.file_count}`);
|
|
109
|
+
}
|
|
110
|
+
if (typeof build.file_bytes === 'number') {
|
|
111
|
+
this.log(`Size: ${build.file_bytes} bytes`);
|
|
112
|
+
}
|
|
107
113
|
if (build.created_at) {
|
|
108
114
|
this.log(`Created: ${build.created_at}`);
|
|
109
115
|
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import BaseCommand from '../../../../base-command.js';
|
|
2
|
+
export interface StaticHostEnv {
|
|
3
|
+
canonical?: null | string;
|
|
4
|
+
}
|
|
5
|
+
export interface StaticHostSummary {
|
|
6
|
+
[k: string]: unknown;
|
|
7
|
+
dev?: StaticHostEnv;
|
|
8
|
+
name: string;
|
|
9
|
+
prod?: StaticHostEnv;
|
|
10
|
+
}
|
|
11
|
+
export interface BuildSummary {
|
|
12
|
+
canonical?: string;
|
|
13
|
+
id: number;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Find the deployed `canonical` for a static host's env from a list of hosts.
|
|
17
|
+
* Returns null when the host isn't present or nothing is deployed to that env.
|
|
18
|
+
*/
|
|
19
|
+
export declare function extractEnvCanonical(hosts: StaticHostSummary[], staticHost: string, env: string): null | string;
|
|
20
|
+
/** Find the build whose unique `canonical` matches, or null if none do. */
|
|
21
|
+
export declare function findBuildByCanonical(builds: BuildSummary[], canonical: string): BuildSummary | null;
|
|
22
|
+
export default class StaticHostBuildPull extends BaseCommand {
|
|
23
|
+
static args: {
|
|
24
|
+
static_host: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
25
|
+
};
|
|
26
|
+
static description: string;
|
|
27
|
+
static examples: string[];
|
|
28
|
+
static flags: {
|
|
29
|
+
build_id: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
30
|
+
directory: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
31
|
+
env: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
32
|
+
latest: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
33
|
+
source: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
34
|
+
workspace: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
35
|
+
config: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
36
|
+
profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
37
|
+
verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
38
|
+
};
|
|
39
|
+
run(): Promise<void>;
|
|
40
|
+
private parseFileDocument;
|
|
41
|
+
/**
|
|
42
|
+
* Resolve the build ID currently deployed to a static host's dev/prod env.
|
|
43
|
+
*
|
|
44
|
+
* The deployed env stores the `canonical` of the build it was created from
|
|
45
|
+
* (static_host.{env}.canonical). Each build carries that same unique
|
|
46
|
+
* `canonical`, so we match the env's canonical against the build list to
|
|
47
|
+
* recover the build ID — a shortcut for "list builds, find the deployed one,
|
|
48
|
+
* then pull it".
|
|
49
|
+
*/
|
|
50
|
+
private resolveEnvBuild;
|
|
51
|
+
private resolveLatestBuild;
|
|
52
|
+
}
|