@xano/cli 0.0.29 → 0.0.30

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.
@@ -10,4 +10,9 @@ export default abstract class BaseCommand extends Command {
10
10
  };
11
11
  protected getDefaultProfile(): string;
12
12
  protected getProfile(): string | undefined;
13
+ /**
14
+ * Make an HTTP request with optional verbose logging.
15
+ * Use this for all Metadata API calls to support the --verbose flag.
16
+ */
17
+ protected verboseFetch(url: string, options: RequestInit, verbose: boolean, authToken?: string): Promise<Response>;
13
18
  }
@@ -44,4 +44,35 @@ export default class BaseCommand extends Command {
44
44
  getProfile() {
45
45
  return this.flags?.profile;
46
46
  }
47
+ /**
48
+ * Make an HTTP request with optional verbose logging.
49
+ * Use this for all Metadata API calls to support the --verbose flag.
50
+ */
51
+ async verboseFetch(url, options, verbose, authToken) {
52
+ const method = options.method || 'GET';
53
+ const contentType = options.headers?.['Content-Type'] || 'application/json';
54
+ if (verbose) {
55
+ this.log('');
56
+ this.log('─'.repeat(60));
57
+ this.log(`→ ${method} ${url}`);
58
+ this.log(` Content-Type: ${contentType}`);
59
+ if (authToken) {
60
+ this.log(` Authorization: Bearer ${authToken.slice(0, 8)}...${authToken.slice(-4)}`);
61
+ }
62
+ if (options.body) {
63
+ const bodyStr = typeof options.body === 'string' ? options.body : String(options.body);
64
+ const bodyPreview = bodyStr.length > 500 ? bodyStr.slice(0, 500) + '...' : bodyStr;
65
+ this.log(` Body: ${bodyPreview}`);
66
+ }
67
+ }
68
+ const startTime = Date.now();
69
+ const response = await fetch(url, options);
70
+ const elapsed = Date.now() - startTime;
71
+ if (verbose) {
72
+ this.log(`← ${response.status} ${response.statusText} (${elapsed}ms)`);
73
+ this.log('─'.repeat(60));
74
+ this.log('');
75
+ }
76
+ return response;
77
+ }
47
78
  }
@@ -101,15 +101,15 @@ Created branch: feature-auth
101
101
  const apiUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}/branch`;
102
102
  // Create branch via the API
103
103
  try {
104
- const response = await fetch(apiUrl, {
104
+ const response = await this.verboseFetch(apiUrl, {
105
105
  body: JSON.stringify(body),
106
106
  headers: {
107
107
  'accept': 'application/json',
108
108
  'Authorization': `Bearer ${profile.access_token}`,
109
- 'content-type': 'application/json',
109
+ 'Content-Type': 'application/json',
110
110
  },
111
111
  method: 'POST',
112
- });
112
+ }, flags.verbose, profile.access_token);
113
113
  if (!response.ok) {
114
114
  const errorText = await response.text();
115
115
  this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
@@ -90,13 +90,13 @@ Deleted branch: dev
90
90
  const apiUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}/branch/${encodeURIComponent(branchLabel)}`;
91
91
  // Delete branch via the API
