@xano/cli 0.0.13 → 0.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/README.md +97 -12
  2. package/dist/commands/profile/create/index.d.ts +2 -0
  3. package/dist/commands/profile/create/index.js +15 -0
  4. package/dist/commands/profile/edit/index.d.ts +4 -0
  5. package/dist/commands/profile/edit/index.js +37 -1
  6. package/dist/commands/profile/list/index.js +5 -0
  7. package/dist/commands/profile/project/index.d.ts +6 -0
  8. package/dist/commands/profile/project/index.js +54 -0
  9. package/dist/commands/profile/token/index.d.ts +6 -0
  10. package/dist/commands/profile/token/index.js +54 -0
  11. package/dist/commands/profile/wizard/index.d.ts +1 -0
  12. package/dist/commands/profile/wizard/index.js +70 -0
  13. package/dist/commands/run/env/delete/index.d.ts +13 -0
  14. package/dist/commands/run/env/delete/index.js +65 -0
  15. package/dist/commands/run/env/get/index.d.ts +13 -0
  16. package/dist/commands/run/env/get/index.js +52 -0
  17. package/dist/commands/run/env/list/index.d.ts +11 -0
  18. package/dist/commands/run/env/list/index.js +58 -0
  19. package/dist/commands/run/env/set/index.d.ts +13 -0
  20. package/dist/commands/run/env/set/index.js +51 -0
  21. package/dist/commands/{ephemeral/run/job → run/exec}/index.d.ts +4 -3
  22. package/dist/commands/run/exec/index.js +353 -0
  23. package/dist/commands/{ephemeral/run/service → run/info}/index.d.ts +3 -5
  24. package/dist/commands/run/info/index.js +160 -0
  25. package/dist/commands/run/projects/create/index.d.ts +13 -0
  26. package/dist/commands/run/projects/create/index.js +75 -0
  27. package/dist/commands/run/projects/delete/index.d.ts +13 -0
  28. package/dist/commands/run/projects/delete/index.js +65 -0
  29. package/dist/commands/run/projects/list/index.d.ts +12 -0
  30. package/dist/commands/run/projects/list/index.js +66 -0
  31. package/dist/commands/run/projects/update/index.d.ts +15 -0
  32. package/dist/commands/run/projects/update/index.js +86 -0
  33. package/dist/commands/run/secrets/delete/index.d.ts +13 -0
  34. package/dist/commands/run/secrets/delete/index.js +65 -0
  35. package/dist/commands/run/secrets/get/index.d.ts +13 -0
  36. package/dist/commands/run/secrets/get/index.js +52 -0
  37. package/dist/commands/run/secrets/list/index.d.ts +11 -0
  38. package/dist/commands/run/secrets/list/index.js +62 -0
  39. package/dist/commands/run/secrets/set/index.d.ts +15 -0
  40. package/dist/commands/run/secrets/set/index.js +74 -0
  41. package/dist/commands/run/sessions/delete/index.d.ts +13 -0
  42. package/dist/commands/run/sessions/delete/index.js +65 -0
  43. package/dist/commands/run/sessions/get/index.d.ts +13 -0
  44. package/dist/commands/run/sessions/get/index.js +72 -0
  45. package/dist/commands/run/sessions/list/index.d.ts +12 -0
  46. package/dist/commands/run/sessions/list/index.js +64 -0
  47. package/dist/commands/run/sessions/start/index.d.ts +13 -0
  48. package/dist/commands/run/sessions/start/index.js +56 -0
  49. package/dist/commands/run/sessions/stop/index.d.ts +13 -0
  50. package/dist/commands/run/sessions/stop/index.js +56 -0
  51. package/dist/commands/run/sink/get/index.d.ts +13 -0
  52. package/dist/commands/run/sink/get/index.js +63 -0
  53. package/dist/lib/base-run-command.d.ts +41 -0
  54. package/dist/lib/base-run-command.js +73 -0
  55. package/dist/lib/run-http-client.d.ts +58 -0
  56. package/dist/lib/run-http-client.js +136 -0
  57. package/dist/lib/run-types.d.ts +226 -0
  58. package/dist/lib/run-types.js +5 -0
  59. package/oclif.manifest.json +1423 -306
  60. package/package.json +1 -1
  61. package/dist/commands/ephemeral/run/job/index.js +0 -311
  62. package/dist/commands/ephemeral/run/service/index.js +0 -287
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@xano/cli",
3
3
  "description": "CLI for Xano's Metadata API",
