@xano/cli 0.0.2

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 (49) hide show
  1. package/README.md +1200 -0
  2. package/bin/dev.cmd +3 -0
  3. package/bin/dev.js +5 -0
  4. package/bin/run.cmd +3 -0
  5. package/bin/run.js +5 -0
  6. package/dist/base-command.d.ts +11 -0
  7. package/dist/base-command.js +40 -0
  8. package/dist/commands/ephemeral/run/job/index.d.ts +19 -0
  9. package/dist/commands/ephemeral/run/job/index.js +318 -0
  10. package/dist/commands/ephemeral/run/service/index.d.ts +18 -0
  11. package/dist/commands/ephemeral/run/service/index.js +286 -0
  12. package/dist/commands/function/create/index.d.ts +18 -0
  13. package/dist/commands/function/create/index.js +280 -0
  14. package/dist/commands/function/edit/index.d.ts +24 -0
  15. package/dist/commands/function/edit/index.js +482 -0
  16. package/dist/commands/function/get/index.d.ts +18 -0
  17. package/dist/commands/function/get/index.js +279 -0
  18. package/dist/commands/function/list/index.d.ts +19 -0
  19. package/dist/commands/function/list/index.js +208 -0
  20. package/dist/commands/profile/create/index.d.ts +17 -0
  21. package/dist/commands/profile/create/index.js +123 -0
  22. package/dist/commands/profile/delete/index.d.ts +14 -0
  23. package/dist/commands/profile/delete/index.js +124 -0
  24. package/dist/commands/profile/edit/index.d.ts +18 -0
  25. package/dist/commands/profile/edit/index.js +129 -0
  26. package/dist/commands/profile/get-default/index.d.ts +6 -0
  27. package/dist/commands/profile/get-default/index.js +44 -0
  28. package/dist/commands/profile/list/index.d.ts +10 -0
  29. package/dist/commands/profile/list/index.js +115 -0
  30. package/dist/commands/profile/set-default/index.d.ts +9 -0
  31. package/dist/commands/profile/set-default/index.js +63 -0
  32. package/dist/commands/profile/wizard/index.d.ts +15 -0
  33. package/dist/commands/profile/wizard/index.js +350 -0
  34. package/dist/commands/static_host/build/create/index.d.ts +18 -0
  35. package/dist/commands/static_host/build/create/index.js +194 -0
  36. package/dist/commands/static_host/build/get/index.d.ts +16 -0
  37. package/dist/commands/static_host/build/get/index.js +165 -0
  38. package/dist/commands/static_host/build/list/index.d.ts +17 -0
  39. package/dist/commands/static_host/build/list/index.js +192 -0
  40. package/dist/commands/static_host/list/index.d.ts +15 -0
  41. package/dist/commands/static_host/list/index.js +187 -0
  42. package/dist/commands/workspace/list/index.d.ts +11 -0
  43. package/dist/commands/workspace/list/index.js +154 -0
  44. package/dist/help.d.ts +20 -0
  45. package/dist/help.js +26 -0
  46. package/dist/index.d.ts +1 -0
  47. package/dist/index.js +1 -0
  48. package/oclif.manifest.json +1370 -0
  49. package/package.json +79 -0
