@xano/cli 0.0.37 → 0.0.39
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 +325 -102
- package/dist/commands/auth/index.d.ts +0 -2
- package/dist/commands/auth/index.js +2 -55
- package/dist/commands/profile/create/index.d.ts +0 -2
- package/dist/commands/profile/create/index.js +0 -15
- package/dist/commands/profile/edit/index.d.ts +0 -4
- package/dist/commands/profile/edit/index.js +7 -38
- package/dist/commands/profile/wizard/index.d.ts +0 -2
- package/dist/commands/profile/wizard/index.js +0 -106
- package/dist/commands/profile/{project → workspace}/index.d.ts +1 -1
- package/dist/commands/profile/{project → workspace}/index.js +10 -10
- package/dist/commands/release/delete/index.d.ts +2 -4
- package/dist/commands/release/delete/index.js +39 -12
- package/dist/commands/release/edit/index.d.ts +2 -4
- package/dist/commands/release/edit/index.js +31 -5
- package/dist/commands/release/export/index.d.ts +2 -4
- package/dist/commands/release/export/index.js +39 -11
- package/dist/commands/release/get/index.d.ts +2 -4
- package/dist/commands/release/get/index.js +31 -5
- package/dist/commands/release/pull/index.d.ts +31 -0
- package/dist/commands/release/pull/index.js +345 -0
- package/dist/commands/release/push/index.d.ts +26 -0
- package/dist/commands/release/push/index.js +230 -0
- package/dist/commands/tenant/backup/delete/index.d.ts +1 -1
- package/dist/commands/tenant/backup/delete/index.js +8 -9
- package/dist/commands/tenant/backup/export/index.d.ts +1 -1
- package/dist/commands/tenant/backup/export/index.js +9 -10
- package/dist/commands/tenant/backup/restore/index.d.ts +1 -1
- package/dist/commands/tenant/backup/restore/index.js +8 -9
- package/dist/commands/tenant/cluster/create/index.d.ts +18 -0
- package/dist/commands/tenant/cluster/create/index.js +149 -0
- package/dist/commands/{run/sessions/start → tenant/cluster/delete}/index.d.ts +9 -3
- package/dist/commands/tenant/cluster/delete/index.js +125 -0
- package/dist/commands/tenant/cluster/edit/index.d.ts +22 -0
- package/dist/commands/tenant/cluster/edit/index.js +128 -0
- package/dist/commands/{run/sessions → tenant/cluster}/get/index.d.ts +7 -3
- package/dist/commands/tenant/cluster/get/index.js +114 -0
- package/dist/commands/{run/info → tenant/cluster/license/get}/index.d.ts +10 -7
- package/dist/commands/tenant/cluster/license/get/index.js +118 -0
- package/dist/commands/tenant/cluster/license/set/index.d.ts +21 -0
- package/dist/commands/tenant/cluster/license/set/index.js +132 -0
- package/dist/commands/{run/env → tenant/cluster}/list/index.d.ts +3 -3
- package/dist/commands/tenant/cluster/list/index.js +109 -0
- package/dist/commands/tenant/create/index.d.ts +6 -3
- package/dist/commands/tenant/create/index.js +28 -20
- package/dist/commands/tenant/deploy_platform/index.d.ts +1 -1
- package/dist/commands/tenant/deploy_platform/index.js +8 -9
- package/dist/commands/tenant/deploy_release/index.d.ts +1 -1
- package/dist/commands/tenant/deploy_release/index.js +8 -9
- package/dist/commands/tenant/env/delete/index.d.ts +19 -0
- package/dist/commands/tenant/env/delete/index.js +139 -0
- package/dist/commands/{run/projects/create → tenant/env/get}/index.d.ts +7 -4
- package/dist/commands/tenant/env/get/index.js +113 -0
- package/dist/commands/{run/projects/update → tenant/env/get_all}/index.d.ts +7 -5
- package/dist/commands/tenant/env/get_all/index.js +123 -0
- package/dist/commands/{run/secrets/get → tenant/env/list}/index.d.ts +5 -3
- package/dist/commands/tenant/env/list/index.js +116 -0
- package/dist/commands/tenant/env/set/index.d.ts +18 -0
- package/dist/commands/tenant/env/set/index.js +122 -0
- package/dist/commands/tenant/env/set_all/index.d.ts +18 -0
- package/dist/commands/tenant/env/set_all/index.js +131 -0
- package/dist/commands/tenant/get/index.js +6 -5
- package/dist/commands/tenant/impersonate/index.d.ts +19 -0
- package/dist/commands/tenant/impersonate/index.js +146 -0
- package/dist/commands/tenant/license/get/index.d.ts +18 -0
- package/dist/commands/tenant/license/get/index.js +127 -0
- package/dist/commands/tenant/license/set/index.d.ts +19 -0
- package/dist/commands/tenant/license/set/index.js +141 -0
- package/dist/commands/tenant/list/index.js +6 -6
- package/dist/commands/tenant/pull/index.d.ts +31 -0
- package/dist/commands/tenant/pull/index.js +327 -0
- package/dist/commands/tenant/push/index.d.ts +24 -0
- package/dist/commands/tenant/push/index.js +245 -0
- package/oclif.manifest.json +2218 -1813
- package/package.json +1 -19
- package/dist/commands/run/env/delete/index.d.ts +0 -14
- package/dist/commands/run/env/delete/index.js +0 -65
- package/dist/commands/run/env/get/index.d.ts +0 -14
- package/dist/commands/run/env/get/index.js +0 -52
- package/dist/commands/run/env/list/index.js +0 -56
- package/dist/commands/run/env/set/index.d.ts +0 -14
- package/dist/commands/run/env/set/index.js +0 -51
- package/dist/commands/run/exec/index.d.ts +0 -31
- package/dist/commands/run/exec/index.js +0 -431
- package/dist/commands/run/info/index.js +0 -160
- package/dist/commands/run/projects/create/index.js +0 -75
- package/dist/commands/run/projects/delete/index.d.ts +0 -14
- package/dist/commands/run/projects/delete/index.js +0 -65
- package/dist/commands/run/projects/list/index.d.ts +0 -13
- package/dist/commands/run/projects/list/index.js +0 -66
- package/dist/commands/run/projects/update/index.js +0 -86
- package/dist/commands/run/secrets/delete/index.d.ts +0 -14
- package/dist/commands/run/secrets/delete/index.js +0 -65
- package/dist/commands/run/secrets/get/index.js +0 -52
- package/dist/commands/run/secrets/list/index.d.ts +0 -12
- package/dist/commands/run/secrets/list/index.js +0 -60
- package/dist/commands/run/secrets/set/index.d.ts +0 -16
- package/dist/commands/run/secrets/set/index.js +0 -74
- package/dist/commands/run/sessions/delete/index.d.ts +0 -14
- package/dist/commands/run/sessions/delete/index.js +0 -65
- package/dist/commands/run/sessions/get/index.js +0 -72
- package/dist/commands/run/sessions/list/index.d.ts +0 -13
- package/dist/commands/run/sessions/list/index.js +0 -64
- package/dist/commands/run/sessions/start/index.js +0 -56
- package/dist/commands/run/sessions/stop/index.d.ts +0 -14
- package/dist/commands/run/sessions/stop/index.js +0 -56
- package/dist/commands/run/sink/get/index.d.ts +0 -14
- package/dist/commands/run/sink/get/index.js +0 -63
- package/dist/lib/base-run-command.d.ts +0 -41
- package/dist/lib/base-run-command.js +0 -75
- package/dist/lib/run-http-client.d.ts +0 -64
- package/dist/lib/run-http-client.js +0 -171
- package/dist/lib/run-types.d.ts +0 -226
- package/dist/lib/run-types.js +0 -5
|
@@ -1,431 +0,0 @@
|
|
|
1
|
-
import { Args, Flags } from '@oclif/core';
|
|
2
|
-
import { execSync } from 'node:child_process';
|
|
3
|
-
import * as fs from 'node:fs';
|
|
4
|
-
import * as os from 'node:os';
|
|
5
|
-
import * as path from 'node:path';
|
|
6
|
-
import BaseRunCommand from '../../../lib/base-run-command.js';
|
|
7
|
-
export default class RunExec extends BaseRunCommand {
|
|
8
|
-
static args = {
|
|
9
|
-
path: Args.string({
|
|
10
|
-
description: 'Path to file or directory containing XanoScript code (directory creates multidoc from .xs files)',
|
|
11
|
-
required: false,
|
|
12
|
-
}),
|
|
13
|
-
};
|
|
14
|
-
static description = 'Execute XanoScript code (job or service)';
|
|
15
|
-
static examples = [
|
|
16
|
-
`$ xano run exec script.xs
|
|
17
|
-
Executed successfully!
|
|
18
|
-
...
|
|
19
|
-
`,
|
|
20
|
-
`$ xano run exec ./my-workspace
|
|
21
|
-
# Executes all .xs files in directory as multidoc
|
|
22
|
-
Executed successfully!
|
|
23
|
-
...
|
|
24
|
-
`,
|
|
25
|
-
`$ xano run exec script.xs --edit
|
|
26
|
-
# Opens script.xs in $EDITOR, then executes
|
|
27
|
-
Executed successfully!
|
|
28
|
-
...
|
|
29
|
-
`,
|
|
30
|
-
`$ cat script.xs | xano run exec --stdin
|
|
31
|
-
Executed successfully!
|
|
32
|
-
...
|
|
33
|
-
`,
|
|
34
|
-
`$ xano run exec script.xs -o json
|
|
35
|
-
{
|
|
36
|
-
"run": { ... }
|
|
37
|
-
}
|
|
38
|
-
`,
|
|
39
|
-
`$ xano run exec script.xs -a args.json
|
|
40
|
-
# Executes with input arguments from args.json
|
|
41
|
-
Executed successfully!
|
|
42
|
-
...
|
|
43
|
-
`,
|
|
44
|
-
`$ xano run exec script.xs --env API_KEY=secret --env DEBUG=true
|
|
45
|
-
# Executes with environment variable overrides
|
|
46
|
-
Executed successfully!
|
|
47
|
-
...
|
|
48
|
-
`,
|
|
49
|
-
];
|
|
50
|
-
static flags = {
|
|
51
|
-
...BaseRunCommand.baseFlags,
|
|
52
|
-
args: Flags.string({
|
|
53
|
-
char: 'a',
|
|
54
|
-
description: 'Path or URL to JSON file containing input arguments',
|
|
55
|
-
required: false,
|
|
56
|
-
}),
|
|
57
|
-
edit: Flags.boolean({
|
|
58
|
-
char: 'e',
|
|
59
|
-
default: false,
|
|
60
|
-
description: 'Open file in editor before running (requires path argument or --file)',
|
|
61
|
-
required: false,
|
|
62
|
-
}),
|
|
63
|
-
env: Flags.string({
|
|
64
|
-
description: 'Environment variable override (key=value)',
|
|
65
|
-
multiple: true,
|
|
66
|
-
required: false,
|
|
67
|
-
}),
|
|
68
|
-
file: Flags.string({
|
|
69
|
-
char: 'f',
|
|
70
|
-
description: 'Path or URL to file containing XanoScript code (deprecated: use path argument instead)',
|
|
71
|
-
exclusive: ['stdin'],
|
|
72
|
-
required: false,
|
|
73
|
-
}),
|
|
74
|
-
output: Flags.string({
|
|
75
|
-
char: 'o',
|
|
76
|
-
default: 'summary',
|
|
77
|
-
description: 'Output format',
|
|
78
|
-
options: ['summary', 'json'],
|
|
79
|
-
required: false,
|
|
80
|
-
}),
|
|
81
|
-
stdin: Flags.boolean({
|
|
82
|
-
char: 's',
|
|
83
|
-
default: false,
|
|
84
|
-
description: 'Read XanoScript code from stdin',
|
|
85
|
-
exclusive: ['file'],
|
|
86
|
-
required: false,
|
|
87
|
-
}),
|
|
88
|
-
};
|
|
89
|
-
async run() {
|
|
90
|
-
const { args, flags } = await this.parse(RunExec);
|
|
91
|
-
// Initialize with project required
|
|
92
|
-
await this.initRunCommandWithProject(flags.profile, flags.verbose);
|
|
93
|
-
// Determine input source: path argument, --file flag, or --stdin
|
|
94
|
-
const inputPath = args.path || flags.file;
|
|
95
|
-
// Validate --edit flag requirements
|
|
96
|
-
if (flags.edit) {
|
|
97
|
-
if (!inputPath) {
|
|
98
|
-
this.error('--edit requires a file path (either path argument or --file flag)');
|
|
99
|
-
}
|
|
100
|
-
if (this.isUrl(inputPath)) {
|
|
101
|
-
this.error('--edit cannot be used with URLs');
|
|
102
|
-
}
|
|
103
|
-
if (fs.existsSync(inputPath) && fs.statSync(inputPath).isDirectory()) {
|
|
104
|
-
this.error('--edit cannot be used with directories');
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
// Read XanoScript content
|
|
108
|
-
let xanoscript;
|
|
109
|
-
if (inputPath) {
|
|
110
|
-
if (this.isUrl(inputPath)) {
|
|
111
|
-
// Fetch URL content
|
|
112
|
-
try {
|
|
113
|
-
const response = await fetch(inputPath);
|
|
114
|
-
if (!response.ok) {
|
|
115
|
-
this.error(`Failed to fetch URL: ${response.status} ${response.statusText}`);
|
|
116
|
-
}
|
|
117
|
-
xanoscript = await response.text();
|
|
118
|
-
}
|
|
119
|
-
catch (error) {
|
|
120
|
-
this.error(`Failed to fetch URL '${inputPath}': ${error}`);
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
else if (fs.existsSync(inputPath) && fs.statSync(inputPath).isDirectory()) {
|
|
124
|
-
// Handle directory - collect .xs files and create multidoc
|
|
125
|
-
xanoscript = this.loadMultidocFromDirectory(inputPath);
|
|
126
|
-
}
|
|
127
|
-
else if (flags.edit) {
|
|
128
|
-
// If edit flag is set, copy to temp file and open in editor
|
|
129
|
-
const fileToRead = await this.editFile(inputPath);
|
|
130
|
-
xanoscript = fs.readFileSync(fileToRead, 'utf8');
|
|
131
|
-
// Clean up temp file
|
|
132
|
-
try {
|
|
133
|
-
fs.unlinkSync(fileToRead);
|
|
134
|
-
}
|
|
135
|
-
catch {
|
|
136
|
-
// Ignore cleanup errors
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
else {
|
|
140
|
-
try {
|
|
141
|
-
xanoscript = fs.readFileSync(inputPath, 'utf8');
|
|
142
|
-
}
|
|
143
|
-
catch (error) {
|
|
144
|
-
this.error(`Failed to read file '${inputPath}': ${error}`);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
else if (flags.stdin) {
|
|
149
|
-
try {
|
|
150
|
-
xanoscript = await this.readStdin();
|
|
151
|
-
}
|
|
152
|
-
catch (error) {
|
|
153
|
-
this.error(`Failed to read from stdin: ${error}`);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
else {
|
|
157
|
-
this.error('Either a path argument, --file, or --stdin must be specified to provide XanoScript code');
|
|
158
|
-
}
|
|
159
|
-
// Validate xanoscript is not empty
|
|
160
|
-
if (!xanoscript || xanoscript.trim().length === 0) {
|
|
161
|
-
this.error('XanoScript content is empty');
|
|
162
|
-
}
|
|
163
|
-
// Load args from JSON file or URL if provided
|
|
164
|
-
let inputArgs;
|
|
165
|
-
if (flags.args) {
|
|
166
|
-
if (this.isUrl(flags.args)) {
|
|
167
|
-
try {
|
|
168
|
-
const response = await fetch(flags.args);
|
|
169
|
-
if (!response.ok) {
|
|
170
|
-
this.error(`Failed to fetch args URL: ${response.status} ${response.statusText}`);
|
|
171
|
-
}
|
|
172
|
-
const argsContent = await response.text();
|
|
173
|
-
inputArgs = JSON.parse(argsContent);
|
|
174
|
-
}
|
|
175
|
-
catch (error) {
|
|
176
|
-
this.error(`Failed to fetch or parse args '${flags.args}': ${error}`);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
else {
|
|
180
|
-
try {
|
|
181
|
-
const argsContent = fs.readFileSync(flags.args, 'utf8');
|
|
182
|
-
inputArgs = JSON.parse(argsContent);
|
|
183
|
-
}
|
|
184
|
-
catch (error) {
|
|
185
|
-
this.error(`Failed to read or parse args '${flags.args}': ${error}`);
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
// Parse env overrides
|
|
190
|
-
let envOverrides;
|
|
191
|
-
if (flags.env && flags.env.length > 0) {
|
|
192
|
-
envOverrides = {};
|
|
193
|
-
for (const envStr of flags.env) {
|
|
194
|
-
const eqIndex = envStr.indexOf('=');
|
|
195
|
-
if (eqIndex === -1) {
|
|
196
|
-
this.error(`Invalid env format '${envStr}'. Expected format: key=value`);
|
|
197
|
-
}
|
|
198
|
-
const key = envStr.slice(0, eqIndex);
|
|
199
|
-
const value = envStr.slice(eqIndex + 1);
|
|
200
|
-
envOverrides[key] = value;
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
// Build query params
|
|
204
|
-
const queryParams = {};
|
|
205
|
-
if (inputArgs) {
|
|
206
|
-
queryParams.args = inputArgs;
|
|
207
|
-
}
|
|
208
|
-
if (envOverrides) {
|
|
209
|
-
queryParams.env = envOverrides;
|
|
210
|
-
}
|
|
211
|
-
// Execute via API
|
|
212
|
-
try {
|
|
213
|
-
const url = this.httpClient.buildProjectUrl('/run/exec', queryParams);
|
|
214
|
-
const result = await this.httpClient.postXanoScript(url, xanoscript);
|
|
215
|
-
// Output results
|
|
216
|
-
if (flags.output === 'json') {
|
|
217
|
-
this.outputJson(result);
|
|
218
|
-
}
|
|
219
|
-
else {
|
|
220
|
-
this.outputSummary(result);
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
catch (error) {
|
|
224
|
-
if (error instanceof Error) {
|
|
225
|
-
const xanoError = error;
|
|
226
|
-
if (xanoError.response) {
|
|
227
|
-
const responseStr = typeof xanoError.response === 'string'
|
|
228
|
-
? xanoError.response
|
|
229
|
-
: JSON.stringify(xanoError.response, null, 2);
|
|
230
|
-
this.error(`Failed to execute: ${error.message}\n\n${responseStr}`);
|
|
231
|
-
}
|
|
232
|
-
else {
|
|
233
|
-
this.error(`Failed to execute: ${error.message}`);
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
else {
|
|
237
|
-
this.error(`Failed to execute: ${String(error)}`);
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
/**
|
|
242
|
-
* Recursively collect all .xs files from a directory, sorted for deterministic ordering.
|
|
243
|
-
*/
|
|
244
|
-
collectFiles(dir) {
|
|
245
|
-
const files = [];
|
|
246
|
-
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
247
|
-
for (const entry of entries) {
|
|
248
|
-
const fullPath = path.join(dir, entry.name);
|
|
249
|
-
if (entry.isDirectory()) {
|
|
250
|
-
files.push(...this.collectFiles(fullPath));
|
|
251
|
-
}
|
|
252
|
-
else if (entry.isFile() && entry.name.endsWith('.xs')) {
|
|
253
|
-
files.push(fullPath);
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
return files.sort();
|
|
257
|
-
}
|
|
258
|
-
// Editor value comes from EDITOR/VISUAL environment variables, not user input
|
|
259
|
-
async editFile(filePath) {
|
|
260
|
-
const editor = process.env.EDITOR || process.env.VISUAL;
|
|
261
|
-
if (!editor) {
|
|
262
|
-
this.error('No editor configured. Please set the EDITOR or VISUAL environment variable.\n' +
|
|
263
|
-
'Example: export EDITOR=vim');
|
|
264
|
-
}
|
|
265
|
-
// Validate editor executable exists
|
|
266
|
-
try {
|
|
267
|
-
execSync(`which ${editor.split(' ')[0]}`, { stdio: 'ignore' });
|
|
268
|
-
}
|
|
269
|
-
catch {
|
|
270
|
-
this.error(`Editor '${editor}' not found. Please set EDITOR to a valid editor.\n` +
|
|
271
|
-
'Example: export EDITOR=vim');
|
|
272
|
-
}
|
|
273
|
-
// Read the original file
|
|
274
|
-
let originalContent;
|
|
275
|
-
try {
|
|
276
|
-
originalContent = fs.readFileSync(filePath, 'utf8');
|
|
277
|
-
}
|
|
278
|
-
catch (error) {
|
|
279
|
-
this.error(`Failed to read file '${filePath}': ${error}`);
|
|
280
|
-
}
|
|
281
|
-
// Create a temporary file with the same extension
|
|
282
|
-
const ext = path.extname(filePath);
|
|
283
|
-
const tmpFile = path.join(os.tmpdir(), `xano-edit-${Date.now()}${ext}`);
|
|
284
|
-
// Copy content to temp file
|
|
285
|
-
try {
|
|
286
|
-
fs.writeFileSync(tmpFile, originalContent, 'utf8');
|
|
287
|
-
}
|
|
288
|
-
catch (error) {
|
|
289
|
-
this.error(`Failed to create temporary file: ${error}`);
|
|
290
|
-
}
|
|
291
|
-
// Open the editor
|
|
292
|
-
try {
|
|
293
|
-
execSync(`${editor} ${tmpFile}`, { stdio: 'inherit' });
|
|
294
|
-
}
|
|
295
|
-
catch (error) {
|
|
296
|
-
try {
|
|
297
|
-
fs.unlinkSync(tmpFile);
|
|
298
|
-
}
|
|
299
|
-
catch {
|
|
300
|
-
// Ignore cleanup errors
|
|
301
|
-
}
|
|
302
|
-
this.error(`Editor exited with an error: ${error}`);
|
|
303
|
-
}
|
|
304
|
-
return tmpFile;
|
|
305
|
-
}
|
|
306
|
-
isUrl(str) {
|
|
307
|
-
return str.startsWith('http://') || str.startsWith('https://');
|
|
308
|
-
}
|
|
309
|
-
/**
|
|
310
|
-
* Load all .xs files from a directory and combine them into a multidoc.
|
|
311
|
-
*/
|
|
312
|
-
loadMultidocFromDirectory(dir) {
|
|
313
|
-
const resolvedDir = path.resolve(dir);
|
|
314
|
-
if (!fs.existsSync(resolvedDir)) {
|
|
315
|
-
this.error(`Directory not found: ${resolvedDir}`);
|
|
316
|
-
}
|
|
317
|
-
const files = this.collectFiles(resolvedDir);
|
|
318
|
-
if (files.length === 0) {
|
|
319
|
-
this.error(`No .xs files found in ${dir}`);
|
|
320
|
-
}
|
|
321
|
-
// Read each file and join with --- separator
|
|
322
|
-
const documents = [];
|
|
323
|
-
for (const filePath of files) {
|
|
324
|
-
const content = fs.readFileSync(filePath, 'utf8').trim();
|
|
325
|
-
if (content) {
|
|
326
|
-
documents.push(content);
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
if (documents.length === 0) {
|
|
330
|
-
this.error(`All .xs files in ${dir} are empty`);
|
|
331
|
-
}
|
|
332
|
-
return documents.join('\n---\n');
|
|
333
|
-
}
|
|
334
|
-
outputSummary(result) {
|
|
335
|
-
this.log('Executed successfully!');
|
|
336
|
-
this.log('');
|
|
337
|
-
// Handle service-specific output
|
|
338
|
-
if (result.service) {
|
|
339
|
-
this.log(` Service ID: ${result.service.id}`);
|
|
340
|
-
this.log(` Run ID: ${result.service.run.id}`);
|
|
341
|
-
this.log('');
|
|
342
|
-
}
|
|
343
|
-
// Handle run/session info
|
|
344
|
-
if (result.run?.id) {
|
|
345
|
-
this.log(` Run ID: ${result.run.id}`);
|
|
346
|
-
}
|
|
347
|
-
if (result.run?.session) {
|
|
348
|
-
const { session } = result.run;
|
|
349
|
-
this.log(` Session ID: ${session.id}`);
|
|
350
|
-
this.log(` State: ${session.state}`);
|
|
351
|
-
this.log('');
|
|
352
|
-
}
|
|
353
|
-
// Handle timing info
|
|
354
|
-
const timing = result.run?.result || result.run?.session || result.result;
|
|
355
|
-
if (timing) {
|
|
356
|
-
const formatTime = (time) => time === undefined ? undefined : `${(time * 1000).toFixed(2)}ms`;
|
|
357
|
-
const times = [
|
|
358
|
-
{ label: 'Total', value: formatTime(timing.total_time) },
|
|
359
|
-
{ label: 'Boot', value: formatTime(timing.boot_time) },
|
|
360
|
-
{ label: 'Main', value: formatTime(timing.main_time) },
|
|
361
|
-
{ label: 'Pre', value: formatTime(timing.pre_time) },
|
|
362
|
-
{ label: 'Post', value: formatTime(timing.post_time) },
|
|
363
|
-
].filter(t => t.value !== undefined);
|
|
364
|
-
if (times.length > 0) {
|
|
365
|
-
this.log(' Timing:');
|
|
366
|
-
for (const t of times) {
|
|
367
|
-
this.log(` ${t.label.padEnd(6)} ${t.value}`);
|
|
368
|
-
}
|
|
369
|
-
this.log('');
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
// Handle service endpoints
|
|
373
|
-
if (result.result?.endpoints && result.result.endpoints.length > 0) {
|
|
374
|
-
this.log(' Endpoints:');
|
|
375
|
-
for (const endpoint of result.result.endpoints) {
|
|
376
|
-
this.log(` ${endpoint.verb.padEnd(6)} ${endpoint.url}`);
|
|
377
|
-
if (endpoint.input.length > 0) {
|
|
378
|
-
for (const input of endpoint.input) {
|
|
379
|
-
const required = input.required ? '*' : '';
|
|
380
|
-
const nullable = input.nullable ? '?' : '';
|
|
381
|
-
this.log(` └─ ${input.name}${required}: ${input.type}${nullable} (${input.source})`);
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
this.log('');
|
|
386
|
-
}
|
|
387
|
-
// Handle metadata API
|
|
388
|
-
if (result.result?.metadata_api) {
|
|
389
|
-
this.log(' Metadata API:');
|
|
390
|
-
this.log(` ${result.result.metadata_api.url}`);
|
|
391
|
-
this.log('');
|
|
392
|
-
}
|
|
393
|
-
// Handle response
|
|
394
|
-
const response = result.run?.result?.response ?? result.run?.session?.response ?? result.result?.response;
|
|
395
|
-
if (response !== undefined) {
|
|
396
|
-
this.log(' Response:');
|
|
397
|
-
const responseStr = typeof response === 'string'
|
|
398
|
-
? response
|
|
399
|
-
: JSON.stringify(response, null, 2);
|
|
400
|
-
const indentedResponse = responseStr.split('\n').map((line) => ` ${line}`).join('\n');
|
|
401
|
-
this.log(indentedResponse);
|
|
402
|
-
}
|
|
403
|
-
// Handle problems/errors
|
|
404
|
-
if (result.run?.problems && result.run.problems.length > 0) {
|
|
405
|
-
this.log('');
|
|
406
|
-
this.log(' Problems:');
|
|
407
|
-
for (const problem of result.run.problems) {
|
|
408
|
-
this.log(` - [${problem.severity}] ${problem.message}`);
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
if (result.run?.session?.error_msg) {
|
|
412
|
-
this.log('');
|
|
413
|
-
this.log(` Error: ${result.run.session.error_msg}`);
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
async readStdin() {
|
|
417
|
-
return new Promise((resolve, reject) => {
|
|
418
|
-
const chunks = [];
|
|
419
|
-
process.stdin.on('data', (chunk) => {
|
|
420
|
-
chunks.push(chunk);
|
|
421
|
-
});
|
|
422
|
-
process.stdin.on('end', () => {
|
|
423
|
-
resolve(Buffer.concat(chunks).toString('utf8'));
|
|
424
|
-
});
|
|
425
|
-
process.stdin.on('error', (error) => {
|
|
426
|
-
reject(error);
|
|
427
|
-
});
|
|
428
|
-
process.stdin.resume();
|
|
429
|
-
});
|
|
430
|
-
}
|
|
431
|
-
}
|
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
import { Flags } from '@oclif/core';
|
|
2
|
-
import * as fs from 'node:fs';
|
|
3
|
-
import BaseRunCommand from '../../../lib/base-run-command.js';
|
|
4
|
-
export default class RunInfo extends BaseRunCommand {
|
|
5
|
-
static args = {};
|
|
6
|
-
static description = 'Get information about a XanoScript document (type, inputs, env vars)';
|
|
7
|
-
static examples = [
|
|
8
|
-
`$ xano run info -f script.xs
|
|
9
|
-
Document Info:
|
|
10
|
-
Type: job
|
|
11
|
-
Inputs:
|
|
12
|
-
- name (string, required)
|
|
13
|
-
- count (number, optional)
|
|
14
|
-
Environment Variables:
|
|
15
|
-
- API_KEY
|
|
16
|
-
- DEBUG
|
|
17
|
-
`,
|
|
18
|
-
`$ cat script.xs | xano run info --stdin
|
|
19
|
-
Document Info:
|
|
20
|
-
Type: service
|
|
21
|
-
Inputs: none
|
|
22
|
-
Environment Variables: none
|
|
23
|
-
`,
|
|
24
|
-
`$ xano run info -f script.xs -o json
|
|
25
|
-
{ "type": "job", "input": { "name": {...} }, "env": ["API_KEY"] }
|
|
26
|
-
`,
|
|
27
|
-
];
|
|
28
|
-
static flags = {
|
|
29
|
-
...BaseRunCommand.baseFlags,
|
|
30
|
-
file: Flags.string({
|
|
31
|
-
char: 'f',
|
|
32
|
-
description: 'Path or URL to file containing XanoScript code',
|
|
33
|
-
exclusive: ['stdin'],
|
|
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
|
-
stdin: Flags.boolean({
|
|
44
|
-
char: 's',
|
|
45
|
-
default: false,
|
|
46
|
-
description: 'Read XanoScript code from stdin',
|
|
47
|
-
exclusive: ['file'],
|
|
48
|
-
required: false,
|
|
49
|
-
}),
|
|
50
|
-
};
|
|
51
|
-
async run() {
|
|
52
|
-
const { flags } = await this.parse(RunInfo);
|
|
53
|
-
// Initialize with project required
|
|
54
|
-
await this.initRunCommandWithProject(flags.profile, flags.verbose);
|
|
55
|
-
// Read XanoScript content
|
|
56
|
-
let xanoscript;
|
|
57
|
-
if (flags.file) {
|
|
58
|
-
if (this.isUrl(flags.file)) {
|
|
59
|
-
// Fetch URL content
|
|
60
|
-
try {
|
|
61
|
-
const response = await fetch(flags.file);
|
|
62
|
-
if (!response.ok) {
|
|
63
|
-
this.error(`Failed to fetch URL: ${response.status} ${response.statusText}`);
|
|
64
|
-
}
|
|
65
|
-
xanoscript = await response.text();
|
|
66
|
-
}
|
|
67
|
-
catch (error) {
|
|
68
|
-
this.error(`Failed to fetch URL '${flags.file}': ${error}`);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
else {
|
|
72
|
-
try {
|
|
73
|
-
xanoscript = fs.readFileSync(flags.file, 'utf8');
|
|
74
|
-
}
|
|
75
|
-
catch (error) {
|
|
76
|
-
this.error(`Failed to read file '${flags.file}': ${error}`);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
else if (flags.stdin) {
|
|
81
|
-
try {
|
|
82
|
-
xanoscript = await this.readStdin();
|
|
83
|
-
}
|
|
84
|
-
catch (error) {
|
|
85
|
-
this.error(`Failed to read from stdin: ${error}`);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
else {
|
|
89
|
-
this.error('Either --file or --stdin must be specified to provide XanoScript code');
|
|
90
|
-
}
|
|
91
|
-
// Validate xanoscript is not empty
|
|
92
|
-
if (!xanoscript || xanoscript.trim().length === 0) {
|
|
93
|
-
this.error('XanoScript content is empty');
|
|
94
|
-
}
|
|
95
|
-
// Get document info via API
|
|
96
|
-
try {
|
|
97
|
-
const url = this.httpClient.buildProjectUrl('/doc/info');
|
|
98
|
-
const result = await this.httpClient.post(url, { doc: xanoscript });
|
|
99
|
-
if (flags.output === 'json') {
|
|
100
|
-
this.outputJson(result);
|
|
101
|
-
}
|
|
102
|
-
else {
|
|
103
|
-
this.outputSummary(result);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
catch (error) {
|
|
107
|
-
if (error instanceof Error) {
|
|
108
|
-
this.error(`Failed to get document info: ${error.message}`);
|
|
109
|
-
}
|
|
110
|
-
else {
|
|
111
|
-
this.error(`Failed to get document info: ${String(error)}`);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
isUrl(str) {
|
|
116
|
-
return str.startsWith('http://') || str.startsWith('https://');
|
|
117
|
-
}
|
|
118
|
-
outputSummary(result) {
|
|
119
|
-
this.log('Document Info:');
|
|
120
|
-
this.log(` Type: ${result.type}`);
|
|
121
|
-
this.log('');
|
|
122
|
-
// Display inputs
|
|
123
|
-
this.log(' Inputs:');
|
|
124
|
-
if (result.input && Object.keys(result.input).length > 0) {
|
|
125
|
-
for (const [name, config] of Object.entries(result.input)) {
|
|
126
|
-
const configStr = typeof config === 'object' ? JSON.stringify(config) : String(config);
|
|
127
|
-
this.log(` - ${name}: ${configStr}`);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
else {
|
|
131
|
-
this.log(' (none)');
|
|
132
|
-
}
|
|
133
|
-
this.log('');
|
|
134
|
-
// Display environment variables
|
|
135
|
-
this.log(' Environment Variables:');
|
|
136
|
-
if (result.env && result.env.length > 0) {
|
|
137
|
-
for (const envVar of result.env) {
|
|
138
|
-
this.log(` - ${envVar}`);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
else {
|
|
142
|
-
this.log(' (none)');
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
async readStdin() {
|
|
146
|
-
return new Promise((resolve, reject) => {
|
|
147
|
-
const chunks = [];
|
|
148
|
-
process.stdin.on('data', (chunk) => {
|
|
149
|
-
chunks.push(chunk);
|
|
150
|
-
});
|
|
151
|
-
process.stdin.on('end', () => {
|
|
152
|
-
resolve(Buffer.concat(chunks).toString('utf8'));
|
|
153
|
-
});
|
|
154
|
-
process.stdin.on('error', (error) => {
|
|
155
|
-
reject(error);
|
|
156
|
-
});
|
|
157
|
-
process.stdin.resume();
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
}
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import { Flags } from '@oclif/core';
|
|
2
|
-
import BaseRunCommand from '../../../../lib/base-run-command.js';
|
|
3
|
-
export default class RunProjectsCreate extends BaseRunCommand {
|
|
4
|
-
static args = {};
|
|
5
|
-
static description = 'Create a new project';
|
|
6
|
-
static examples = [
|
|
7
|
-
`$ xano run projects create -n "My Project"
|
|
8
|
-
Project created successfully!
|
|
9
|
-
ID: abc123-def456-ghi789
|
|
10
|
-
Name: My Project
|
|
11
|
-
`,
|
|
12
|
-
`$ xano run projects create -n "My Project" -d "Description here"
|
|
13
|
-
Project created successfully!
|
|
14
|
-
ID: abc123-def456-ghi789
|
|
15
|
-
Name: My Project
|
|
16
|
-
`,
|
|
17
|
-
`$ xano run projects create -n "My Project" -o json
|
|
18
|
-
{ "id": "abc123-def456-ghi789", "name": "My Project", ... }
|
|
19
|
-
`,
|
|
20
|
-
];
|
|
21
|
-
static flags = {
|
|
22
|
-
...BaseRunCommand.baseFlags,
|
|
23
|
-
description: Flags.string({
|
|
24
|
-
char: 'd',
|
|
25
|
-
default: '',
|
|
26
|
-
description: 'Project description',
|
|
27
|
-
required: false,
|
|
28
|
-
}),
|
|
29
|
-
name: Flags.string({
|
|
30
|
-
char: 'n',
|
|
31
|
-
description: 'Project name',
|
|
32
|
-
required: true,
|
|
33
|
-
}),
|
|
34
|
-
output: Flags.string({
|
|
35
|
-
char: 'o',
|
|
36
|
-
default: 'summary',
|
|
37
|
-
description: 'Output format',
|
|
38
|
-
options: ['summary', 'json'],
|
|
39
|
-
required: false,
|
|
40
|
-
}),
|
|
41
|
-
};
|
|
42
|
-
async run() {
|
|
43
|
-
const { flags } = await this.parse(RunProjectsCreate);
|
|
44
|
-
// Initialize (no project required for creating projects)
|
|
45
|
-
await this.initRunCommand(flags.profile, flags.verbose);
|
|
46
|
-
const input = {
|
|
47
|
-
description: flags.description || '',
|
|
48
|
-
name: flags.name,
|
|
49
|
-
};
|
|
50
|
-
try {
|
|
51
|
-
const url = this.httpClient.buildUrl('/project');
|
|
52
|
-
const project = await this.httpClient.post(url, input);
|
|
53
|
-
if (flags.output === 'json') {
|
|
54
|
-
this.outputJson(project);
|
|
55
|
-
}
|
|
56
|
-
else {
|
|
57
|
-
this.log('Project created successfully!');
|
|
58
|
-
this.log(` ID: ${project.id}`);
|
|
59
|
-
this.log(` Name: ${project.name}`);
|
|
60
|
-
if (project.description) {
|
|
61
|
-
this.log(` Description: ${project.description}`);
|
|
62
|
-
}
|
|
63
|
-
this.log(` Access: ${project.access}`);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
catch (error) {
|
|
67
|
-
if (error instanceof Error) {
|
|
68
|
-
this.error(`Failed to create project: ${error.message}`);
|
|
69
|
-
}
|
|
70
|
-
else {
|
|
71
|
-
this.error(`Failed to create project: ${String(error)}`);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import BaseRunCommand from '../../../../lib/base-run-command.js';
|
|
2
|
-
export default class RunProjectsDelete extends BaseRunCommand {
|
|
3
|
-
static args: {
|
|
4
|
-
projectId: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
5
|
-
};
|
|
6
|
-
static description: string;
|
|
7
|
-
static examples: string[];
|
|
8
|
-
static flags: {
|
|
9
|
-
force: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
10
|
-
profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
-
verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
12
|
-
};
|
|
13
|
-
run(): Promise<void>;
|
|
14
|
-
}
|