@xano/cli 0.0.10 → 0.0.11
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/commands/ephemeral/run/job/index.d.ts +1 -2
- package/dist/commands/ephemeral/run/job/index.js +48 -52
- package/dist/commands/ephemeral/run/service/index.d.ts +1 -2
- package/dist/commands/ephemeral/run/service/index.js +33 -33
- package/oclif.manifest.json +510 -510
- package/package.json +1 -1
|
@@ -110,11 +110,16 @@ Job executed successfully!
|
|
|
110
110
|
` 1. Provide it as a flag: xano ephemeral:run:job -w <workspace_id>\n` +
|
|
111
111
|
` 2. Set it in your profile using: xano profile:edit ${profileName} -w <workspace_id>`);
|
|
112
112
|
}
|
|
113
|
-
// Read XanoScript content
|
|
113
|
+
// Read XanoScript content or use URL
|
|
114
114
|
let xanoscript;
|
|
115
|
+
let xanoscriptUrl;
|
|
115
116
|
if (flags.file) {
|
|
116
|
-
|
|
117
|
-
|
|
117
|
+
if (this.isUrl(flags.file)) {
|
|
118
|
+
// Pass URL directly to API
|
|
119
|
+
xanoscriptUrl = flags.file;
|
|
120
|
+
}
|
|
121
|
+
else if (flags.edit) {
|
|
122
|
+
// If edit flag is set, copy to temp file and open in editor
|
|
118
123
|
const fileToRead = await this.editFile(flags.file);
|
|
119
124
|
xanoscript = fs.readFileSync(fileToRead, 'utf8');
|
|
120
125
|
// Clean up temp file
|
|
@@ -126,7 +131,12 @@ Job executed successfully!
|
|
|
126
131
|
}
|
|
127
132
|
}
|
|
128
133
|
else {
|
|
129
|
-
|
|
134
|
+
try {
|
|
135
|
+
xanoscript = fs.readFileSync(flags.file, 'utf8');
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
this.error(`Failed to read file '${flags.file}': ${error}`);
|
|
139
|
+
}
|
|
130
140
|
}
|
|
131
141
|
}
|
|
132
142
|
else if (flags.stdin) {
|
|
@@ -141,45 +151,53 @@ Job executed successfully!
|
|
|
141
151
|
else {
|
|
142
152
|
this.error('Either --file or --stdin must be specified to provide XanoScript code');
|
|
143
153
|
}
|
|
144
|
-
// Validate xanoscript is not empty
|
|
145
|
-
if (!xanoscript || xanoscript.trim().length === 0) {
|
|
154
|
+
// Validate xanoscript is not empty (only if not using URL)
|
|
155
|
+
if (!xanoscriptUrl && (!xanoscript || xanoscript.trim().length === 0)) {
|
|
146
156
|
this.error('XanoScript content is empty');
|
|
147
157
|
}
|
|
148
|
-
// Load args from JSON file
|
|
158
|
+
// Load args from JSON file/URL if provided
|
|
149
159
|
let inputArgs;
|
|
160
|
+
let inputArgsUrl;
|
|
150
161
|
if (flags.args) {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
162
|
+
if (this.isUrl(flags.args)) {
|
|
163
|
+
// Pass URL directly to API
|
|
164
|
+
inputArgsUrl = flags.args;
|
|
154
165
|
}
|
|
155
|
-
|
|
156
|
-
|
|
166
|
+
else {
|
|
167
|
+
try {
|
|
168
|
+
const argsContent = fs.readFileSync(flags.args, 'utf8');
|
|
169
|
+
inputArgs = JSON.parse(argsContent);
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
this.error(`Failed to read or parse args '${flags.args}': ${error}`);
|
|
173
|
+
}
|
|
157
174
|
}
|
|
158
175
|
}
|
|
159
176
|
// Construct the API URL
|
|
160
177
|
const apiUrl = `${profile.instance_origin}/api:meta/beta/workspace/${workspaceId}/ephemeral/job`;
|
|
161
|
-
// Build request body
|
|
162
|
-
let requestBody;
|
|
163
|
-
let contentType;
|
|
178
|
+
// Build request body
|
|
164
179
|
const formData = new FormData();
|
|
165
|
-
|
|
166
|
-
|
|
180
|
+
if (xanoscriptUrl) {
|
|
181
|
+
formData.append('doc', xanoscriptUrl);
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
formData.append('doc', xanoscript);
|
|
185
|
+
}
|
|
186
|
+
if (inputArgsUrl) {
|
|
187
|
+
formData.append('args', inputArgsUrl);
|
|
188
|
+
}
|
|
189
|
+
else if (inputArgs) {
|
|
167
190
|
formData.append('args', JSON.stringify(inputArgs));
|
|
168
191
|
}
|
|
169
|
-
requestBody = formData;
|
|
170
|
-
contentType = ''; // Let fetch set the boundary
|
|
192
|
+
const requestBody = formData;
|
|
171
193
|
// Run ephemeral job via API
|
|
172
194
|
try {
|
|
173
|
-
const headers = {
|
|
174
|
-
'accept': 'application/json',
|
|
175
|
-
'Authorization': `Bearer ${profile.access_token}`,
|
|
176
|
-
};
|
|
177
|
-
if (contentType) {
|
|
178
|
-
headers['Content-Type'] = contentType;
|
|
179
|
-
}
|
|
180
195
|
const response = await fetch(apiUrl, {
|
|
181
196
|
method: 'POST',
|
|
182
|
-
headers
|
|
197
|
+
headers: {
|
|
198
|
+
'accept': 'application/json',
|
|
199
|
+
'Authorization': `Bearer ${profile.access_token}`,
|
|
200
|
+
},
|
|
183
201
|
body: requestBody,
|
|
184
202
|
});
|
|
185
203
|
if (!response.ok) {
|
|
@@ -272,6 +290,9 @@ Job executed successfully!
|
|
|
272
290
|
}
|
|
273
291
|
return tmpFile;
|
|
274
292
|
}
|
|
293
|
+
isUrl(str) {
|
|
294
|
+
return str.startsWith('http://') || str.startsWith('https://');
|
|
295
|
+
}
|
|
275
296
|
async readStdin() {
|
|
276
297
|
return new Promise((resolve, reject) => {
|
|
277
298
|
const chunks = [];
|
|
@@ -288,31 +309,6 @@ Job executed successfully!
|
|
|
288
309
|
process.stdin.resume();
|
|
289
310
|
});
|
|
290
311
|
}
|
|
291
|
-
isUrl(str) {
|
|
292
|
-
return str.startsWith('http://') || str.startsWith('https://');
|
|
293
|
-
}
|
|
294
|
-
async fetchContent(source) {
|
|
295
|
-
if (this.isUrl(source)) {
|
|
296
|
-
try {
|
|
297
|
-
const response = await fetch(source);
|
|
298
|
-
if (!response.ok) {
|
|
299
|
-
this.error(`Failed to fetch '${source}': ${response.status} ${response.statusText}`);
|
|
300
|
-
}
|
|
301
|
-
return await response.text();
|
|
302
|
-
}
|
|
303
|
-
catch (error) {
|
|
304
|
-
this.error(`Failed to fetch '${source}': ${error}`);
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
else {
|
|
308
|
-
try {
|
|
309
|
-
return fs.readFileSync(source, 'utf8');
|
|
310
|
-
}
|
|
311
|
-
catch (error) {
|
|
312
|
-
this.error(`Failed to read file '${source}': ${error}`);
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
312
|
loadCredentials() {
|
|
317
313
|
const configDir = path.join(os.homedir(), '.xano');
|
|
318
314
|
const credentialsPath = path.join(configDir, 'credentials.yaml');
|
|
@@ -13,8 +13,7 @@ export default class EphemeralRunService extends BaseCommand {
|
|
|
13
13
|
static examples: string[];
|
|
14
14
|
run(): Promise<void>;
|
|
15
15
|
private editFile;
|
|
16
|
-
private readStdin;
|
|
17
16
|
private isUrl;
|
|
18
|
-
private
|
|
17
|
+
private readStdin;
|
|
19
18
|
private loadCredentials;
|
|
20
19
|
}
|
|
@@ -100,11 +100,16 @@ Service created successfully!
|
|
|
100
100
|
` 1. Provide it as a flag: xano ephemeral:run:service -w <workspace_id>\n` +
|
|
101
101
|
` 2. Set it in your profile using: xano profile:edit ${profileName} -w <workspace_id>`);
|
|
102
102
|
}
|
|
103
|
-
// Read XanoScript content
|
|
103
|
+
// Read XanoScript content or use URL
|
|
104
104
|
let xanoscript;
|
|
105
|
+
let xanoscriptUrl;
|
|
105
106
|
if (flags.file) {
|
|
106
|
-
|
|
107
|
-
|
|
107
|
+
if (this.isUrl(flags.file)) {
|
|
108
|
+
// Pass URL directly to API
|
|
109
|
+
xanoscriptUrl = flags.file;
|
|
110
|
+
}
|
|
111
|
+
else if (flags.edit) {
|
|
112
|
+
// If edit flag is set, copy to temp file and open in editor
|
|
108
113
|
const fileToRead = await this.editFile(flags.file);
|
|
109
114
|
xanoscript = fs.readFileSync(fileToRead, 'utf8');
|
|
110
115
|
// Clean up temp file
|
|
@@ -116,7 +121,12 @@ Service created successfully!
|
|
|
116
121
|
}
|
|
117
122
|
}
|
|
118
123
|
else {
|
|
119
|
-
|
|
124
|
+
try {
|
|
125
|
+
xanoscript = fs.readFileSync(flags.file, 'utf8');
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
this.error(`Failed to read file '${flags.file}': ${error}`);
|
|
129
|
+
}
|
|
120
130
|
}
|
|
121
131
|
}
|
|
122
132
|
else if (flags.stdin) {
|
|
@@ -131,22 +141,29 @@ Service created successfully!
|
|
|
131
141
|
else {
|
|
132
142
|
this.error('Either --file or --stdin must be specified to provide XanoScript code');
|
|
133
143
|
}
|
|
134
|
-
// Validate xanoscript is not empty
|
|
135
|
-
if (!xanoscript || xanoscript.trim().length === 0) {
|
|
144
|
+
// Validate xanoscript is not empty (only if not using URL)
|
|
145
|
+
if (!xanoscriptUrl && (!xanoscript || xanoscript.trim().length === 0)) {
|
|
136
146
|
this.error('XanoScript content is empty');
|
|
137
147
|
}
|
|
138
148
|
// Construct the API URL
|
|
139
149
|
const apiUrl = `${profile.instance_origin}/api:meta/beta/workspace/${workspaceId}/ephemeral/service`;
|
|
150
|
+
// Build request body
|
|
151
|
+
const formData = new FormData();
|
|
152
|
+
if (xanoscriptUrl) {
|
|
153
|
+
formData.append('doc', xanoscriptUrl);
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
formData.append('doc', xanoscript);
|
|
157
|
+
}
|
|
140
158
|
// Run ephemeral service via API
|
|
141
159
|
try {
|
|
142
160
|
const response = await fetch(apiUrl, {
|
|
143
161
|
method: 'POST',
|
|
144
162
|
headers: {
|
|
145
163
|
'accept': 'application/json',
|
|
146
|
-
'Content-Type': 'text/x-xanoscript',
|
|
147
164
|
'Authorization': `Bearer ${profile.access_token}`,
|
|
148
165
|
},
|
|
149
|
-
body:
|
|
166
|
+
body: formData,
|
|
150
167
|
});
|
|
151
168
|
if (!response.ok) {
|
|
152
169
|
const errorText = await response.text();
|
|
@@ -182,6 +199,11 @@ Service created successfully!
|
|
|
182
199
|
}
|
|
183
200
|
}
|
|
184
201
|
}
|
|
202
|
+
this.log('');
|
|
203
|
+
}
|
|
204
|
+
if (result.result.metadata_api) {
|
|
205
|
+
this.log(' Metadata API:');
|
|
206
|
+
this.log(` ${result.result.metadata_api.url}`);
|
|
185
207
|
}
|
|
186
208
|
}
|
|
187
209
|
}
|
|
@@ -244,6 +266,9 @@ Service created successfully!
|
|
|
244
266
|
}
|
|
245
267
|
return tmpFile;
|
|
246
268
|
}
|
|
269
|
+
isUrl(str) {
|
|
270
|
+
return str.startsWith('http://') || str.startsWith('https://');
|
|
271
|
+
}
|
|
247
272
|
async readStdin() {
|
|
248
273
|
return new Promise((resolve, reject) => {
|
|
249
274
|
const chunks = [];
|
|
@@ -260,31 +285,6 @@ Service created successfully!
|
|
|
260
285
|
process.stdin.resume();
|
|
261
286
|
});
|
|
262
287
|
}
|
|
263
|
-
isUrl(str) {
|
|
264
|
-
return str.startsWith('http://') || str.startsWith('https://');
|
|
265
|
-
}
|
|
266
|
-
async fetchContent(source) {
|
|
267
|
-
if (this.isUrl(source)) {
|
|
268
|
-
try {
|
|
269
|
-
const response = await fetch(source);
|
|
270
|
-
if (!response.ok) {
|
|
271
|
-
this.error(`Failed to fetch '${source}': ${response.status} ${response.statusText}`);
|
|
272
|
-
}
|
|
273
|
-
return await response.text();
|
|
274
|
-
}
|
|
275
|
-
catch (error) {
|
|
276
|
-
this.error(`Failed to fetch '${source}': ${error}`);
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
else {
|
|
280
|
-
try {
|
|
281
|
-
return fs.readFileSync(source, 'utf8');
|
|
282
|
-
}
|
|
283
|
-
catch (error) {
|
|
284
|
-
this.error(`Failed to read file '${source}': ${error}`);
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
288
|
loadCredentials() {
|
|
289
289
|
const configDir = path.join(os.homedir(), '.xano');
|
|
290
290
|
const credentialsPath = path.join(configDir, 'credentials.yaml');
|