92
92
  try {
93
- const response = await fetch(apiUrl, {
93
+ const response = await this.verboseFetch(apiUrl, {
94
94
  headers: {
95
95
  'accept': 'application/json',
96
96
  'Authorization': `Bearer ${profile.access_token}`,
97
97
  },
98
98
  method: 'DELETE',
99
- });
99
+ }, flags.verbose, profile.access_token);
100
100
  if (!response.ok) {
101
101
  const errorText = await response.text();
102
102
  this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
@@ -104,15 +104,15 @@ Updated branch: feature-authentication
104
104
  const apiUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}/branch/${encodeURIComponent(branchLabel)}`;
105
105
  // Update branch via the API
106
106
  try {
107
- const response = await fetch(apiUrl, {
107
+ const response = await this.verboseFetch(apiUrl, {
108
108
  body: JSON.stringify(body),
109
109
  headers: {
110
110
  'accept': 'application/json',
111
111
  'Authorization': `Bearer ${profile.access_token}`,
112
- 'content-type': 'application/json',
112
+ 'Content-Type': 'application/json',
113
113
  },
114
114
  method: 'PUT',
115
- });
115
+ }, flags.verbose, profile.access_token);
116
116
  if (!response.ok) {
117
117
  const errorText = await response.text();
118
118
  this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
@@ -75,13 +75,13 @@ Branch: dev
75
75
  const apiUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}/branch/${encodeURIComponent(branchLabel)}`;
76
76
  // Fetch branch from the API
77
77
  try {
78
- const response = await fetch(apiUrl, {
78
+ const response = await this.verboseFetch(apiUrl, {
79
79
  headers: {
80
80
  'accept': 'application/json',
81
81
  'Authorization': `Bearer ${profile.access_token}`,
82
82
  },
83
83
  method: 'GET',
84
- });
84
+ }, flags.verbose, profile.access_token);
85
85
  if (!response.ok) {
86
86
  const errorText = await response.text();
87
87
  this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
@@ -74,13 +74,13 @@ Available branches:
74
74
  const apiUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}/branch`;
75
75
  // Fetch branches from the API
76
76
  try {
77
- const response = await fetch(apiUrl, {
77
+ const response = await this.verboseFetch(apiUrl, {
78
78
  headers: {
79
79
  'accept': 'application/json',
80
80
  'Authorization': `Bearer ${profile.access_token}`,
81
81
  },
82
82
  method: 'GET',
83
- });
83
+ }, flags.verbose, profile.access_token);
84
84
  if (!response.ok) {
85
85
  const errorText = await response.text();
86
86
  this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
@@ -88,13 +88,13 @@ Branch 'v1' is now live
88
88
  const apiUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}/branch/${encodeURIComponent(branchLabel)}/live`;
89
89
  // Set branch as live via the API
90
90
  try {
91
- const response = await fetch(apiUrl, {
91
+ const response = await this.verboseFetch(apiUrl, {
92
92
  headers: {
93
93
  'accept': 'application/json',
94
94
  'Authorization': `Bearer ${profile.access_token}`,
95
95
  },
96
96
  method: 'POST',
97
- });
97
+ }, flags.verbose, profile.access_token);
98
98
  if (!response.ok) {
99
99
  const errorText = await response.text();
100
100
  this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
@@ -153,7 +153,7 @@ Name: my_function
153
153
  const apiUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}/function?${queryParams.toString()}`;
154
154
  // Create function via API
155
155
  try {
156
- const response = await fetch(apiUrl, {
156
+ const response = await this.verboseFetch(apiUrl, {
157
157
  body: xanoscript,
158
158
  headers: {
159
159
  'accept': 'application/json',
@@ -161,7 +161,7 @@ Name: my_function
161
161
  'Content-Type': 'text/x-xanoscript',
162
162
  },
163
163
  method: 'POST',
164
- });
164
+ }, flags.verbose, profile.access_token);
165
165
  if (!response.ok) {
166
166
  const errorText = await response.text();
167
167
  this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
@@ -196,7 +196,7 @@ Name: my_function
196
196
  const apiUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}/function/${functionId}?${queryParams.toString()}`;
197
197
  // Update function via API
198
198
  try {
199
- const response = await fetch(apiUrl, {
199
+ const response = await this.verboseFetch(apiUrl, {
200
200
  body: xanoscript,
201
201
  headers: {
202
202
  'accept': 'application/json',
@@ -204,7 +204,7 @@ Name: my_function
204
204
  'Content-Type': 'text/x-xanoscript',
205
205
  },
206
206
  method: 'PUT',
207
- });
207
+ }, flags.verbose, profile.access_token);
208
208
  if (!response.ok) {
209
209
  const errorText = await response.text();
210
210
  this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
@@ -122,13 +122,13 @@ function yo {
122
122
  const apiUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}/function/${functionId}?${queryParams.toString()}`;
123
123
  // Fetch function from the API
124
124
  try {
125
- const response = await fetch(apiUrl, {
125
+ const response = await this.verboseFetch(apiUrl, {
126
126
  headers: {
127
127
  'accept': 'application/json',
128
128
  'Authorization': `Bearer ${profile.access_token}`,
129
129
  },
130
130
  method: 'GET',
131
- });
131
+ }, flags.verbose, profile.access_token);
132
132
  if (!response.ok) {
133
133
  const errorText = await response.text();
134
134
  this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
@@ -127,13 +127,13 @@ Available functions:
127
127
  const apiUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}/function?${queryParams.toString()}`;
128
128
  // Fetch functions from the API
129
129
  try {
130
- const response = await fetch(apiUrl, {
130
+ const response = await this.verboseFetch(apiUrl, {
131
131
  headers: {
132
132
  'accept': 'application/json',
133
133
  'Authorization': `Bearer ${profile.access_token}`,
134
134
  },
135
135
  method: 'GET',
136
- });
136
+ }, flags.verbose, profile.access_token);
137
137
  if (!response.ok) {
138
138
  const errorText = await response.text();
139
139
  this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
@@ -60,13 +60,13 @@ User Information:
60
60
  const apiUrl = `${profile.instance_origin}/api:meta/auth/me`;
61
61
  // Fetch user info from the API
62
62
  try {
63
- const response = await fetch(apiUrl, {
63
+ const response = await this.verboseFetch(apiUrl, {
64
64
  headers: {
65
65
  'accept': 'application/json',
66
66
  'Authorization': `Bearer ${profile.access_token}`,
67
67
  },
68
68
  method: 'GET',
69
- });
69
+ }, flags.verbose, profile.access_token);
70
70
  if (!response.ok) {
71
71
  const errorText = await response.text();
72
72
  this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
@@ -127,14 +127,14 @@ Description: Production build
127
127
  }
128
128
  // Create build via API
129
129
  try {
130
- const response = await fetch(apiUrl, {
130
+ const response = await this.verboseFetch(apiUrl, {
131
131
  body: formData,
132
132
  headers: {
133
133
  'accept': 'application/json',
134
134
  'Authorization': `Bearer ${profile.access_token}`,
135
135
  },
136
136
  method: 'POST',
137
- });
137
+ }, flags.verbose, profile.access_token);
138
138
  if (!response.ok) {
139
139
  const errorText = await response.text();
140
140
  this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
@@ -93,13 +93,13 @@ Name: production-build
93
93
  const apiUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}/static_host/${args.static_host}/build/${args.build_id}`;
94
94
  // Fetch build from the API
95
95
  try {
96
- const response = await fetch(apiUrl, {
96
+ const response = await this.verboseFetch(apiUrl, {
97
97
  headers: {
98
98
  'accept': 'application/json',
99
99
  'Authorization': `Bearer ${profile.access_token}`,
100
100
  },
101
101
  method: 'GET',
102
- });
102
+ }, flags.verbose, profile.access_token);
103
103
  if (!response.ok) {
104
104
  const errorText = await response.text();
105
105
  this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
@@ -110,13 +110,13 @@ Available builds:
110
110
  const apiUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}/static_host/${args.static_host}/build?${queryParams.toString()}`;
111
111
  // Fetch builds from the API
112
112
  try {
113
- const response = await fetch(apiUrl, {
113
+ const response = await this.verboseFetch(apiUrl, {
114
114
  headers: {
115
115
  'accept': 'application/json',
116
116
  'Authorization': `Bearer ${profile.access_token}`,
117
117
  },
118
118
  method: 'GET',
119
- });
119
+ }, flags.verbose, profile.access_token);
120
120
  if (!response.ok) {
121
121
  const errorText = await response.text();
122
122
  this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
@@ -105,13 +105,13 @@ Available static hosts:
105
105
  const apiUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}/static_host?${queryParams.toString()}`;
106
106
  // Fetch static hosts from the API
107
107
  try {
108
- const response = await fetch(apiUrl, {
108
+ const response = await this.verboseFetch(apiUrl, {
109
109
  headers: {
110
110
  'accept': 'application/json',
111
111
  'Authorization': `Bearer ${profile.access_token}`,
112
112
  },
113
113
  method: 'GET',
114
- });
114
+ }, flags.verbose, profile.access_token);
115
115
  if (!response.ok) {
116
116
  const errorText = await response.text();
117
117
  this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
@@ -72,15 +72,15 @@ Created workspace: my-app (ID: 456)
72
72
  }
73
73
  // Create workspace via the API
74
74
  try {
75
- const response = await fetch(apiUrl, {
75
+ const response = await this.verboseFetch(apiUrl, {
76
76
  body: JSON.stringify(body),
77
77
  headers: {
78
78
  'accept': 'application/json',
79
79
  'Authorization': `Bearer ${profile.access_token}`,
80
- 'content-type': 'application/json',
80
+ 'Content-Type': 'application/json',
81
81
  },
82
82
  method: 'POST',
83
- });
83
+ }, flags.verbose, profile.access_token);
84
84
  if (!response.ok) {
85
85
  const errorText = await response.text();
86
86
  this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
@@ -75,13 +75,13 @@ Deleted workspace 123
75
75
  const apiUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}`;
76
76
  // Delete workspace via the API
77
77
  try {
78
- const response = await fetch(apiUrl, {
78
+ const response = await this.verboseFetch(apiUrl, {
79
79
  headers: {
80
80
  'accept': 'application/json',
81
81
  'Authorization': `Bearer ${profile.access_token}`,
82
82
  },
83
83
  method: 'DELETE',
84
- });
84
+ }, flags.verbose, profile.access_token);
85
85
  if (!response.ok) {
86
86
  const errorText = await response.text();
87
87
  this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
@@ -111,15 +111,15 @@ Updated workspace: my-workspace (ID: 123)
111
111
  const apiUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}`;
112
112
  // Update workspace via the API
113
113
  try {
114
- const response = await fetch(apiUrl, {
114
+ const response = await this.verboseFetch(apiUrl, {
115
115
  body: JSON.stringify(body),
116
116
  headers: {
117
117
  'accept': 'application/json',
118
118
  'Authorization': `Bearer ${profile.access_token}`,
119
- 'content-type': 'application/json',
119
+ 'Content-Type': 'application/json',
120
120
  },
121
121
  method: 'PUT',
122
- });
122
+ }, flags.verbose, profile.access_token);
123
123
  if (!response.ok) {
124
124
  const errorText = await response.text();
125
125
  this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
@@ -71,13 +71,13 @@ Workspace: my-workspace (ID: 123)
71
71
  const apiUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}`;
72
72
  // Fetch workspace from the API
73
73
  try {
74
- const response = await fetch(apiUrl, {
74
+ const response = await this.verboseFetch(apiUrl, {
75
75
  headers: {
76
76
  'accept': 'application/json',
77
77
  'Authorization': `Bearer ${profile.access_token}`,
78
78
  },
79
79
  method: 'GET',
80
- });
80
+ }, flags.verbose, profile.access_token);
81
81
  if (!response.ok) {
82
82
  const errorText = await response.text();
83
83
  this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
@@ -76,13 +76,13 @@ Available workspaces:
76
76
  const apiUrl = `${profile.instance_origin}/api:meta/workspace`;
77
77
  // Fetch workspaces from the API
78
78
  try {
79
- const response = await fetch(apiUrl, {
79
+ const response = await this.verboseFetch(apiUrl, {
80
80
  headers: {
81
81
  'accept': 'application/json',
82
82
  'Authorization': `Bearer ${profile.access_token}`,
83
83
  },
84
84
  method: 'GET',
85
- });
85
+ }, flags.verbose, profile.access_token);
86
86
  if (!response.ok) {
87
87
  const errorText = await response.text();
88
88
  this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
@@ -9,9 +9,9 @@ export default class Pull extends BaseCommand {
9
9
  branch: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
10
  env: import("@oclif/core/interfaces").BooleanFlag<boolean>;
11
11
  records: import("@oclif/core/interfaces").BooleanFlag<boolean>;
12
- verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
13
12
  workspace: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
14
13
  profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
14
+ verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
15
15
  };
16
16
  run(): Promise<void>;
17
17
  private loadCredentials;
@@ -44,12 +44,6 @@ Pulled 42 documents to ./my-workspace
44
44
  description: 'Include records',
45
45
  required: false,
46
46
  }),
47
- verbose: Flags.boolean({
48
- char: 'v',
49
- default: false,
50
- description: 'Show request details',
51
- required: false,
52
- }),
53
47
  workspace: Flags.string({
54
48
  char: 'w',
55
49
  description: 'Workspace ID (optional if set in profile)',
@@ -104,19 +98,11 @@ Pulled 42 documents to ./my-workspace
104
98
  'accept': 'application/json',
105
99
  'Authorization': `Bearer ${profile.access_token}`,
106
100
  };
107
- if (flags.verbose) {
108
- this.log('Request details:');
109
- this.log(` Method: GET`);
110
- this.log(` URL: ${apiUrl}`);
111
- this.log(` Headers:`);
112
- this.log(` accept: application/json`);
113
- this.log(` Authorization: Bearer ${profile.access_token.slice(0, 8)}...${profile.access_token.slice(-4)}`);
114
- }
115
101
  try {
116
- const response = await fetch(apiUrl, {
102
+ const response = await this.verboseFetch(apiUrl, {
117
103
  headers: requestHeaders,
118
104
  method: 'GET',
119
- });
105
+ }, flags.verbose, profile.access_token);
120
106
  if (!response.ok) {
121
107
  const errorText = await response.text();
122
108
  this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
@@ -7,9 +7,9 @@ export default class Push extends BaseCommand {
7
7
  static examples: string[];
8
8
  static flags: {
9
9
  branch: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
- verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
11
10
  workspace: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
12
11
  profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
12
+ verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
13
13
  };
14
14
  run(): Promise<void>;
15
15
  /**
@@ -33,12 +33,6 @@ Pushed 42 documents from ./my-workspace
33
33
  description: 'Branch name (optional if set in profile, defaults to live)',
34
34
  required: false,
35
35
  }),
36
- verbose: Flags.boolean({
37
- char: 'v',
38
- default: false,
39
- description: 'Show request details',
40
- required: false,
41
- }),
42
36
  workspace: Flags.string({
43
37
  char: 'w',
44
38
  description: 'Workspace ID (optional if set in profile)',
@@ -113,22 +107,12 @@ Pushed 42 documents from ./my-workspace
113
107
  'Authorization': `Bearer ${profile.access_token}`,
114
108
  'Content-Type': 'text/x-xanoscript',
115
109
  };
116
- if (flags.verbose) {
117
- this.log('Request details:');
118
- this.log(` Method: POST`);
119
- this.log(` URL: ${apiUrl}`);
120
- this.log(` Headers:`);
121
- this.log(` accept: application/json`);
122
- this.log(` Authorization: Bearer ${profile.access_token.slice(0, 8)}...${profile.access_token.slice(-4)}`);
123
- this.log(` Content-Type: text/x-xanoscript`);
124
- this.log(` Body: ${multidoc.length} bytes (${documents.length} documents)`);
125
- }
126
110
  try {
127
- const response = await fetch(apiUrl, {
111
+ const response = await this.verboseFetch(apiUrl, {
128
112
  body: multidoc,
129
113
  headers: requestHeaders,
130
114
  method: 'POST',
131
- });
115
+ }, flags.verbose, profile.access_token);
132
116
  if (!response.ok) {
133
117
  const errorText = await response.text();
134
118
  this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);