@@ -0,0 +1,286 @@
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
+ workspace: Flags.string({
13
+ char: 'w',
14
+ description: 'Workspace ID (optional if set in profile)',
15
+ required: false,
16
+ }),
17
+ file: Flags.string({
18
+ char: 'f',
19
+ description: 'Path to file containing XanoScript code',
20
+ required: false,
21
+ exclusive: ['stdin'],
22
+ }),
23
+ stdin: Flags.boolean({
24
+ char: 's',
25
+ description: 'Read XanoScript code from stdin',
26
+ required: false,
27
+ default: false,
28
+ exclusive: ['file'],
29
+ }),
30
+ edit: Flags.boolean({
31
+ char: 'e',
32
+ description: 'Open file in editor before running service (requires --file)',
33
+ required: false,
34
+ default: false,
35
+ dependsOn: ['file'],
36
+ }),
37
+ output: Flags.string({
38
+ char: 'o',
39
+ description: 'Output format',
40
+ required: false,
41
+ default: 'summary',
42
+ options: ['summary', 'json'],
43
+ }),
44
+ };
45
+ static description = 'Run an ephemeral service in a workspace';
46
+ static examples = [
47
+ `$ xano ephemeral:run:service -w 1 -f service.xs
48
+ Service created successfully!
49
+ ...
50
+ `,
51
+ `$ xano ephemeral:run:service -f service.xs
52
+ Service created successfully!
53
+ ...
54
+ `,
55
+ `$ xano ephemeral:run:service -w 1 -f service.xs --edit
56
+ # Opens service.xs in $EDITOR, then creates service with edited content
57
+ Service created successfully!
58
+ ...
59
+ `,
60
+ `$ cat service.xs | xano ephemeral:run:service -w 1 --stdin
61
+ Service created successfully!
62
+ ...
63
+ `,
64
+ `$ xano ephemeral:run:service -w 1 -f service.xs -o json
65
+ {
66
+ "service": { "id": 1 },
67
+ ...
68
+ }
69
+ `,
70
+ ];
71
+ async run() {
72
+ const { flags } = await this.parse(EphemeralRunService);
73
+ // Get profile name (default or from flag/env)
74
+ const profileName = flags.profile || this.getDefaultProfile();
75
+ // Load credentials
76
+ const credentials = this.loadCredentials();
77
+ // Get the profile configuration
78
+ if (!(profileName in credentials.profiles)) {
79
+ this.error(`Profile '${profileName}' not found. Available profiles: ${Object.keys(credentials.profiles).join(', ')}\n` +
80
+ `Create a profile using 'xano profile:create'`);
81
+ }
82
+ const profile = credentials.profiles[profileName];
83
+ // Validate required fields
84
+ if (!profile.instance_origin) {
85
+ this.error(`Profile '${profileName}' is missing instance_origin`);
86
+ }
87
+ if (!profile.access_token) {
88
+ this.error(`Profile '${profileName}' is missing access_token`);
89
+ }
90
+ // Determine workspace_id from flag or profile
91
+ let workspaceId;
92
+ if (flags.workspace) {
93
+ workspaceId = flags.workspace;
94
+ }
95
+ else if (profile.workspace) {
96
+ workspaceId = profile.workspace;
97
+ }
98
+ else {
99
+ this.error(`Workspace ID is required. Either:\n` +
100
+ ` 1. Provide it as a flag: xano ephemeral:run:service -w <workspace_id>\n` +
101
+ ` 2. Set it in your profile using: xano profile:edit ${profileName} -w <workspace_id>`);
102
+ }
103
+ // Read XanoScript content
104
+ let xanoscript;
105
+ if (flags.file) {
106
+ // Read from file
107
+ let fileToRead = flags.file;
108
+ // If edit flag is set, copy to temp file and open in editor
109
+ if (flags.edit) {
110
+ fileToRead = await this.editFile(flags.file);
111
+ }
112
+ try {
113
+ xanoscript = fs.readFileSync(fileToRead, 'utf8');
114
+ // Clean up temp file if it was created
115
+ if (flags.edit && fileToRead !== flags.file) {
116
+ try {
117
+ fs.unlinkSync(fileToRead);
118
+ }
119
+ catch {
120
+ // Ignore cleanup errors
121
+ }
122
+ }
123
+ }
124
+ catch (error) {
125
+ this.error(`Failed to read file '${fileToRead}': ${error}`);
126
+ }
127
+ }
128
+ else if (flags.stdin) {
129
+ // Read from stdin
130
+ try {
131
+ xanoscript = await this.readStdin();
132
+ }
133
+ catch (error) {
134
+ this.error(`Failed to read from stdin: ${error}`);
135
+ }
136
+ }
137
+ else {
138
+ this.error('Either --file or --stdin must be specified to provide XanoScript code');
139
+ }
140
+ // Validate xanoscript is not empty
141
+ if (!xanoscript || xanoscript.trim().length === 0) {
142
+ this.error('XanoScript content is empty');
143
+ }
144
+ // Construct the API URL
145
+ const apiUrl = `${profile.instance_origin}/api:meta/beta/workspace/${workspaceId}/ephemeral/service`;
146
+ // Run ephemeral service via API
147
+ try {
148
+ const response = await fetch(apiUrl, {
149
+ method: 'POST',
150
+ headers: {
151
+ 'accept': 'application/json',
152
+ 'Content-Type': 'text/x-xanoscript',
153
+ 'Authorization': `Bearer ${profile.access_token}`,
154
+ },
155
+ body: xanoscript,
156
+ });
157
+ if (!response.ok) {
158
+ const errorText = await response.text();
159
+ this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
160
+ }
161
+ const result = await response.json();
162
+ // Output results
163
+ if (flags.output === 'json') {
164
+ this.log(JSON.stringify(result, null, 2));
165
+ }
166
+ else {
167
+ // summary format
168
+ this.log('Service started successfully!');
169
+ this.log('');
170
+ this.log(` Service ID: ${result.service.id}`);
171
+ this.log(` Run ID: ${result.service.run.id}`);
172
+ this.log('');
173
+ if (result.result) {
174
+ const formatTime = (time) => time !== undefined ? `${(time * 1000).toFixed(2)}ms` : 'N/A';
175
+ this.log(' Timing:');
176
+ this.log(` Boot: ${formatTime(result.result.boot_time)}`);
177
+ this.log(` Pre: ${formatTime(result.result.pre_time)}`);
178
+ this.log('');
179
+ if (result.result.response !== undefined) {
180
+ this.log(' Response:');
181
+ const responseStr = typeof result.result.response === 'string'
182
+ ? result.result.response
183
+ : JSON.stringify(result.result.response, null, 2);
184
+ // Indent multiline response
185
+ const indentedResponse = responseStr.split('\n').map((line) => ` ${line}`).join('\n');
186
+ this.log(indentedResponse);
187
+ }
188
+ }
189
+ }
190
+ }
191
+ catch (error) {
192
+ if (error instanceof Error) {
193
+ this.error(`Failed to run ephemeral service: ${error.message}`);
194
+ }
195
+ else {
196
+ this.error(`Failed to run ephemeral service: ${String(error)}`);
197
+ }
198
+ }
199
+ }
200
+ async editFile(filePath) {
201
+ // Get the EDITOR environment variable
202
+ const editor = process.env.EDITOR || process.env.VISUAL;
203
+ if (!editor) {
204
+ this.error('No editor configured. Please set the EDITOR or VISUAL environment variable.\n' +
205
+ 'Example: export EDITOR=vim');
206
+ }
207
+ // Validate editor executable exists
208
+ try {
209
+ execSync(`which ${editor.split(' ')[0]}`, { stdio: 'ignore' });
210
+ }
211
+ catch {
212
+ this.error(`Editor '${editor}' not found. Please set EDITOR to a valid editor.\n` +
213
+ 'Example: export EDITOR=vim');
214
+ }
215
+ // Read the original file
216
+ let originalContent;
217
+ try {
218
+ originalContent = fs.readFileSync(filePath, 'utf8');
219
+ }
220
+ catch (error) {
221
+ this.error(`Failed to read file '${filePath}': ${error}`);
222
+ }
223
+ // Create a temporary file with the same extension
224
+ const ext = path.extname(filePath);
225
+ const tmpFile = path.join(os.tmpdir(), `xano-edit-${Date.now()}${ext}`);
226
+ // Copy content to temp file
227
+ try {
228
+ fs.writeFileSync(tmpFile, originalContent, 'utf8');
229
+ }
230
+ catch (error) {
231
+ this.error(`Failed to create temporary file: ${error}`);
232
+ }
233
+ // Open the editor
234
+ try {
235
+ execSync(`${editor} ${tmpFile}`, { stdio: 'inherit' });
236
+ }
237
+ catch (error) {
238
+ // Clean up temp file
239
+ try {
240
+ fs.unlinkSync(tmpFile);
241
+ }
242
+ catch {
243
+ // Ignore cleanup errors
244
+ }
245
+ this.error(`Editor exited with an error: ${error}`);
246
+ }
247
+ return tmpFile;
248
+ }
249
+ async readStdin() {
250
+ return new Promise((resolve, reject) => {
251
+ const chunks = [];
252
+ process.stdin.on('data', (chunk) => {
253
+ chunks.push(chunk);
254
+ });
255
+ process.stdin.on('end', () => {
256
+ resolve(Buffer.concat(chunks).toString('utf8'));
257
+ });
258
+ process.stdin.on('error', (error) => {
259
+ reject(error);
260
+ });
261
+ // Resume stdin if it was paused
262
+ process.stdin.resume();
263
+ });
264
+ }
265
+ loadCredentials() {
266
+ const configDir = path.join(os.homedir(), '.xano');
267
+ const credentialsPath = path.join(configDir, 'credentials.yaml');
268
+ // Check if credentials file exists
269
+ if (!fs.existsSync(credentialsPath)) {
270
+ this.error(`Credentials file not found at ${credentialsPath}\n` +
271
+ `Create a profile using 'xano profile:create'`);
272
+ }
273
+ // Read credentials file
274
+ try {
275
+ const fileContent = fs.readFileSync(credentialsPath, 'utf8');
276
+ const parsed = yaml.load(fileContent);
277
+ if (!parsed || typeof parsed !== 'object' || !('profiles' in parsed)) {
278
+ this.error('Credentials file has invalid format.');
279
+ }
280
+ return parsed;
281
+ }
282
+ catch (error) {
283
+ this.error(`Failed to parse credentials file: ${error}`);
284
+ }
285
+ }
286
+ }
@@ -0,0 +1,18 @@
1
+ import BaseCommand from '../../../base-command.js';
2
+ export default class FunctionCreate extends BaseCommand {
3
+ static args: {};
4
+ static flags: {
5
+ workspace: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
6
+ file: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
7
+ stdin: import("@oclif/core/interfaces").BooleanFlag<boolean>;
8
+ edit: import("@oclif/core/interfaces").BooleanFlag<boolean>;
9
+ output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
10
+ profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
+ };
12
+ static description: string;
13
+ static examples: string[];
14
+ run(): Promise<void>;
15
+ private editFile;
16
+ private readStdin;
17
+ private loadCredentials;
18
+ }
@@ -0,0 +1,280 @@
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 FunctionCreate extends BaseCommand {
9
+ static args = {};
10
+ static flags = {
11
+ ...BaseCommand.baseFlags,
12
+ workspace: Flags.string({
13
+ char: 'w',
14
+ description: 'Workspace ID (optional if set in profile)',
15
+ required: false,
16
+ }),
17
+ file: Flags.string({
18
+ char: 'f',
19
+ description: 'Path to file containing XanoScript code',
20
+ required: false,
21
+ exclusive: ['stdin'],
22
+ }),
23
+ stdin: Flags.boolean({
24
+ char: 's',
25
+ description: 'Read XanoScript code from stdin',
26
+ required: false,
27
+ default: false,
28
+ exclusive: ['file'],
29
+ }),
30
+ edit: Flags.boolean({
31
+ char: 'e',
32
+ description: 'Open file in editor before creating function (requires --file)',
33
+ required: false,
34
+ default: false,
35
+ dependsOn: ['file'],
36
+ }),
37
+ output: Flags.string({
38
+ char: 'o',
39
+ description: 'Output format',
40
+ required: false,
41
+ default: 'summary',
42
+ options: ['summary', 'json'],
43
+ }),
44
+ };
45
+ static description = 'Create a new function in a workspace';
46
+ static examples = [
47
+ `$ xano function:create -w 40 -f function.xs
48
+ Function created successfully!
49
+ ID: 123
50
+ Name: my_function
51
+ `,
52
+ `$ xano function:create -f function.xs
53
+ Function created successfully!
54
+ ID: 123
55
+ Name: my_function
56
+ `,
57
+ `$ xano function:create -w 40 -f function.xs --edit
58
+ # Opens function.xs in $EDITOR, then creates function with edited content
59
+ Function created successfully!
60
+ ID: 123
61
+ Name: my_function
62
+ `,
63
+ `$ cat function.xs | xano function:create -w 40 --stdin
64
+ Function created successfully!
65
+ ID: 123
66
+ Name: my_function
67
+ `,
68
+ `$ xano function:create -w 40 -f function.xs -o json
69
+ {
70
+ "id": 123,
71
+ "name": "my_function",
72
+ ...
73
+ }
74
+ `,
75
+ ];
76
+ async run() {
77
+ const { flags } = await this.parse(FunctionCreate);
78
+ // Get profile name (default or from flag/env)
79
+ const profileName = flags.profile || this.getDefaultProfile();
80
+ // Load credentials
81
+ const credentials = this.loadCredentials();
82
+ // Get the profile configuration
83
+ if (!(profileName in credentials.profiles)) {
84
+ this.error(`Profile '${profileName}' not found. Available profiles: ${Object.keys(credentials.profiles).join(', ')}\n` +
85
+ `Create a profile using 'xano profile:create'`);
86
+ }
87
+ const profile = credentials.profiles[profileName];
88
+ // Validate required fields
89
+ if (!profile.instance_origin) {
90
+ this.error(`Profile '${profileName}' is missing instance_origin`);
91
+ }
92
+ if (!profile.access_token) {
93
+ this.error(`Profile '${profileName}' is missing access_token`);
94
+ }
95
+ // Determine workspace_id from flag or profile
96
+ let workspaceId;
97
+ if (flags.workspace) {
98
+ workspaceId = flags.workspace;
99
+ }
100
+ else if (profile.workspace) {
101
+ workspaceId = profile.workspace;
102
+ }
103
+ else {
104
+ this.error(`Workspace ID is required. Either:\n` +
105
+ ` 1. Provide it as a flag: xano function:create -w <workspace_id>\n` +
106
+ ` 2. Set it in your profile using: xano profile:edit ${profileName} -w <workspace_id>`);
107
+ }
108
+ // Read XanoScript content
109
+ let xanoscript;
110
+ if (flags.file) {
111
+ // Read from file
112
+ let fileToRead = flags.file;
113
+ // If edit flag is set, copy to temp file and open in editor
114
+ if (flags.edit) {
115
+ fileToRead = await this.editFile(flags.file);
116
+ }
117
+ try {
118
+ xanoscript = fs.readFileSync(fileToRead, 'utf8');
119
+ // Clean up temp file if it was created
120
+ if (flags.edit && fileToRead !== flags.file) {
121
+ try {
122
+ fs.unlinkSync(fileToRead);
123
+ }
124
+ catch {
125
+ // Ignore cleanup errors
126
+ }
127
+ }
128
+ }
129
+ catch (error) {
130
+ this.error(`Failed to read file '${fileToRead}': ${error}`);
131
+ }
132
+ }
133
+ else if (flags.stdin) {
134
+ // Read from stdin
135
+ try {
136
+ xanoscript = await this.readStdin();
137
+ }
138
+ catch (error) {
139
+ this.error(`Failed to read from stdin: ${error}`);
140
+ }
141
+ }
142
+ else {
143
+ this.error('Either --file or --stdin must be specified to provide XanoScript code');
144
+ }
145
+ // Validate xanoscript is not empty
146
+ if (!xanoscript || xanoscript.trim().length === 0) {
147
+ this.error('XanoScript content is empty');
148
+ }
149
+ // Construct the API URL
150
+ const queryParams = new URLSearchParams({
151
+ include_xanoscript: 'false',
152
+ });
153
+ const apiUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}/function?${queryParams.toString()}`;
154
+ // Create function via API
155
+ try {
156
+ const response = await fetch(apiUrl, {
157
+ method: 'POST',
158
+ headers: {
159
+ 'accept': 'application/json',
160
+ 'Content-Type': 'text/x-xanoscript',
161
+ 'Authorization': `Bearer ${profile.access_token}`,
162
+ },
163
+ body: xanoscript,
164
+ });
165
+ if (!response.ok) {
166
+ const errorText = await response.text();
167
+ this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
168
+ }
169
+ const result = await response.json();
170
+ // Validate response
171
+ if (!result || typeof result !== 'object') {
172
+ this.error('Unexpected API response format');
173
+ }
174
+ // Output results
175
+ if (flags.output === 'json') {
176
+ this.log(JSON.stringify(result, null, 2));
177
+ }
178
+ else {
179
+ // summary format
180
+ this.log('Function created successfully!');
181
+ this.log(`ID: ${result.id}`);
182
+ this.log(`Name: ${result.name}`);
183
+ }
184
+ }
185
+ catch (error) {
186
+ if (error instanceof Error) {
187
+ this.error(`Failed to create function: ${error.message}`);
188
+ }
189
+ else {
190
+ this.error(`Failed to create function: ${String(error)}`);
191
+ }
192
+ }
193
+ }
194
+ async editFile(filePath) {
195
+ // Get the EDITOR environment variable
196
+ const editor = process.env.EDITOR || process.env.VISUAL;
197
+ if (!editor) {
198
+ this.error('No editor configured. Please set the EDITOR or VISUAL environment variable.\n' +
199
+ 'Example: export EDITOR=vim');
200
+ }
201
+ // Validate editor executable exists
202
+ try {
203
+ execSync(`which ${editor.split(' ')[0]}`, { stdio: 'ignore' });
204
+ }
205
+ catch {
206
+ this.error(`Editor '${editor}' not found. Please set EDITOR to a valid editor.\n` +
207
+ 'Example: export EDITOR=vim');
208
+ }
209
+ // Read the original file
210
+ let originalContent;
211
+ try {
212
+ originalContent = fs.readFileSync(filePath, 'utf8');
213
+ }
214
+ catch (error) {
215
+ this.error(`Failed to read file '${filePath}': ${error}`);
216
+ }
217
+ // Create a temporary file with the same extension
218
+ const ext = path.extname(filePath);
219
+ const tmpFile = path.join(os.tmpdir(), `xano-edit-${Date.now()}${ext}`);
220
+ // Copy content to temp file
221
+ try {
222
+ fs.writeFileSync(tmpFile, originalContent, 'utf8');
223
+ }
224
+ catch (error) {
225
+ this.error(`Failed to create temporary file: ${error}`);
226
+ }
227
+ // Open the editor
228
+ try {
229
+ execSync(`${editor} ${tmpFile}`, { stdio: 'inherit' });
230
+ }
231
+ catch (error) {
232
+ // Clean up temp file
233
+ try {
234
+ fs.unlinkSync(tmpFile);
235
+ }
236
+ catch {
237
+ // Ignore cleanup errors
238
+ }
239
+ this.error(`Editor exited with an error: ${error}`);
240
+ }
241
+ return tmpFile;
242
+ }
243
+ async readStdin() {
244
+ return new Promise((resolve, reject) => {
245
+ const chunks = [];
246
+ process.stdin.on('data', (chunk) => {
247
+ chunks.push(chunk);
248
+ });
249
+ process.stdin.on('end', () => {
250
+ resolve(Buffer.concat(chunks).toString('utf8'));
251
+ });
252
+ process.stdin.on('error', (error) => {
253
+ reject(error);
254
+ });
255
+ // Resume stdin if it was paused
256
+ process.stdin.resume();
257
+ });
258
+ }
259
+ loadCredentials() {
260
+ const configDir = path.join(os.homedir(), '.xano');
261
+ const credentialsPath = path.join(configDir, 'credentials.yaml');
262
+ // Check if credentials file exists
263
+ if (!fs.existsSync(credentialsPath)) {
264
+ this.error(`Credentials file not found at ${credentialsPath}\n` +
265
+ `Create a profile using 'xano profile:create'`);
266
+ }
267
+ // Read credentials file
268
+ try {
269
+ const fileContent = fs.readFileSync(credentialsPath, 'utf8');
270
+ const parsed = yaml.load(fileContent);
271
+ if (!parsed || typeof parsed !== 'object' || !('profiles' in parsed)) {
272
+ this.error('Credentials file has invalid format.');
273
+ }
274
+ return parsed;
275
+ }
276
+ catch (error) {
277
+ this.error(`Failed to parse credentials file: ${error}`);
278
+ }
279
+ }
280
+ }
@@ -0,0 +1,24 @@
1
+ import BaseCommand from '../../../base-command.js';
2
+ export default class FunctionEdit extends BaseCommand {
3
+ static args: {
4
+ function_id: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
5
+ };
6
+ static flags: {
7
+ workspace: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
8
+ file: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
9
+ stdin: import("@oclif/core/interfaces").BooleanFlag<boolean>;
10
+ edit: import("@oclif/core/interfaces").BooleanFlag<boolean>;
11
+ publish: import("@oclif/core/interfaces").BooleanFlag<boolean>;
12
+ output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
13
+ profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
14
+ };
15
+ static description: string;
16
+ static examples: string[];
17
+ run(): Promise<void>;
18
+ private fetchFunctionCode;
19
+ private editFunctionContent;
20
+ private editFile;
21
+ private readStdin;
22
+ private promptForFunctionId;
23
+ private loadCredentials;
24
+ }