appwrite-cli 17.1.0 → 17.2.1

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 (56) hide show
  1. package/.github/workflows/ci.yml +1 -1
  2. package/.github/workflows/publish.yml +1 -1
  3. package/CHANGELOG.md +14 -0
  4. package/README.md +2 -2
  5. package/bun.lock +783 -0
  6. package/cli.ts +14 -2
  7. package/dist/bundle-win-arm64.mjs +1137 -733
  8. package/dist/cli.cjs +1137 -733
  9. package/dist/index.cjs +193 -79
  10. package/dist/index.js +193 -79
  11. package/dist/lib/client.d.ts +9 -0
  12. package/dist/lib/client.d.ts.map +1 -1
  13. package/dist/lib/commands/init.d.ts.map +1 -1
  14. package/dist/lib/constants.d.ts +1 -1
  15. package/dist/lib/emulation/docker.d.ts.map +1 -1
  16. package/dist/lib/parser.d.ts.map +1 -1
  17. package/dist/lib/questions.d.ts.map +1 -1
  18. package/dist/lib/types.d.ts +2 -0
  19. package/dist/lib/types.d.ts.map +1 -1
  20. package/dist/lib/utils.d.ts +12 -0
  21. package/dist/lib/utils.d.ts.map +1 -1
  22. package/install.ps1 +2 -2
  23. package/install.sh +1 -1
  24. package/lib/client.ts +12 -0
  25. package/lib/commands/init.ts +109 -2
  26. package/lib/commands/services/account.ts +110 -55
  27. package/lib/commands/services/activities.ts +4 -2
  28. package/lib/commands/services/backups.ts +24 -12
  29. package/lib/commands/services/databases.ts +150 -75
  30. package/lib/commands/services/functions.ts +60 -30
  31. package/lib/commands/services/graphql.ts +4 -2
  32. package/lib/commands/services/health.ts +46 -23
  33. package/lib/commands/services/locale.ts +16 -8
  34. package/lib/commands/services/messaging.ts +96 -48
  35. package/lib/commands/services/migrations.ts +28 -14
  36. package/lib/commands/services/organizations.ts +76 -38
  37. package/lib/commands/services/project.ts +12 -6
  38. package/lib/commands/services/projects.ts +103 -51
  39. package/lib/commands/services/proxy.ts +16 -8
  40. package/lib/commands/services/sites.ts +58 -29
  41. package/lib/commands/services/storage.ts +30 -15
  42. package/lib/commands/services/tables-db.ts +148 -74
  43. package/lib/commands/services/teams.ts +28 -14
  44. package/lib/commands/services/tokens.ts +10 -5
  45. package/lib/commands/services/users.ts +88 -44
  46. package/lib/commands/services/vcs.ts +20 -10
  47. package/lib/commands/services/webhooks.ts +12 -6
  48. package/lib/constants.ts +1 -1
  49. package/lib/emulation/docker.ts +1 -0
  50. package/lib/parser.ts +279 -122
  51. package/lib/questions.ts +8 -3
  52. package/lib/sdks.ts +0 -1
  53. package/lib/types.ts +2 -0
  54. package/lib/utils.ts +234 -0
  55. package/package.json +1 -1
  56. package/scoop/appwrite.config.json +3 -3
@@ -26,7 +26,7 @@ export const vcs = new Command("vcs")
26
26
  helpWidth: process.stdout.columns || 80,
27
27
  });
28
28
 
29
- vcs
29
+ const vcsCreateRepositoryDetectionCommand = vcs
30
30
  .command(`create-repository-detection`)
31
31
  .description(`Analyze a GitHub repository to automatically detect the programming language and runtime environment. This endpoint scans the repository's files and language statistics to determine the appropriate runtime settings for your function. The GitHub installation must be properly configured and the repository must be accessible through your installation for this endpoint to work.`)
32
32
  .requiredOption(`--installation-id <installation-id>`, `Installation Id`)
