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.
- package/.github/workflows/ci.yml +1 -1
- package/.github/workflows/publish.yml +1 -1
- package/CHANGELOG.md +14 -0
- package/README.md +2 -2
- package/bun.lock +783 -0
- package/cli.ts +14 -2
- package/dist/bundle-win-arm64.mjs +1137 -733
- package/dist/cli.cjs +1137 -733
- package/dist/index.cjs +193 -79
- package/dist/index.js +193 -79
- package/dist/lib/client.d.ts +9 -0
- package/dist/lib/client.d.ts.map +1 -1
- package/dist/lib/commands/init.d.ts.map +1 -1
- package/dist/lib/constants.d.ts +1 -1
- package/dist/lib/emulation/docker.d.ts.map +1 -1
- package/dist/lib/parser.d.ts.map +1 -1
- package/dist/lib/questions.d.ts.map +1 -1
- package/dist/lib/types.d.ts +2 -0
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/lib/utils.d.ts +12 -0
- package/dist/lib/utils.d.ts.map +1 -1
- package/install.ps1 +2 -2
- package/install.sh +1 -1
- package/lib/client.ts +12 -0
- package/lib/commands/init.ts +109 -2
- package/lib/commands/services/account.ts +110 -55
- package/lib/commands/services/activities.ts +4 -2
- package/lib/commands/services/backups.ts +24 -12
- package/lib/commands/services/databases.ts +150 -75
- package/lib/commands/services/functions.ts +60 -30
- package/lib/commands/services/graphql.ts +4 -2
- package/lib/commands/services/health.ts +46 -23
- package/lib/commands/services/locale.ts +16 -8
- package/lib/commands/services/messaging.ts +96 -48
- package/lib/commands/services/migrations.ts +28 -14
- package/lib/commands/services/organizations.ts +76 -38
- package/lib/commands/services/project.ts +12 -6
- package/lib/commands/services/projects.ts +103 -51
- package/lib/commands/services/proxy.ts +16 -8
- package/lib/commands/services/sites.ts +58 -29
- package/lib/commands/services/storage.ts +30 -15
- package/lib/commands/services/tables-db.ts +148 -74
- package/lib/commands/services/teams.ts +28 -14
- package/lib/commands/services/tokens.ts +10 -5
- package/lib/commands/services/users.ts +88 -44
- package/lib/commands/services/vcs.ts +20 -10
- package/lib/commands/services/webhooks.ts +12 -6
- package/lib/constants.ts +1 -1
- package/lib/emulation/docker.ts +1 -0
- package/lib/parser.ts +279 -122
- package/lib/questions.ts +8 -3
- package/lib/sdks.ts +0 -1
- package/lib/types.ts +2 -0
- package/lib/utils.ts +234 -0
- package/package.json +1 -1
- 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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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';
|
package/lib/emulation/docker.ts
CHANGED
|
@@ -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 () {
|
|
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
|
-
|
|
108
|
-
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
235
|
+
withRender(() => {
|
|
236
|
+
const sanitizedData = maskSensitiveData(data) as JsonObject;
|
|
111
237
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
238
|
+
if (cliConfig.raw) {
|
|
239
|
+
drawJSON(sanitizedData);
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
116
242
|
|
|
117
|
-
|
|
118
|
-
|
|
243
|
+
if (cliConfig.json) {
|
|
244
|
+
drawJSON(filterData(sanitizedData));
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
119
247
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
if (typeof value
|
|
129
|
-
|
|
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
|
-
|
|
175
|
-
|
|
176
|
-
|
|
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
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
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
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
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
|
-
|
|
205
|
-
|
|
206
|
-
|
|
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
|
-
|
|
212
|
-
|
|
213
|
-
|
|
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
|
|
218
|
-
|
|
219
|
-
|
|
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
|
-
|
|
222
|
-
|
|
223
|
-
for (const
|
|
224
|
-
|
|
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
|
-
|
|
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,
|
|
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.`,
|