4
- "version": "0.0.13",
4
+ "version": "0.0.15",
5
5
  "author": "Sean Montgomery",
6
6
  "bin": {
7
7
  "xano": "./bin/run.js"
@@ -1,311 +0,0 @@
1
- import { 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 * as yaml from 'js-yaml';
7
- import BaseCommand from '../../../../base-command.js';
8
- export default class EphemeralRunJob extends BaseCommand {
9
- static args = {};
10
- static flags = {
11
- ...BaseCommand.baseFlags,
12
- file: Flags.string({
13
- char: 'f',
14
- description: 'Path or URL to file containing XanoScript code',
15
- required: false,
16
- exclusive: ['stdin'],
17
- }),
18
- stdin: Flags.boolean({
19
- char: 's',
20
- description: 'Read XanoScript code from stdin',
21
- required: false,
22
- default: false,
23
- exclusive: ['file'],
24
- }),
25
- edit: Flags.boolean({
26
- char: 'e',
27
- description: 'Open file in editor before running job (requires --file)',
28
- required: false,
29
- default: false,
30
- dependsOn: ['file'],
31
- }),
32
- output: Flags.string({
33
- char: 'o',
34
- description: 'Output format',
35
- required: false,
36
- default: 'summary',
37
- options: ['summary', 'json'],
38
- }),
39
- args: Flags.string({
40
- char: 'a',
41
- description: 'Path or URL to JSON file containing input arguments',
42
- required: false,
43
- }),
44
- };
45
- static description = 'Run an ephemeral job';
46
- static examples = [
47
- `$ xano ephemeral:run:job -f script.xs
48
- Job executed successfully!
49
- ...
50
- `,
51
- `$ xano ephemeral:run:job -f script.xs --edit
52
- # Opens script.xs in $EDITOR, then runs job with edited content
53
- Job executed successfully!
54
- ...
55
- `,
56
- `$ cat script.xs | xano ephemeral:run:job --stdin
57
- Job executed successfully!
58
- ...
59
- `,
60
- `$ xano ephemeral:run:job -f script.xs -o json
61
- {
62
- "job": { "id": 1, "run": { "id": 1 } },
63
- "result": { ... }
64
- }
65
- `,
66
- `$ xano ephemeral:run:job -f script.xs -a args.json
67
- # Runs job with input arguments from args.json
68
- Job executed successfully!
69
- ...
70
- `,
71
- ];
72
- async run() {
73
- const { flags } = await this.parse(EphemeralRunJob);
74
- // Get profile name (default or from flag/env)
75
- const profileName = flags.profile || this.getDefaultProfile();
76
- // Load credentials
77
- const credentials = this.loadCredentials();
78
- // Get the profile configuration
79
- if (!(profileName in credentials.profiles)) {
80
- this.error(`Profile '${profileName}' not found. Available profiles: ${Object.keys(credentials.profiles).join(', ')}\n` +
81
- `Create a profile using 'xano profile:create'`);
82
- }
83
- const profile = credentials.profiles[profileName];
84
- // Validate required fields
85
- if (!profile.instance_origin) {
86
- this.error(`Profile '${profileName}' is missing instance_origin`);
87
- }
88
- if (!profile.access_token) {
89
- this.error(`Profile '${profileName}' is missing access_token`);
90
- }
91
- // Read XanoScript content or use URL
92
- let xanoscript;
93
- let xanoscriptUrl;
94
- if (flags.file) {
95
- if (this.isUrl(flags.file)) {
96
- // Pass URL directly to API
97
- xanoscriptUrl = flags.file;
98
- }
99
- else if (flags.edit) {
100
- // If edit flag is set, copy to temp file and open in editor
101
- const fileToRead = await this.editFile(flags.file);
102
- xanoscript = fs.readFileSync(fileToRead, 'utf8');
103
- // Clean up temp file
104
- try {
105
- fs.unlinkSync(fileToRead);
106
- }
107
- catch {
108
- // Ignore cleanup errors
109
- }
110
- }
111
- else {
112
- try {
113
- xanoscript = fs.readFileSync(flags.file, 'utf8');
114
- }
115
- catch (error) {
116
- this.error(`Failed to read file '${flags.file}': ${error}`);
117
- }
118
- }
119
- }
120
- else if (flags.stdin) {
121
- // Read from stdin
122
- try {
123
- xanoscript = await this.readStdin();
124
- }
125
- catch (error) {
126
- this.error(`Failed to read from stdin: ${error}`);
127
- }
128
- }
129
- else {
130
- this.error('Either --file or --stdin must be specified to provide XanoScript code');
131
- }
132
- // Validate xanoscript is not empty (only if not using URL)
133
- if (!xanoscriptUrl && (!xanoscript || xanoscript.trim().length === 0)) {
134
- this.error('XanoScript content is empty');
135
- }
136
- // Load args from JSON file/URL if provided
137
- let inputArgs;
138
- let inputArgsUrl;
139
- if (flags.args) {
140
- if (this.isUrl(flags.args)) {
141
- // Pass URL directly to API
142
- inputArgsUrl = flags.args;
143
- }
144
- else {
145
- try {
146
- const argsContent = fs.readFileSync(flags.args, 'utf8');
147
- inputArgs = JSON.parse(argsContent);
148
- }
149
- catch (error) {
150
- this.error(`Failed to read or parse args '${flags.args}': ${error}`);
151
- }
152
- }
153
- }
154
- // Construct the API URL
155
- const apiUrl = `${profile.instance_origin}/api:meta/beta/ephemeral/job`;
156
- // Build request body
157
- const formData = new FormData();
158
- if (xanoscriptUrl) {
159
- formData.append('doc', xanoscriptUrl);
160
- }
161
- else {
162
- formData.append('doc', xanoscript);
163
- }
164
- if (inputArgsUrl) {
165
- formData.append('args', inputArgsUrl);
166
- }
167
- else if (inputArgs) {
168
- formData.append('args', JSON.stringify(inputArgs));
169
- }
170
- const requestBody = formData;
171
- // Run ephemeral job via API
172
- try {
173
- const response = await fetch(apiUrl, {
174
- method: 'POST',
175
- headers: {
176
- 'accept': 'application/json',
177
- 'Authorization': `Bearer ${profile.access_token}`,
178
- },
179
- body: requestBody,
180
- });
181
- if (!response.ok) {
182
- const errorText = await response.text();
183
- this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
184
- }
185
- const result = await response.json();
186
- // Output results
187
- if (flags.output === 'json') {
188
- this.log(JSON.stringify(result, null, 2));
189
- }
190
- else {
191
- // summary format
192
- this.log('Job executed successfully!');
193
- this.log('');
194
- this.log(` Job ID: ${result.job.id}`);
195
- this.log(` Run ID: ${result.job.run.id}`);
196
- this.log('');
197
- this.log(' Timing:');
198
- this.log(` Total: ${(result.result.total_time * 1000).toFixed(2)}ms`);
199
- this.log(` Boot: ${(result.result.boot_time * 1000).toFixed(2)}ms`);
200
- this.log(` Main: ${(result.result.main_time * 1000).toFixed(2)}ms`);
201
- this.log(` Pre: ${(result.result.pre_time * 1000).toFixed(2)}ms`);
202
- this.log(` Post: ${(result.result.post_time * 1000).toFixed(2)}ms`);
203
- this.log('');
204
- this.log(' Response:');
205
- const responseStr = typeof result.result.response === 'string'
206
- ? result.result.response
207
- : JSON.stringify(result.result.response, null, 2);
208
- // Indent multiline response
209
- const indentedResponse = responseStr.split('\n').map((line) => ` ${line}`).join('\n');
210
- this.log(indentedResponse);
211
- }
212
- }
213
- catch (error) {
214
- if (error instanceof Error) {
215
- this.error(`Failed to run ephemeral job: ${error.message}`);
216
- }
217
- else {
218
- this.error(`Failed to run ephemeral job: ${String(error)}`);
219
- }
220
- }
221
- }
222
- async editFile(filePath) {
223
- // Get the EDITOR environment variable
224
- const editor = process.env.EDITOR || process.env.VISUAL;
225
- if (!editor) {
226
- this.error('No editor configured. Please set the EDITOR or VISUAL environment variable.\n' +
227
- 'Example: export EDITOR=vim');
228
- }
229
- // Validate editor executable exists
230
- try {
231
- execSync(`which ${editor.split(' ')[0]}`, { stdio: 'ignore' });
232
- }
233
- catch {
234
- this.error(`Editor '${editor}' not found. Please set EDITOR to a valid editor.\n` +
235
- 'Example: export EDITOR=vim');
236
- }
237
- // Read the original file
238
- let originalContent;
239
- try {
240
- originalContent = fs.readFileSync(filePath, 'utf8');
241
- }
242
- catch (error) {
243
- this.error(`Failed to read file '${filePath}': ${error}`);
244
- }
245
- // Create a temporary file with the same extension
246
- const ext = path.extname(filePath);
247
- const tmpFile = path.join(os.tmpdir(), `xano-edit-${Date.now()}${ext}`);
248
- // Copy content to temp file
249
- try {
250
- fs.writeFileSync(tmpFile, originalContent, 'utf8');
251
- }
252
- catch (error) {
253
- this.error(`Failed to create temporary file: ${error}`);
254
- }
255
- // Open the editor
256
- try {
257
- execSync(`${editor} ${tmpFile}`, { stdio: 'inherit' });
258
- }
259
- catch (error) {
260
- // Clean up temp file
261
- try {
262
- fs.unlinkSync(tmpFile);
263
- }
264
- catch {
265
- // Ignore cleanup errors
266
- }
267
- this.error(`Editor exited with an error: ${error}`);
268
- }
269
- return tmpFile;
270
- }
271
- isUrl(str) {
272
- return str.startsWith('http://') || str.startsWith('https://');
273
- }
274
- async readStdin() {
275
- return new Promise((resolve, reject) => {
276
- const chunks = [];
277
- process.stdin.on('data', (chunk) => {
278
- chunks.push(chunk);
279
- });
280
- process.stdin.on('end', () => {
281
- resolve(Buffer.concat(chunks).toString('utf8'));
282
- });
283
- process.stdin.on('error', (error) => {
284
- reject(error);
285
- });
286
- // Resume stdin if it was paused
287
- process.stdin.resume();
288
- });
289
- }
290
- loadCredentials() {
291
- const configDir = path.join(os.homedir(), '.xano');
292
- const credentialsPath = path.join(configDir, 'credentials.yaml');
293
- // Check if credentials file exists
294
- if (!fs.existsSync(credentialsPath)) {
295
- this.error(`Credentials file not found at ${credentialsPath}\n` +
296
- `Create a profile using 'xano profile:create'`);
297
- }
298
- // Read credentials file
299
- try {
300
- const fileContent = fs.readFileSync(credentialsPath, 'utf8');
301
- const parsed = yaml.load(fileContent);
302
- if (!parsed || typeof parsed !== 'object' || !('profiles' in parsed)) {
303
- this.error('Credentials file has invalid format.');
304
- }
305
- return parsed;
306
- }
307
- catch (error) {
308
- this.error(`Failed to parse credentials file: ${error}`);
309
- }
310
- }
311
- }
@@ -1,287 +0,0 @@
1
- import { 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 * as yaml from 'js-yaml';
7
- import BaseCommand from '../../../../base-command.js';
8
- export default class EphemeralRunService extends BaseCommand {
9
- static args = {};
10
- static flags = {
11
- ...BaseCommand.baseFlags,
12
- file: Flags.string({
13
- char: 'f',
14
- description: 'Path or URL to file containing XanoScript code',
15
- required: false,
16
- exclusive: ['stdin'],
17
- }),
18
- stdin: Flags.boolean({
19
- char: 's',
20
- description: 'Read XanoScript code from stdin',
21
- required: false,
22
- default: false,
23
- exclusive: ['file'],
24
- }),
25
- edit: Flags.boolean({
26
- char: 'e',
27
- description: 'Open file in editor before running service (requires --file)',
28
- required: false,
29
- default: false,
30
- dependsOn: ['file'],
31
- }),
32
- output: Flags.string({
33
- char: 'o',
34
- description: 'Output format',
35
- required: false,
36
- default: 'summary',
37
- options: ['summary', 'json'],
38
- }),
39
- };
40
- static description = 'Run an ephemeral service';
41
- static examples = [
42
- `$ xano ephemeral:run:service -f service.xs
43
- Service created successfully!
44
- ...
45
- `,
46
- `$ xano ephemeral:run:service -f service.xs --edit
47
- # Opens service.xs in $EDITOR, then creates service with edited content
48
- Service created successfully!
49
- ...
50
- `,
51
- `$ cat service.xs | xano ephemeral:run:service --stdin
52
- Service created successfully!
53
- ...
54
- `,
55
- `$ xano ephemeral:run:service -f service.xs -o json
56
- {
57
- "service": { "id": 1 },
58
- ...
59
- }
60
- `,
61
- ];
62
- async run() {
63
- const { flags } = await this.parse(EphemeralRunService);
64
- // Get profile name (default or from flag/env)
65
- const profileName = flags.profile || this.getDefaultProfile();
66
- // Load credentials
67
- const credentials = this.loadCredentials();
68
- // Get the profile configuration
69
- if (!(profileName in credentials.profiles)) {
70
- this.error(`Profile '${profileName}' not found. Available profiles: ${Object.keys(credentials.profiles).join(', ')}\n` +
71
- `Create a profile using 'xano profile:create'`);
72
- }
73
- const profile = credentials.profiles[profileName];
74
- // Validate required fields
75
- if (!profile.instance_origin) {
76
- this.error(`Profile '${profileName}' is missing instance_origin`);
77
- }
78
- if (!profile.access_token) {
79
- this.error(`Profile '${profileName}' is missing access_token`);
80
- }
81
- // Read XanoScript content or use URL
82
- let xanoscript;
83
- let xanoscriptUrl;
84
- if (flags.file) {
85
- if (this.isUrl(flags.file)) {
86
- // Pass URL directly to API
87
- xanoscriptUrl = flags.file;
88
- }
89
- else if (flags.edit) {
90
- // If edit flag is set, copy to temp file and open in editor
91
- const fileToRead = await this.editFile(flags.file);
92
- xanoscript = fs.readFileSync(fileToRead, 'utf8');
93
- // Clean up temp file
94
- try {
95
- fs.unlinkSync(fileToRead);
96
- }
97
- catch {
98
- // Ignore cleanup errors
99
- }
100
- }
101
- else {
102
- try {
103
- xanoscript = fs.readFileSync(flags.file, 'utf8');
104
- }
105
- catch (error) {
106
- this.error(`Failed to read file '${flags.file}': ${error}`);
107
- }
108
- }
109
- }
110
- else if (flags.stdin) {
111
- // Read from stdin
112
- try {
113
- xanoscript = await this.readStdin();
114
- }
115
- catch (error) {
116
- this.error(`Failed to read from stdin: ${error}`);
117
- }
118
- }
119
- else {
120
- this.error('Either --file or --stdin must be specified to provide XanoScript code');
121
- }
122
- // Validate xanoscript is not empty (only if not using URL)
123
- if (!xanoscriptUrl && (!xanoscript || xanoscript.trim().length === 0)) {
124
- this.error('XanoScript content is empty');
125
- }
126
- // Construct the API URL
127
- const apiUrl = `${profile.instance_origin}/api:meta/beta/ephemeral/service`;
128
- // Build request body
129
- const formData = new FormData();
130
- if (xanoscriptUrl) {
131
- formData.append('doc', xanoscriptUrl);
132
- }
133
- else {
134
- formData.append('doc', xanoscript);
135
- }
136
- // Run ephemeral service via API
137
- try {
138
- const response = await fetch(apiUrl, {
139
- method: 'POST',
140
- headers: {
141
- 'accept': 'application/json',
142
- 'Authorization': `Bearer ${profile.access_token}`,
143
- },
144
- body: formData,
145
- });
146
- if (!response.ok) {
147
- const errorText = await response.text();
148
- this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
149
- }
150
- const result = await response.json();
151
- // Output results
152
- if (flags.output === 'json') {
153
- this.log(JSON.stringify(result, null, 2));
154
- }
155
- else {
156
- // summary format
157
- this.log('Service started successfully!');
158
- this.log('');
159
- this.log(` Service ID: ${result.service.id}`);
160
- this.log(` Run ID: ${result.service.run.id}`);
161
- this.log('');
162
- if (result.result) {
163
- const formatTime = (time) => time !== undefined ? `${(time * 1000).toFixed(2)}ms` : 'N/A';
164
- this.log(' Timing:');
165
- this.log(` Boot: ${formatTime(result.result.boot_time)}`);
166
- this.log(` Pre: ${formatTime(result.result.pre_time)}`);
167
- this.log('');
168
- if (result.result.endpoints && result.result.endpoints.length > 0) {
169
- this.log(' Endpoints:');
170
- for (const endpoint of result.result.endpoints) {
171
- this.log(` ${endpoint.verb.padEnd(6)} ${endpoint.url}`);
172
- if (endpoint.input.length > 0) {
173
- for (const input of endpoint.input) {
174
- const required = input.required ? '*' : '';
175
- const nullable = input.nullable ? '?' : '';
176
- this.log(` └─ ${input.name}${required}: ${input.type}${nullable} (${input.source})`);
177
- }
178
- }
179
- }
180
- this.log('');
181
- }
182
- if (result.result.metadata_api) {
183
- this.log(' Metadata API:');
184
- this.log(` ${result.result.metadata_api.url}`);
185
- }
186
- }
187
- }
188
- }
189
- catch (error) {
190
- if (error instanceof Error) {
191
- this.error(`Failed to run ephemeral service: ${error.message}`);
192
- }
193
- else {
194
- this.error(`Failed to run ephemeral service: ${String(error)}`);
195
- }
196
- }
197
- }
198
- async editFile(filePath) {
199
- // Get the EDITOR environment variable
200
- const editor = process.env.EDITOR || process.env.VISUAL;
201
- if (!editor) {
202
- this.error('No editor configured. Please set the EDITOR or VISUAL environment variable.\n' +
203
- 'Example: export EDITOR=vim');
204
- }
205
- // Validate editor executable exists
206
- try {
207
- execSync(`which ${editor.split(' ')[0]}`, { stdio: 'ignore' });
208
- }
209
- catch {
210
- this.error(`Editor '${editor}' not found. Please set EDITOR to a valid editor.\n` +
211
- 'Example: export EDITOR=vim');
212
- }
213
- // Read the original file
214
- let originalContent;
215
- try {
216
- originalContent = fs.readFileSync(filePath, 'utf8');
217
- }
218
- catch (error) {
219
- this.error(`Failed to read file '${filePath}': ${error}`);
220
- }
221
- // Create a temporary file with the same extension
222
- const ext = path.extname(filePath);
223
- const tmpFile = path.join(os.tmpdir(), `xano-edit-${Date.now()}${ext}`);
224
- // Copy content to temp file
225
- try {
226
- fs.writeFileSync(tmpFile, originalContent, 'utf8');
227
- }
228
- catch (error) {
229
- this.error(`Failed to create temporary file: ${error}`);
230
- }
231
- // Open the editor
232
- try {
233
- execSync(`${editor} ${tmpFile}`, { stdio: 'inherit' });
234
- }
235
- catch (error) {
236
- // Clean up temp file
237
- try {
238
- fs.unlinkSync(tmpFile);
239
- }
240
- catch {
241
- // Ignore cleanup errors
242
- }
243
- this.error(`Editor exited with an error: ${error}`);
244
- }
245
- return tmpFile;
246
- }
247
- isUrl(str) {
248
- return str.startsWith('http://') || str.startsWith('https://');
249
- }
250
- async readStdin() {
251
- return new Promise((resolve, reject) => {
252
- const chunks = [];
253
- process.stdin.on('data', (chunk) => {
254
- chunks.push(chunk);
255
- });
256
- process.stdin.on('end', () => {
257
- resolve(Buffer.concat(chunks).toString('utf8'));
258
- });
259
- process.stdin.on('error', (error) => {
260
- reject(error);
261
- });
262
- // Resume stdin if it was paused
263
- process.stdin.resume();
264
- });
265
- }
266
- loadCredentials() {
267
- const configDir = path.join(os.homedir(), '.xano');
268
- const credentialsPath = path.join(configDir, 'credentials.yaml');
269
- // Check if credentials file exists
270
- if (!fs.existsSync(credentialsPath)) {
271
- this.error(`Credentials file not found at ${credentialsPath}\n` +
272
- `Create a profile using 'xano profile:create'`);
273
- }
274
- // Read credentials file
275
- try {
276
- const fileContent = fs.readFileSync(credentialsPath, 'utf8');
277
- const parsed = yaml.load(fileContent);
278
- if (!parsed || typeof parsed !== 'object' || !('profiles' in parsed)) {
279
- this.error('Credentials file has invalid format.');
280
- }
281
- return parsed;
282
- }
283
- catch (error) {
284
- this.error(`Failed to parse credentials file: ${error}`);
285
- }
286
- }
287
- }