@@ -40,7 +40,8 @@ vcs
40
40
  ),
41
41
  );
42
42
 
43
- vcs
43
+
44
+ const vcsListRepositoriesCommand = vcs
44
45
  .command(`list-repositories`)
45
46
  .description(`Get a list of GitHub repositories available through your installation. This endpoint returns repositories with their basic information, detected runtime environments, and latest push dates. You can optionally filter repositories using a search term. Each repository's runtime is automatically detected based on its contents and language statistics. The GitHub installation must be properly configured for this endpoint to work.`)
46
47
  .requiredOption(`--installation-id <installation-id>`, `Installation Id`)
@@ -54,7 +55,8 @@ vcs
54
55
  ),
55
56
  );
56
57
 
57
- vcs
58
+
59
+ const vcsCreateRepositoryCommand = vcs
58
60
  .command(`create-repository`)
59
61
  .description(`Create a new GitHub repository through your installation. This endpoint allows you to create either a public or private repository by specifying a name and visibility setting. The repository will be created under your GitHub user account or organization, depending on your installation type. The GitHub installation must be properly configured and have the necessary permissions for repository creation.`)
60
62
  .requiredOption(`--installation-id <installation-id>`, `Installation Id`)
@@ -67,7 +69,8 @@ vcs
67
69
  ),
68
70
  );
69
71
 
70
- vcs
72
+
73
+ const vcsGetRepositoryCommand = vcs
71
74
  .command(`get-repository`)
72
75
  .description(`Get detailed information about a specific GitHub repository from your installation. This endpoint returns repository details including its ID, name, visibility status, organization, and latest push date. The GitHub installation must be properly configured and have access to the requested repository for this endpoint to work.`)
73
76
  .requiredOption(`--installation-id <installation-id>`, `Installation Id`)
@@ -79,7 +82,8 @@ vcs
79
82
  ),
80
83
  );
81
84
 
82
- vcs
85
+
86
+ const vcsListRepositoryBranchesCommand = vcs
83
87
  .command(`list-repository-branches`)
84
88
  .description(`Get a list of all branches from a GitHub repository in your installation. This endpoint returns the names of all branches in the repository and their total count. The GitHub installation must be properly configured and have access to the requested repository for this endpoint to work.
85
89
  `)
@@ -92,7 +96,8 @@ vcs
92
96
  ),
93
97
  );
94
98
 
95
- vcs
99
+
100
+ const vcsGetRepositoryContentsCommand = vcs
96
101
  .command(`get-repository-contents`)
97
102
  .description(`Get a list of files and directories from a GitHub repository connected to your project. This endpoint returns the contents of a specified repository path, including file names, sizes, and whether each item is a file or directory. The GitHub installation must be properly configured and the repository must be accessible through your installation for this endpoint to work.`)
98
103
  .requiredOption(`--installation-id <installation-id>`, `Installation Id`)
@@ -106,7 +111,8 @@ vcs
106
111
  ),
107
112
  );
108
113
 
109
- vcs
114
+
115
+ const vcsUpdateExternalDeploymentsCommand = vcs
110
116
  .command(`update-external-deployments`)
111
117
  .description(`Authorize and create deployments for a GitHub pull request in your project. This endpoint allows external contributions by creating deployments from pull requests, enabling preview environments for code review. The pull request must be open and not previously authorized. The GitHub installation must be properly configured and have access to both the repository and pull request for this endpoint to work.`)
112
118
  .requiredOption(`--installation-id <installation-id>`, `Installation Id`)
@@ -119,7 +125,8 @@ vcs
119
125
  ),
120
126
  );
121
127
 
122
- vcs
128
+
129
+ const vcsListInstallationsCommand = vcs
123
130
  .command(`list-installations`)
124
131
  .description(`List all VCS installations configured for the current project. This endpoint returns a list of installations including their provider, organization, and other configuration details.
125
132
  `)
@@ -138,7 +145,8 @@ vcs
138
145
  ),
139
146
  );
140
147
 
141
- vcs
148
+
149
+ const vcsGetInstallationCommand = vcs
142
150
  .command(`get-installation`)
143
151
  .description(`Get a VCS installation by its unique ID. This endpoint returns the installation's details including its provider, organization, and configuration. `)
144
152
  .requiredOption(`--installation-id <installation-id>`, `Installation Id`)
@@ -149,7 +157,8 @@ vcs
149
157
  ),
150
158
  );
151
159
 
152
- vcs
160
+
161
+ const vcsDeleteInstallationCommand = vcs
153
162
  .command(`delete-installation`)
154
163
  .description(`Delete a VCS installation by its unique ID. This endpoint removes the installation and all its associated repositories from the project.`)
155
164
  .requiredOption(`--installation-id <installation-id>`, `Installation Id`)
@@ -160,3 +169,4 @@ vcs
160
169
  ),
161
170
  );
162
171
 
172
+
@@ -26,7 +26,7 @@ export const webhooks = new Command("webhooks")
26
26
  helpWidth: process.stdout.columns || 80,
27
27
  });
28
28
 
29
- webhooks
29
+ const webhooksListCommand = webhooks
30
30
  .command(`list`)
31
31
  .description(`Get a list of all webhooks belonging to the project. You can use the query params to filter your results.`)
32
32
  .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, url, httpUser, security, events, enabled, logs, attempts`)
@@ -43,7 +43,8 @@ webhooks
43
43
  ),
44
44
  );
45
45
 
46
- webhooks
46
+
47
+ const webhooksCreateCommand = webhooks
47
48
  .command(`create`)
48
49
  .description(`Create a new webhook. Use this endpoint to configure a URL that will receive events from Appwrite when specific events occur.`)
49
50
  .requiredOption(`--webhook-id <webhook-id>`, `Webhook ID. Choose a custom ID or generate a random ID with \`ID.unique()\`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`)
@@ -71,7 +72,8 @@ webhooks
71
72
  ),
72
73
  );
73
74
 
74
- webhooks
75
+
76
+ const webhooksGetCommand = webhooks
75
77
  .command(`get`)
76
78
  .description(`Get a webhook by its unique ID. This endpoint returns details about a specific webhook configured for a project. `)
77
79
  .requiredOption(`--webhook-id <webhook-id>`, `Webhook ID.`)
@@ -82,7 +84,8 @@ webhooks
82
84
  ),
83
85
  );
84
86
 
85
- webhooks
87
+
88
+ const webhooksUpdateCommand = webhooks
86
89
  .command(`update`)
87
90
  .description(`Update a webhook by its unique ID. Use this endpoint to update the URL, events, or status of an existing webhook.`)
88
91
  .requiredOption(`--webhook-id <webhook-id>`, `Webhook ID.`)
@@ -110,7 +113,8 @@ webhooks
110
113
  ),
111
114
  );
112
115
 
113
- webhooks
116
+
117
+ const webhooksDeleteCommand = webhooks
114
118
  .command(`delete`)
115
119
  .description(`Delete a webhook by its unique ID. Once deleted, the webhook will no longer receive project events. `)
116
120
  .requiredOption(`--webhook-id <webhook-id>`, `Webhook ID.`)
@@ -121,7 +125,8 @@ webhooks
121
125
  ),
122
126
  );
123
127
 
124
- webhooks
128
+
129
+ const webhooksUpdateSignatureCommand = webhooks
125
130
  .command(`update-signature`)
126
131
  .description(`Update the webhook signature key. This endpoint can be used to regenerate the signature key used to sign and validate payload deliveries for a specific webhook.`)
127
132
  .requiredOption(`--webhook-id <webhook-id>`, `Webhook ID.`)
@@ -132,3 +137,4 @@ webhooks
132
137
  ),
133
138
  );
134
139
 
140
+
package/lib/constants.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  // SDK
2
2
  export const SDK_TITLE = 'Appwrite';
3
3
  export const SDK_TITLE_LOWER = 'appwrite';
4
- export const SDK_VERSION = '17.1.0';
4
+ export const SDK_VERSION = '17.2.1';
5
5
  export const SDK_NAME = 'Command Line';
6
6
  export const SDK_PLATFORM = 'console';
7
7
  export const SDK_LANGUAGE = 'cli';
@@ -219,6 +219,7 @@ export async function dockerStart(
219
219
  params.push("-p", `${port}:3000`);
220
220
  params.push("-e", "OPEN_RUNTIMES_ENV=development");
221
221
  params.push("-e", "OPEN_RUNTIMES_SECRET=");
222
+ params.push("-e", `OPEN_RUNTIMES_ENTRYPOINT=${func.entrypoint}`);
222
223
 
223
224
  for (const k of Object.keys(variables)) {
224
225
  params.push("-e", `${k}=${variables[k]}`);
package/lib/parser.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  // @ts-expect-error BigInt toJSON polyfill for JSON.stringify support
2
- BigInt.prototype.toJSON = function () { return this.toString(); };
2
+ BigInt.prototype.toJSON = function () {
3
+ return this.toString();
4
+ };
3
5
 
4
6
  import chalk from "chalk";
5
7
  import { InvalidArgumentError } from "commander";
@@ -22,15 +24,32 @@ const cliConfig: CliConfig = {
22
24
  verbose: false,
23
25
  json: false,
24
26
  raw: false,
27
+ showSecrets: false,
25
28
  force: false,
26
29
  all: false,
27
30
  ids: [],
28
31
  report: false,
29
32
  reportData: {},
33
+ displayFields: [],
30
34
  };
31
35
 
32
36
  type JsonObject = Record<string, unknown>;
33
37
 
38
+ const HIDDEN_VALUE = "[hidden]";
39
+ const SENSITIVE_KEYS = new Set([
40
+ "secret",
41
+ "apikey",
42
+ "accesstoken",
43
+ "refreshtoken",
44
+ "password",
45
+ "jwt",
46
+ "clientsecret",
47
+ "secretkey",
48
+ "sessionsecret",
49
+ ]);
50
+ let renderDepth = 0;
51
+ let redactionApplied = false;
52
+
34
53
  interface ReportDataPayload {
35
54
  data?: {
36
55
  args?: string[];
@@ -58,6 +77,97 @@ const extractReportCommandArgs = (value: unknown): string[] => {
58
77
  return reportData.data.args;
59
78
  };
60
79
 
80
+ const beginRender = (): void => {
81
+ if (renderDepth === 0) {
82
+ redactionApplied = false;
83
+ }
84
+
85
+ renderDepth++;
86
+ };
87
+
88
+ const endRender = (): void => {
89
+ renderDepth = Math.max(0, renderDepth - 1);
90
+
91
+ if (renderDepth === 0 && redactionApplied && !cliConfig.showSecrets) {
92
+ const message =
93
+ "Sensitive values were redacted. Pass --show-secrets to display them.";
94
+
95
+ if (cliConfig.json || cliConfig.raw) {
96
+ console.error(`${chalk.cyan.bold("♥ Hint:")} ${chalk.cyan(message)}`);
97
+ } else {
98
+ hint(message);
99
+ }
100
+ }
101
+ };
102
+
103
+ const withRender = <T>(callback: () => T): T => {
104
+ beginRender();
105
+
106
+ try {
107
+ return callback();
108
+ } finally {
109
+ endRender();
110
+ }
111
+ };
112
+
113
+ const isSensitiveKey = (key: string): boolean => {
114
+ const normalizedKey = key.toLowerCase().replace(/[^a-z0-9]/g, "");
115
+
116
+ return SENSITIVE_KEYS.has(normalizedKey);
117
+ };
118
+
119
+ const maskSensitiveString = (value: string): string => {
120
+ if (value.length <= 16) {
121
+ return HIDDEN_VALUE;
122
+ }
123
+
124
+ const separatorIndex = value.indexOf("_");
125
+ if (separatorIndex > 0 && separatorIndex < value.length - 9) {
126
+ const prefix = value.slice(0, separatorIndex + 1);
127
+ const tail = value.slice(-4);
128
+ return `${prefix}${HIDDEN_VALUE}${tail}`;
129
+ }
130
+
131
+ return `${HIDDEN_VALUE}${value.slice(-4)}`;
132
+ };
133
+
134
+ const maskSensitiveData = (value: unknown, key?: string): unknown => {
135
+ if (key && isSensitiveKey(key) && !cliConfig.showSecrets) {
136
+ redactionApplied = true;
137
+
138
+ if (typeof value === "string") {
139
+ return maskSensitiveString(value);
140
+ }
141
+
142
+ if (value == null) {
143
+ return value;
144
+ }
145
+
146
+ return HIDDEN_VALUE;
147
+ }
148
+
149
+ if (Array.isArray(value)) {
150
+ return value.map((item) => maskSensitiveData(item));
151
+ }
152
+
153
+ if (value && typeof value === "object") {
154
+ if (value?.constructor?.name === "BigNumber") {
155
+ return String(value);
156
+ }
157
+
158
+ const result: JsonObject = {};
159
+ for (const childKey of Object.keys(value as JsonObject)) {
160
+ const childValue = (value as JsonObject)[childKey];
161
+ if (typeof childValue === "function") continue;
162
+ result[childKey] = maskSensitiveData(childValue, childKey);
163
+ }
164
+
165
+ return result;
166
+ }
167
+
168
+ return value;
169
+ };
170
+
61
171
  const filterObject = (obj: JsonObject): JsonObject => {
62
172
  const result: JsonObject = {};
63
173
  for (const key of Object.keys(obj)) {
@@ -75,6 +185,24 @@ const filterObject = (obj: JsonObject): JsonObject => {
75
185
  return result;
76
186
  };
77
187
 
188
+ const applyDisplayFilter = (rows: JsonObject[]): JsonObject[] => {
189
+ if (cliConfig.displayFields.length === 0) {
190
+ return rows;
191
+ }
192
+
193
+ return rows.map((row) => {
194
+ const filtered: JsonObject = {};
195
+
196
+ for (const key of cliConfig.displayFields) {
197
+ if (Object.prototype.hasOwnProperty.call(row, key)) {
198
+ filtered[key] = row[key];
199
+ }
200
+ }
201
+
202
+ return Object.keys(filtered).length > 0 ? filtered : row;
203
+ });
204
+ };
205
+
78
206
  const filterData = (data: JsonObject): JsonObject => {
79
207
  const result: JsonObject = {};
80
208
  for (const key of Object.keys(data)) {
@@ -104,49 +232,68 @@ const filterData = (data: JsonObject): JsonObject => {
104
232
  };
105
233
 
106
234
  export const parse = (data: JsonObject): void => {
107
- if (cliConfig.raw) {
108
- drawJSON(data);
109
- return;
110
- }
235
+ withRender(() => {
236
+ const sanitizedData = maskSensitiveData(data) as JsonObject;
111
237
 
112
- if (cliConfig.json) {
113
- drawJSON(filterData(data));
114
- return;
115
- }
238
+ if (cliConfig.raw) {
239
+ drawJSON(sanitizedData);
240
+ return;
241
+ }
116
242
 
117
- const keys = Object.keys(data).filter((k) => typeof data[k] !== "function");
118
- let printedScalar = false;
243
+ if (cliConfig.json) {
244
+ drawJSON(filterData(sanitizedData));
245
+ return;
246
+ }
119
247
 
120
- for (const key of keys) {
121
- const value = data[key];
122
- if (value === null) {
123
- console.log(`${chalk.yellow.bold(key)} : null`);
124
- printedScalar = true;
125
- } else if (Array.isArray(value)) {
126
- if (printedScalar) console.log("");
127
- console.log(`${chalk.yellow.bold.underline(key)}`);
128
- if (typeof value[0] === "object") {
129
- drawTable(value);
248
+ const keys = Object.keys(sanitizedData).filter(
249
+ (k) => typeof sanitizedData[k] !== "function",
250
+ );
251
+ let printedScalar = false;
252
+
253
+ for (const key of keys) {
254
+ const value = sanitizedData[key];
255
+ if (value == null) continue;
256
+ if (typeof value === "string" && value.trim() === "") continue;
257
+ if (Array.isArray(value)) {
258
+ if (value.length === 0) continue;
259
+ if (
260
+ value.every(
261
+ (item) =>
262
+ item &&
263
+ typeof item === "object" &&
264
+ !Array.isArray(item) &&
265
+ Object.keys(item).length === 0,
266
+ )
267
+ )
268
+ continue;
269
+ console.log();
270
+ console.log(`${chalk.yellow.bold.underline(key)}`);
271
+ if (typeof value[0] === "object") {
272
+ drawTable(value);
273
+ } else {
274
+ drawJSON(value);
275
+ }
276
+ console.log();
277
+ printedScalar = false;
278
+ } else if (typeof value === "object") {
279
+ if (value?.constructor?.name === "BigNumber") {
280
+ console.log(`${chalk.yellow.bold(key)} : ${value}`);
281
+ printedScalar = true;
282
+ } else {
283
+ const tableRow = toJsonObject(value) ?? {};
284
+ if (Object.keys(tableRow).length === 0) continue;
285
+ console.log();
286
+ console.log(`${chalk.yellow.bold.underline(key)}`);
287
+ drawTable([tableRow]);
288
+ console.log();
289
+ printedScalar = false;
290
+ }
130
291
  } else {
131
- drawJSON(value);
132
- }
133
- printedScalar = false;
134
- } else if (typeof value === "object") {
135
- if (printedScalar) console.log("");
136
- if (value?.constructor?.name === "BigNumber") {
137
292
  console.log(`${chalk.yellow.bold(key)} : ${value}`);
138
293
  printedScalar = true;
139
- } else {
140
- console.log(`${chalk.yellow.bold.underline(key)}`);
141
- const tableRow = toJsonObject(value) ?? {};
142
- drawTable([tableRow]);
143
- printedScalar = false;
144
294
  }
145
- } else {
146
- console.log(`${chalk.yellow.bold(key)} : ${value}`);
147
- printedScalar = true;
148
295
  }
149
- }
296
+ });
150
297
  };
151
298
 
152
299
  const MAX_COL_WIDTH = 40;
@@ -171,104 +318,114 @@ const formatCellValue = (value: unknown): string => {
171
318
  };
172
319
 
173
320
  export const drawTable = (data: Array<JsonObject | null | undefined>): void => {
174
- if (data.length == 0) {
175
- console.log("[]");
176
- return;
177
- }
178
-
179
- const rows = data.map((item): JsonObject => toJsonObject(item) ?? {});
321
+ withRender(() => {
322
+ if (data.length == 0) {
323
+ console.log("[]");
324
+ return;
325
+ }
180
326
 
181
- // Create an object with all the keys in it
182
- const obj = rows.reduce((res, item) => ({ ...res, ...item }), {});
183
- // Get those keys as an array
184
- const allKeys = Object.keys(obj);
185
- if (allKeys.length === 0) {
186
- drawJSON(data);
187
- return;
188
- }
327
+ const rows = applyDisplayFilter(
328
+ data.map((item): JsonObject => {
329
+ const maskedItem = maskSensitiveData(item);
330
+ return toJsonObject(maskedItem) ?? {};
331
+ }),
332
+ );
333
+
334
+ // Create an object with all the keys in it
335
+ const obj = rows.reduce((res, item) => ({ ...res, ...item }), {});
336
+ // Get those keys as an array
337
+ const allKeys = Object.keys(obj);
338
+ if (allKeys.length === 0) {
339
+ drawJSON(data);
340
+ return;
341
+ }
189
342
 
190
- // If too many columns, show condensed key-value output with only scalar, non-empty fields
191
- const maxColumns = 6;
192
- if (allKeys.length > maxColumns) {
193
- // Collect visible entries per row to compute alignment
194
- const rowEntries = rows.map((row) => {
195
- const entries: Array<[string, string]> = [];
196
- for (const key of Object.keys(row)) {
197
- const value = row[key];
198
- if (typeof value === "function") continue;
199
- if (value == null) continue;
200
- if (value?.constructor?.name === "BigNumber") {
343
+ // If too many columns, show condensed key-value output with only scalar, non-empty fields
344
+ const maxColumns = 6;
345
+ if (allKeys.length > maxColumns) {
346
+ // Collect visible entries per row to compute alignment
347
+ const rowEntries = rows.map((row) => {
348
+ const entries: Array<[string, string]> = [];
349
+ for (const key of Object.keys(row)) {
350
+ const value = row[key];
351
+ if (typeof value === "function") continue;
352
+ if (value == null) continue;
353
+ if (value?.constructor?.name === "BigNumber") {
354
+ entries.push([key, String(value)]);
355
+ continue;
356
+ }
357
+ if (typeof value === "object") continue;
358
+ if (typeof value === "string" && value.trim() === "") continue;
201
359
  entries.push([key, String(value)]);
202
- continue;
203
360
  }
204
- if (typeof value === "object") continue;
205
- if (typeof value === "string" && value.trim() === "") continue;
206
- entries.push([key, String(value)]);
361
+ return entries;
362
+ });
363
+
364
+ const flatEntries = rowEntries.flat();
365
+ if (flatEntries.length === 0) {
366
+ drawJSON(data);
367
+ return;
207
368
  }
208
- return entries;
209
- });
210
369
 
211
- const flatEntries = rowEntries.flat();
212
- if (flatEntries.length === 0) {
213
- drawJSON(data);
370
+ const maxKeyLen = Math.max(...flatEntries.map(([key]) => key.length));
371
+
372
+ const separatorLen = Math.min(
373
+ maxKeyLen + 2 + MAX_COL_WIDTH,
374
+ process.stdout.columns || 80,
375
+ );
376
+
377
+ rowEntries.forEach((entries, idx) => {
378
+ if (idx > 0) console.log(chalk.cyan("─".repeat(separatorLen)));
379
+ for (const [key, value] of entries) {
380
+ const paddedKey = key.padEnd(maxKeyLen);
381
+ console.log(`${chalk.yellow.bold(paddedKey)} ${value}`);
382
+ }
383
+ });
214
384
  return;
215
385
  }
216
386
 
217
- const maxKeyLen = Math.max(...flatEntries.map(([key]) => key.length));
218
-
219
- const separatorLen = Math.min(maxKeyLen + 2 + MAX_COL_WIDTH, process.stdout.columns || 80);
387
+ const columns = allKeys;
388
+
389
+ // Create an object with all keys set to the default value ''
390
+ const def = allKeys.reduce((result: Record<string, string>, key) => {
391
+ result[key] = "-";
392
+ return result;
393
+ }, {});
394
+ // Use object destructuring to replace all default values with the ones we have
395
+ const normalizedData = rows.map((item) => ({ ...def, ...item }));
396
+
397
+ const table = new Table({
398
+ head: columns.map((c) => chalk.cyan.italic.bold(c)),
399
+ colWidths: columns.map(() => null) as (number | null)[],
400
+ wordWrap: false,
401
+ chars: {
402
+ "top": " ",
403
+ "top-mid": " ",
404
+ "top-left": " ",
405
+ "top-right": " ",
406
+ "bottom": " ",
407
+ "bottom-mid": " ",
408
+ "bottom-left": " ",
409
+ "bottom-right": " ",
410
+ "left": " ",
411
+ "left-mid": " ",
412
+ "mid": chalk.cyan("─"),
413
+ "mid-mid": chalk.cyan("┼"),
414
+ "right": " ",
415
+ "right-mid": " ",
416
+ "middle": chalk.cyan("│"),
417
+ },
418
+ });
220
419
 
221
- rowEntries.forEach((entries, idx) => {
222
- if (idx > 0) console.log(chalk.cyan("─".repeat(separatorLen)));
223
- for (const [key, value] of entries) {
224
- const paddedKey = key.padEnd(maxKeyLen);
225
- console.log(`${chalk.yellow.bold(paddedKey)} ${value}`);
420
+ normalizedData.forEach((row) => {
421
+ const rowValues: string[] = [];
422
+ for (const key of columns) {
423
+ rowValues.push(formatCellValue(row[key]));
226
424
  }
425
+ table.push(rowValues);
227
426
  });
228
- return;
229
- }
230
-
231
- const columns = allKeys;
232
-
233
- // Create an object with all keys set to the default value ''
234
- const def = allKeys.reduce((result: Record<string, string>, key) => {
235
- result[key] = "-";
236
- return result;
237
- }, {});
238
- // Use object destructuring to replace all default values with the ones we have
239
- const normalizedData = rows.map((item) => ({ ...def, ...item }));
240
-
241
- const table = new Table({
242
- head: columns.map((c) => chalk.cyan.italic.bold(c)),
243
- colWidths: columns.map(() => null) as (number | null)[],
244
- wordWrap: false,
245
- chars: {
246
- top: " ",
247
- "top-mid": " ",
248
- "top-left": " ",
249
- "top-right": " ",
250
- bottom: " ",
251
- "bottom-mid": " ",
252
- "bottom-left": " ",
253
- "bottom-right": " ",
254
- left: " ",
255
- "left-mid": " ",
256
- mid: chalk.cyan("─"),
257
- "mid-mid": chalk.cyan("┼"),
258
- right: " ",
259
- "right-mid": " ",
260
- middle: chalk.cyan("│"),
261
- },
262
- });
263
-
264
- normalizedData.forEach((row) => {
265
- const rowValues: string[] = [];
266
- for (const key of columns) {
267
- rowValues.push(formatCellValue(row[key]));
268
- }
269
- table.push(rowValues);
427
+ console.log(table.toString());
270
428
  });
271
- console.log(table.toString());
272
429
  };
273
430
 
274
431
  export const drawJSON = (data: unknown): void => {
@@ -403,7 +560,7 @@ export const commandDescriptions: Record<string, string> = {
403
560
  avatars: `The avatars command aims to help you complete everyday tasks related to your app image, icons, and avatars.`,
404
561
  databases: `(Legacy) The databases command allows you to create structured collections of documents and query and filter lists of documents.`,
405
562
  "tables-db": `The tables-db command allows you to create structured tables of columns and query and filter lists of rows.`,
406
- init: `The init command provides a convenient wrapper for creating and initializing projects, functions, collections, buckets, teams, and messaging-topics in ${SDK_TITLE}.`,
563
+ init: `The init command provides a convenient wrapper for creating and initializing projects, functions, collections, buckets, teams, messaging-topics, and agent skills in ${SDK_TITLE}.`,
407
564
  push: `The push command provides a convenient wrapper for pushing your functions, collections, buckets, teams, and messaging-topics.`,
408
565
  run: `The run command allows you to run the project locally to allow easy development and quick debugging.`,
409
566
  functions: `The functions command allows you to view, create, and manage your Cloud Functions.`,