@zapier/zapier-sdk-cli 0.4.4 ā 0.6.0
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/CHANGELOG.md +30 -0
- package/README.md +92 -72
- package/dist/cli.js +212 -67
- package/dist/src/cli.js +1 -1
- package/dist/src/commands/bundle-code/cli.js +1 -1
- package/dist/src/commands/generate-types/cli.js +17 -6
- package/dist/src/commands/generate-types/index.js +26 -5
- package/dist/src/commands/generate-types/schemas.d.ts +3 -0
- package/dist/src/commands/generate-types/schemas.js +4 -0
- package/dist/src/utils/api/client.d.ts +3 -3
- package/dist/src/utils/cli-generator-utils.d.ts +2 -2
- package/dist/src/utils/cli-generator.js +84 -23
- package/dist/src/utils/log.d.ts +4 -4
- package/dist/src/utils/parameter-resolver.d.ts +1 -1
- package/dist/src/utils/parameter-resolver.js +45 -30
- package/dist/src/utils/schema-formatter.d.ts +1 -1
- package/dist/src/utils/schema-formatter.js +6 -4
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
- package/src/cli.test.ts +1 -2
- package/src/cli.ts +1 -1
- package/src/commands/bundle-code/cli.ts +19 -4
- package/src/commands/generate-types/cli.ts +25 -9
- package/src/commands/generate-types/index.ts +32 -6
- package/src/commands/generate-types/schemas.ts +4 -0
- package/src/utils/api/client.ts +3 -3
- package/src/utils/auth/login.ts +2 -1
- package/src/utils/cli-generator-utils.ts +7 -7
- package/src/utils/cli-generator.ts +154 -48
- package/src/utils/log.ts +4 -4
- package/src/utils/parameter-resolver.ts +106 -55
- package/src/utils/schema-formatter.ts +20 -11
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zapier/zapier-sdk-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Command line interface for Zapier SDK",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -31,9 +31,9 @@
|
|
|
31
31
|
"ora": "^8.2.0",
|
|
32
32
|
"pkce-challenge": "^5.0.0",
|
|
33
33
|
"zod": "^3.25.67",
|
|
34
|
-
"@zapier/zapier-sdk": "0.
|
|
35
|
-
"@zapier/zapier-sdk-
|
|
36
|
-
"@zapier/zapier-sdk-
|
|
34
|
+
"@zapier/zapier-sdk": "0.6.0",
|
|
35
|
+
"@zapier/zapier-sdk-cli-login": "0.3.2",
|
|
36
|
+
"@zapier/zapier-sdk-mcp": "0.2.0"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@types/express": "^5.0.3",
|
package/src/cli.test.ts
CHANGED
package/src/cli.ts
CHANGED
|
@@ -46,7 +46,11 @@ export function createBundleCodeCommand(): Command {
|
|
|
46
46
|
command.option(flags.join(", "), param.description);
|
|
47
47
|
} else {
|
|
48
48
|
const flagSignature = flags.join(", ") + ` <${param.type}>`;
|
|
49
|
-
command.option(
|
|
49
|
+
command.option(
|
|
50
|
+
flagSignature,
|
|
51
|
+
param.description || "",
|
|
52
|
+
param.default as string | boolean | string[] | undefined,
|
|
53
|
+
);
|
|
50
54
|
}
|
|
51
55
|
}
|
|
52
56
|
});
|
|
@@ -54,10 +58,12 @@ export function createBundleCodeCommand(): Command {
|
|
|
54
58
|
// Add formatting options like other commands
|
|
55
59
|
command.option("--json", "Output raw JSON instead of formatted results");
|
|
56
60
|
|
|
57
|
-
command.action(async (...args:
|
|
61
|
+
command.action(async (...args: unknown[]) => {
|
|
58
62
|
try {
|
|
59
63
|
// The last argument is always the command object with parsed options
|
|
60
|
-
const commandObj = args[args.length - 1]
|
|
64
|
+
const commandObj = args[args.length - 1] as {
|
|
65
|
+
opts(): Record<string, unknown>;
|
|
66
|
+
};
|
|
61
67
|
const options = commandObj.opts();
|
|
62
68
|
|
|
63
69
|
// Convert CLI args to SDK method parameters
|
|
@@ -76,7 +82,16 @@ export function createBundleCodeCommand(): Command {
|
|
|
76
82
|
console.log(chalk.blue(`š¦ Bundling ${rawParams.input}...`));
|
|
77
83
|
|
|
78
84
|
// Call our implementation
|
|
79
|
-
const result = await bundleCode(
|
|
85
|
+
const result = await bundleCode(
|
|
86
|
+
rawParams as {
|
|
87
|
+
string: boolean;
|
|
88
|
+
input: string;
|
|
89
|
+
minify: boolean;
|
|
90
|
+
target: string;
|
|
91
|
+
cjs: boolean;
|
|
92
|
+
output?: string | undefined;
|
|
93
|
+
},
|
|
94
|
+
);
|
|
80
95
|
|
|
81
96
|
if (options.json) {
|
|
82
97
|
console.log(JSON.stringify({ result }, null, 2));
|
|
@@ -48,7 +48,11 @@ export function createGenerateTypesCommand(): Command {
|
|
|
48
48
|
command.option(flags.join(", "), param.description);
|
|
49
49
|
} else {
|
|
50
50
|
const flagSignature = flags.join(", ") + ` <${param.type}>`;
|
|
51
|
-
command.option(
|
|
51
|
+
command.option(
|
|
52
|
+
flagSignature,
|
|
53
|
+
param.description || "",
|
|
54
|
+
param.default as string | boolean | string[] | undefined,
|
|
55
|
+
);
|
|
52
56
|
}
|
|
53
57
|
}
|
|
54
58
|
});
|
|
@@ -56,10 +60,12 @@ export function createGenerateTypesCommand(): Command {
|
|
|
56
60
|
// Add formatting options like other commands
|
|
57
61
|
command.option("--json", "Output raw JSON instead of formatted results");
|
|
58
62
|
|
|
59
|
-
command.action(async (...args:
|
|
63
|
+
command.action(async (...args: unknown[]) => {
|
|
60
64
|
try {
|
|
61
65
|
// The last argument is always the command object with parsed options
|
|
62
|
-
const commandObj = args[args.length - 1]
|
|
66
|
+
const commandObj = args[args.length - 1] as {
|
|
67
|
+
opts(): Record<string, unknown>;
|
|
68
|
+
};
|
|
63
69
|
const options = commandObj.opts();
|
|
64
70
|
|
|
65
71
|
// Convert CLI args to SDK method parameters
|
|
@@ -69,9 +75,10 @@ export function createGenerateTypesCommand(): Command {
|
|
|
69
75
|
options,
|
|
70
76
|
);
|
|
71
77
|
|
|
72
|
-
// Create SDK instance
|
|
73
|
-
const sdk = createZapierSdk(
|
|
74
|
-
|
|
78
|
+
// Create SDK instance with manifest path if provided
|
|
79
|
+
const sdk = createZapierSdk({
|
|
80
|
+
manifestPath: rawParams.lockFilePath as string | undefined,
|
|
81
|
+
});
|
|
75
82
|
// Resolve missing parameters interactively using schema metadata
|
|
76
83
|
const resolver = new SchemaParameterResolver();
|
|
77
84
|
const resolvedParams = await resolver.resolveParameters(
|
|
@@ -80,20 +87,29 @@ export function createGenerateTypesCommand(): Command {
|
|
|
80
87
|
sdk,
|
|
81
88
|
);
|
|
82
89
|
|
|
90
|
+
const params = resolvedParams as Record<string, unknown>;
|
|
83
91
|
console.log(
|
|
84
92
|
chalk.blue(
|
|
85
|
-
`š§ Generating TypeScript types for ${
|
|
93
|
+
`š§ Generating TypeScript types for ${params.appKey as string}...`,
|
|
86
94
|
),
|
|
87
95
|
);
|
|
88
96
|
|
|
89
97
|
// Call our implementation
|
|
90
|
-
const
|
|
98
|
+
const generateTypesParams = {
|
|
99
|
+
appKey: params.appKey as string,
|
|
100
|
+
debug: (params.debug as boolean) ?? false,
|
|
101
|
+
authenticationId: params.authenticationId as number | undefined,
|
|
102
|
+
output: params.output as string | undefined,
|
|
103
|
+
sdk,
|
|
104
|
+
};
|
|
105
|
+
const result = await generateTypes(generateTypesParams);
|
|
91
106
|
|
|
92
107
|
if (options.json) {
|
|
93
108
|
console.log(JSON.stringify({ result }, null, 2));
|
|
94
109
|
} else {
|
|
95
110
|
const output =
|
|
96
|
-
|
|
111
|
+
(params.output as string) ||
|
|
112
|
+
`./types/${params.appKey as string}.d.ts`;
|
|
97
113
|
console.log(chalk.green("ā
TypeScript types generated successfully!"));
|
|
98
114
|
console.log(chalk.gray(`Output written to: ${output}`));
|
|
99
115
|
}
|
|
@@ -64,24 +64,50 @@ export async function generateTypes(
|
|
|
64
64
|
if (authenticationId) {
|
|
65
65
|
for (const action of actions) {
|
|
66
66
|
try {
|
|
67
|
+
// Check to see if the appKey is in the manifest
|
|
68
|
+
const manifestEntry = sdk.getContext().getManifestEntry(appKey);
|
|
69
|
+
|
|
67
70
|
const fieldsResult = await sdk.listInputFields({
|
|
68
|
-
appKey
|
|
71
|
+
// If the appKey is in the manifest, use the appKey so that the types are consistent with the manifest's version, otherwise use the action.app_key
|
|
72
|
+
appKey: manifestEntry ? appKey : action.app_key,
|
|
69
73
|
actionKey: action.key,
|
|
70
|
-
actionType: action.action_type
|
|
74
|
+
actionType: action.action_type,
|
|
71
75
|
authenticationId: authenticationId,
|
|
72
76
|
});
|
|
73
77
|
|
|
74
|
-
const fields = fieldsResult.data
|
|
75
|
-
|
|
78
|
+
const fields = fieldsResult.data.map((field: unknown): ActionField => {
|
|
79
|
+
const fieldObj = field as {
|
|
80
|
+
is_required?: boolean;
|
|
81
|
+
required?: boolean;
|
|
82
|
+
[key: string]: unknown;
|
|
83
|
+
};
|
|
84
|
+
return {
|
|
85
|
+
...fieldObj,
|
|
86
|
+
required: fieldObj.is_required || fieldObj.required || false,
|
|
87
|
+
} as ActionField;
|
|
88
|
+
});
|
|
89
|
+
actionsWithFields.push({
|
|
90
|
+
...action,
|
|
91
|
+
inputFields: fields,
|
|
92
|
+
name: action.title || action.key,
|
|
93
|
+
});
|
|
76
94
|
} catch {
|
|
77
95
|
// If we can't get fields for an action, include it without fields
|
|
78
|
-
actionsWithFields.push({
|
|
96
|
+
actionsWithFields.push({
|
|
97
|
+
...action,
|
|
98
|
+
inputFields: [],
|
|
99
|
+
name: action.title || action.key,
|
|
100
|
+
});
|
|
79
101
|
}
|
|
80
102
|
}
|
|
81
103
|
} else {
|
|
82
104
|
// Convert actions to have empty input fields (will generate generic types)
|
|
83
105
|
actions.forEach((action: ActionItem) => {
|
|
84
|
-
actionsWithFields.push({
|
|
106
|
+
actionsWithFields.push({
|
|
107
|
+
...action,
|
|
108
|
+
inputFields: [],
|
|
109
|
+
name: action.title || action.key,
|
|
110
|
+
});
|
|
85
111
|
});
|
|
86
112
|
}
|
|
87
113
|
|
|
@@ -17,6 +17,10 @@ export const GenerateTypesSchema = z
|
|
|
17
17
|
debug: DebugPropertySchema.describe(
|
|
18
18
|
"Enable debug logging during generation",
|
|
19
19
|
),
|
|
20
|
+
lockFilePath: z
|
|
21
|
+
.string()
|
|
22
|
+
.optional()
|
|
23
|
+
.describe("Path to the .zapierrc lock file (defaults to .zapierrc)"),
|
|
20
24
|
})
|
|
21
25
|
.describe("Generate TypeScript SDK code for a specific app");
|
|
22
26
|
|
package/src/utils/api/client.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
// Simple HTTP client for OAuth authentication
|
|
2
|
-
export interface ApiResponse<T =
|
|
2
|
+
export interface ApiResponse<T = unknown> {
|
|
3
3
|
data: T;
|
|
4
4
|
status: number;
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
export const createApiClient = () => {
|
|
8
|
-
const post = async <T =
|
|
8
|
+
const post = async <T = unknown>(
|
|
9
9
|
url: string,
|
|
10
|
-
data:
|
|
10
|
+
data: Record<string, string>,
|
|
11
11
|
options: {
|
|
12
12
|
headers?: Record<string, string>;
|
|
13
13
|
} = {},
|
package/src/utils/auth/login.ts
CHANGED
|
@@ -2,6 +2,7 @@ import open from "open";
|
|
|
2
2
|
import crypto from "node:crypto";
|
|
3
3
|
import express from "express";
|
|
4
4
|
import pkceChallenge from "pkce-challenge";
|
|
5
|
+
import type { Socket } from "net";
|
|
5
6
|
|
|
6
7
|
import {
|
|
7
8
|
AUTH_MODE_HEADER,
|
|
@@ -86,7 +87,7 @@ const login = async (timeoutMs: number = LOGIN_TIMEOUT_MS): Promise<string> => {
|
|
|
86
87
|
const server = app.listen(availablePort);
|
|
87
88
|
|
|
88
89
|
// Track connections to force close them if needed
|
|
89
|
-
const connections = new Set<
|
|
90
|
+
const connections = new Set<Socket>();
|
|
90
91
|
server.on("connection", (conn) => {
|
|
91
92
|
connections.add(conn);
|
|
92
93
|
conn.on("close", () => connections.delete(conn));
|
|
@@ -10,7 +10,7 @@ export interface CliParameter {
|
|
|
10
10
|
type: "string" | "number" | "boolean" | "array";
|
|
11
11
|
required: boolean;
|
|
12
12
|
description?: string;
|
|
13
|
-
default?:
|
|
13
|
+
default?: unknown;
|
|
14
14
|
choices?: string[];
|
|
15
15
|
hasResolver?: boolean;
|
|
16
16
|
isPositional?: boolean;
|
|
@@ -43,7 +43,7 @@ function analyzeZodField(
|
|
|
43
43
|
): CliParameter | null {
|
|
44
44
|
let baseSchema = schema;
|
|
45
45
|
let required = true;
|
|
46
|
-
let defaultValue:
|
|
46
|
+
let defaultValue: unknown = undefined;
|
|
47
47
|
|
|
48
48
|
// Unwrap optional and default wrappers
|
|
49
49
|
if (baseSchema instanceof z.ZodOptional) {
|
|
@@ -96,10 +96,10 @@ function analyzeZodField(
|
|
|
96
96
|
|
|
97
97
|
export function convertCliArgsToSdkParams(
|
|
98
98
|
parameters: CliParameter[],
|
|
99
|
-
positionalArgs:
|
|
100
|
-
options: Record<string,
|
|
101
|
-
): Record<string,
|
|
102
|
-
const sdkParams: Record<string,
|
|
99
|
+
positionalArgs: unknown[],
|
|
100
|
+
options: Record<string, unknown>,
|
|
101
|
+
): Record<string, unknown> {
|
|
102
|
+
const sdkParams: Record<string, unknown> = {};
|
|
103
103
|
|
|
104
104
|
// Handle positional arguments (required parameters or optional positional parameters)
|
|
105
105
|
let argIndex = 0;
|
|
@@ -131,7 +131,7 @@ export function convertCliArgsToSdkParams(
|
|
|
131
131
|
return sdkParams;
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
-
function convertValue(value:
|
|
134
|
+
function convertValue(value: unknown, type: CliParameter["type"]): unknown {
|
|
135
135
|
switch (type) {
|
|
136
136
|
case "number":
|
|
137
137
|
return Number(value);
|
|
@@ -17,13 +17,15 @@ import inquirer from "inquirer";
|
|
|
17
17
|
// JSON Formatting
|
|
18
18
|
// ============================================================================
|
|
19
19
|
|
|
20
|
-
function formatJsonOutput(data:
|
|
20
|
+
function formatJsonOutput(data: unknown): void {
|
|
21
21
|
// Show success message for action results
|
|
22
22
|
if (
|
|
23
23
|
data &&
|
|
24
24
|
typeof data === "object" &&
|
|
25
25
|
!Array.isArray(data) &&
|
|
26
|
-
(data.success !== undefined ||
|
|
26
|
+
((data as Record<string, unknown>).success !== undefined ||
|
|
27
|
+
(data as Record<string, unknown>).id ||
|
|
28
|
+
(data as Record<string, unknown>).status)
|
|
27
29
|
) {
|
|
28
30
|
console.log(chalk.green("ā
Action completed successfully!\n"));
|
|
29
31
|
}
|
|
@@ -41,7 +43,7 @@ function formatJsonOutput(data: any): void {
|
|
|
41
43
|
interface CliCommandConfig {
|
|
42
44
|
description: string;
|
|
43
45
|
parameters: CliParameter[];
|
|
44
|
-
handler: (...args:
|
|
46
|
+
handler: (...args: unknown[]) => Promise<void>;
|
|
45
47
|
}
|
|
46
48
|
|
|
47
49
|
interface CliParameter {
|
|
@@ -49,7 +51,7 @@ interface CliParameter {
|
|
|
49
51
|
type: "string" | "number" | "boolean" | "array";
|
|
50
52
|
required: boolean;
|
|
51
53
|
description?: string;
|
|
52
|
-
default?:
|
|
54
|
+
default?: unknown;
|
|
53
55
|
choices?: string[];
|
|
54
56
|
hasResolver?: boolean;
|
|
55
57
|
isPositional?: boolean;
|
|
@@ -82,7 +84,7 @@ function analyzeZodField(
|
|
|
82
84
|
): CliParameter | null {
|
|
83
85
|
let baseSchema = schema;
|
|
84
86
|
let required = true;
|
|
85
|
-
let defaultValue:
|
|
87
|
+
let defaultValue: unknown = undefined;
|
|
86
88
|
|
|
87
89
|
// Unwrap optional and default wrappers
|
|
88
90
|
if (baseSchema instanceof z.ZodOptional) {
|
|
@@ -155,13 +157,15 @@ function methodNameToCliCommand(methodName: string): string {
|
|
|
155
157
|
|
|
156
158
|
export function generateCliCommands(program: Command, sdk: ZapierSdk): void {
|
|
157
159
|
// Check if SDK has registry
|
|
158
|
-
if (
|
|
160
|
+
if (typeof sdk.getRegistry !== "function") {
|
|
159
161
|
console.error("SDK registry not available");
|
|
160
162
|
return;
|
|
161
163
|
}
|
|
162
164
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
+
const registry = sdk.getRegistry();
|
|
166
|
+
|
|
167
|
+
// Create all commands first
|
|
168
|
+
registry.functions.forEach((fnInfo) => {
|
|
165
169
|
if (!fnInfo.inputSchema) {
|
|
166
170
|
console.warn(`Schema not found for ${fnInfo.name}`);
|
|
167
171
|
return;
|
|
@@ -179,6 +183,75 @@ export function generateCliCommands(program: Command, sdk: ZapierSdk): void {
|
|
|
179
183
|
|
|
180
184
|
addCommand(program, cliCommandName, config);
|
|
181
185
|
});
|
|
186
|
+
|
|
187
|
+
// Override the help display to show commands grouped by category
|
|
188
|
+
program.configureHelp({
|
|
189
|
+
formatHelp: (cmd, helper) => {
|
|
190
|
+
const helpWidth = helper.helpWidth || 80;
|
|
191
|
+
|
|
192
|
+
let output = helper.commandUsage(cmd) + "\n";
|
|
193
|
+
|
|
194
|
+
if (cmd.description()) {
|
|
195
|
+
output += helper.wrap(cmd.description(), helpWidth, 0) + "\n";
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Add options section
|
|
199
|
+
const options = helper.visibleOptions(cmd);
|
|
200
|
+
if (options.length > 0) {
|
|
201
|
+
output += "\nOptions:\n";
|
|
202
|
+
const longestOptionLength = Math.max(
|
|
203
|
+
...options.map((opt) => helper.optionTerm(opt).length),
|
|
204
|
+
);
|
|
205
|
+
options.forEach((option) => {
|
|
206
|
+
const term = helper.optionTerm(option);
|
|
207
|
+
const padding = " ".repeat(
|
|
208
|
+
Math.max(2, longestOptionLength - term.length + 4),
|
|
209
|
+
);
|
|
210
|
+
output += ` ${term}${padding}${helper.optionDescription(option)}\n`;
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Add categorized commands section
|
|
215
|
+
const commands = helper.visibleCommands(cmd);
|
|
216
|
+
if (commands.length > 0) {
|
|
217
|
+
output += "\nCommands:\n";
|
|
218
|
+
|
|
219
|
+
// Collect all SDK commands that belong to categories
|
|
220
|
+
const categorizedCommands = new Set<string>();
|
|
221
|
+
|
|
222
|
+
// Group SDK commands by categories
|
|
223
|
+
registry.categories.forEach((category) => {
|
|
224
|
+
const categoryCommands = commands.filter((command) =>
|
|
225
|
+
category.functions.some((functionName) => {
|
|
226
|
+
const cliCommandName = methodNameToCliCommand(functionName);
|
|
227
|
+
return command.name() === cliCommandName;
|
|
228
|
+
}),
|
|
229
|
+
);
|
|
230
|
+
|
|
231
|
+
if (categoryCommands.length > 0) {
|
|
232
|
+
output += `\n ${category.titlePlural}:\n`;
|
|
233
|
+
categoryCommands.forEach((command) => {
|
|
234
|
+
output += ` ${helper.subcommandTerm(command)}\n`;
|
|
235
|
+
categorizedCommands.add(command.name());
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
// Add any remaining commands that aren't part of SDK categories
|
|
241
|
+
const otherCommands = commands.filter(
|
|
242
|
+
(command) => !categorizedCommands.has(command.name()),
|
|
243
|
+
);
|
|
244
|
+
if (otherCommands.length > 0) {
|
|
245
|
+
output += `\n Other:\n`;
|
|
246
|
+
otherCommands.forEach((command) => {
|
|
247
|
+
output += ` ${helper.subcommandTerm(command)}\n`;
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return output;
|
|
253
|
+
},
|
|
254
|
+
});
|
|
182
255
|
}
|
|
183
256
|
|
|
184
257
|
function createCommandConfig(
|
|
@@ -190,10 +263,12 @@ function createCommandConfig(
|
|
|
190
263
|
const parameters = analyzeZodSchema(schema);
|
|
191
264
|
const description = schema.description || `${cliCommandName} command`;
|
|
192
265
|
|
|
193
|
-
const handler = async (...args:
|
|
266
|
+
const handler = async (...args: unknown[]) => {
|
|
194
267
|
try {
|
|
195
268
|
// The last argument is always the command object with parsed options
|
|
196
|
-
const commandObj = args[args.length - 1]
|
|
269
|
+
const commandObj = args[args.length - 1] as {
|
|
270
|
+
opts(): Record<string, unknown>;
|
|
271
|
+
};
|
|
197
272
|
const options = commandObj.opts();
|
|
198
273
|
|
|
199
274
|
// Check if this is a list command for pagination
|
|
@@ -201,7 +276,7 @@ function createCommandConfig(
|
|
|
201
276
|
const hasPaginationParams = parameters.some(
|
|
202
277
|
(p) => p.name === "maxItems" || p.name === "pageSize",
|
|
203
278
|
);
|
|
204
|
-
const hasUserSpecifiedMaxItems =
|
|
279
|
+
const hasUserSpecifiedMaxItems: boolean =
|
|
205
280
|
"maxItems" in options && options.maxItems !== undefined;
|
|
206
281
|
const shouldUseJson = options.json;
|
|
207
282
|
|
|
@@ -220,18 +295,6 @@ function createCommandConfig(
|
|
|
220
295
|
sdk,
|
|
221
296
|
);
|
|
222
297
|
|
|
223
|
-
// Special handling for commands that write to files
|
|
224
|
-
const hasOutputFile = resolvedParams.output;
|
|
225
|
-
if (hasOutputFile) {
|
|
226
|
-
// Call the SDK method for file output commands
|
|
227
|
-
await (sdk as any)[sdkMethodName](resolvedParams);
|
|
228
|
-
console.log(
|
|
229
|
-
chalk.green(`ā
${cliCommandName} completed successfully!`),
|
|
230
|
-
);
|
|
231
|
-
console.log(chalk.gray(`Output written to: ${resolvedParams.output}`));
|
|
232
|
-
return;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
298
|
// Handle paginated list commands with async iteration
|
|
236
299
|
if (
|
|
237
300
|
isListCommand &&
|
|
@@ -240,25 +303,51 @@ function createCommandConfig(
|
|
|
240
303
|
!hasUserSpecifiedMaxItems
|
|
241
304
|
) {
|
|
242
305
|
// Get the async iterator directly from the SDK method call
|
|
243
|
-
const
|
|
306
|
+
const sdkObj = sdk as unknown as Record<
|
|
307
|
+
string,
|
|
308
|
+
(params: unknown) => Promise<unknown>
|
|
309
|
+
>;
|
|
310
|
+
const sdkIterator = await sdkObj[sdkMethodName](resolvedParams);
|
|
244
311
|
await handlePaginatedListWithAsyncIteration(
|
|
245
312
|
sdkMethodName,
|
|
246
313
|
sdkIterator,
|
|
247
314
|
schema,
|
|
248
315
|
);
|
|
249
316
|
} else {
|
|
317
|
+
// Special handling for commands that write to files
|
|
318
|
+
const hasOutputFile = (resolvedParams as { output?: unknown }).output;
|
|
319
|
+
if (hasOutputFile) {
|
|
320
|
+
// Call the SDK method for file output commands
|
|
321
|
+
const sdkObj = sdk as unknown as Record<
|
|
322
|
+
string,
|
|
323
|
+
(params: unknown) => Promise<unknown>
|
|
324
|
+
>;
|
|
325
|
+
await sdkObj[sdkMethodName](resolvedParams);
|
|
326
|
+
console.log(
|
|
327
|
+
chalk.green(`ā
${cliCommandName} completed successfully!`),
|
|
328
|
+
);
|
|
329
|
+
console.log(chalk.gray(`Output written to: ${hasOutputFile}`));
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
|
|
250
333
|
// Call the SDK method and handle non-paginated results
|
|
251
|
-
const
|
|
252
|
-
|
|
334
|
+
const sdkObj = sdk as unknown as Record<
|
|
335
|
+
string,
|
|
336
|
+
(params: unknown) => Promise<unknown>
|
|
337
|
+
>;
|
|
338
|
+
const result: unknown = await sdkObj[sdkMethodName](resolvedParams);
|
|
339
|
+
const items = (result as { data?: unknown })?.data
|
|
340
|
+
? (result as { data: unknown }).data
|
|
341
|
+
: result;
|
|
253
342
|
|
|
254
343
|
if (shouldUseJson) {
|
|
255
344
|
console.log(JSON.stringify(items, null, 2));
|
|
256
345
|
} else if (isListCommand) {
|
|
257
346
|
formatNonPaginatedResults(
|
|
258
|
-
items,
|
|
259
|
-
resolvedParams.maxItems,
|
|
347
|
+
items as unknown[],
|
|
348
|
+
(resolvedParams as { maxItems?: number }).maxItems,
|
|
260
349
|
hasUserSpecifiedMaxItems,
|
|
261
|
-
shouldUseJson,
|
|
350
|
+
shouldUseJson as boolean,
|
|
262
351
|
schema,
|
|
263
352
|
sdkMethodName,
|
|
264
353
|
);
|
|
@@ -272,9 +361,14 @@ function createCommandConfig(
|
|
|
272
361
|
try {
|
|
273
362
|
const validationErrors = JSON.parse(error.message);
|
|
274
363
|
console.error(chalk.red("ā Validation Error:"));
|
|
275
|
-
validationErrors.forEach((err:
|
|
276
|
-
const
|
|
277
|
-
|
|
364
|
+
validationErrors.forEach((err: unknown) => {
|
|
365
|
+
const errorObj = err as { path?: string[]; message?: string };
|
|
366
|
+
const field = errorObj?.path?.join(".") || "unknown";
|
|
367
|
+
console.error(
|
|
368
|
+
chalk.yellow(
|
|
369
|
+
` ⢠${field}: ${errorObj?.message || "Unknown error"}`,
|
|
370
|
+
),
|
|
371
|
+
);
|
|
278
372
|
});
|
|
279
373
|
console.error(
|
|
280
374
|
"\n" + chalk.dim(`Use --help to see available options`),
|
|
@@ -342,10 +436,18 @@ function addCommand(
|
|
|
342
436
|
} else if (param.type === "array") {
|
|
343
437
|
// For arrays, use variadic syntax to collect multiple values
|
|
344
438
|
const flagSignature = flags.join(", ") + ` <values...>`;
|
|
345
|
-
command.option(
|
|
439
|
+
command.option(
|
|
440
|
+
flagSignature,
|
|
441
|
+
param.description,
|
|
442
|
+
param.default as string[] | undefined,
|
|
443
|
+
);
|
|
346
444
|
} else {
|
|
347
445
|
const flagSignature = flags.join(", ") + ` <${param.type}>`;
|
|
348
|
-
command.option(
|
|
446
|
+
command.option(
|
|
447
|
+
flagSignature,
|
|
448
|
+
param.description || "",
|
|
449
|
+
param.default as string | boolean | string[] | undefined,
|
|
450
|
+
);
|
|
349
451
|
}
|
|
350
452
|
}
|
|
351
453
|
});
|
|
@@ -362,10 +464,10 @@ function addCommand(
|
|
|
362
464
|
|
|
363
465
|
function convertCliArgsToSdkParams(
|
|
364
466
|
parameters: CliParameter[],
|
|
365
|
-
positionalArgs:
|
|
366
|
-
options: Record<string,
|
|
367
|
-
): Record<string,
|
|
368
|
-
const sdkParams: Record<string,
|
|
467
|
+
positionalArgs: unknown[],
|
|
468
|
+
options: Record<string, unknown>,
|
|
469
|
+
): Record<string, unknown> {
|
|
470
|
+
const sdkParams: Record<string, unknown> = {};
|
|
369
471
|
|
|
370
472
|
// Handle positional arguments (required parameters or optional positional parameters)
|
|
371
473
|
let argIndex = 0;
|
|
@@ -397,7 +499,7 @@ function convertCliArgsToSdkParams(
|
|
|
397
499
|
return sdkParams;
|
|
398
500
|
}
|
|
399
501
|
|
|
400
|
-
function convertValue(value:
|
|
502
|
+
function convertValue(value: unknown, type: CliParameter["type"]): unknown {
|
|
401
503
|
switch (type) {
|
|
402
504
|
case "number":
|
|
403
505
|
return Number(value);
|
|
@@ -428,7 +530,7 @@ function convertValue(value: any, type: CliParameter["type"]): any {
|
|
|
428
530
|
|
|
429
531
|
async function handlePaginatedListWithAsyncIteration(
|
|
430
532
|
sdkMethodName: string,
|
|
431
|
-
sdkResult:
|
|
533
|
+
sdkResult: unknown,
|
|
432
534
|
schema: z.ZodSchema,
|
|
433
535
|
): Promise<void> {
|
|
434
536
|
const itemName = getItemNameFromMethod(sdkMethodName);
|
|
@@ -439,7 +541,10 @@ async function handlePaginatedListWithAsyncIteration(
|
|
|
439
541
|
|
|
440
542
|
try {
|
|
441
543
|
// Use async iteration to go through pages
|
|
442
|
-
for await (const page of sdkResult
|
|
544
|
+
for await (const page of sdkResult as AsyncIterable<{
|
|
545
|
+
data?: unknown[];
|
|
546
|
+
nextCursor?: string;
|
|
547
|
+
}>) {
|
|
443
548
|
const items = page.data || page;
|
|
444
549
|
pageCount++;
|
|
445
550
|
|
|
@@ -502,7 +607,7 @@ async function handlePaginatedListWithAsyncIteration(
|
|
|
502
607
|
console.log(chalk.gray(`\nš Finished browsing ${itemName}`));
|
|
503
608
|
} catch (error) {
|
|
504
609
|
// If the result is not async iterable, fall back to showing the first page
|
|
505
|
-
const items = sdkResult?.data || sdkResult;
|
|
610
|
+
const items = (sdkResult as { data?: unknown[] })?.data || sdkResult;
|
|
506
611
|
if (Array.isArray(items)) {
|
|
507
612
|
if (items.length === 0) {
|
|
508
613
|
console.log(chalk.yellow(`No ${itemName} found.`));
|
|
@@ -523,7 +628,7 @@ async function handlePaginatedListWithAsyncIteration(
|
|
|
523
628
|
}
|
|
524
629
|
|
|
525
630
|
function formatNonPaginatedResults(
|
|
526
|
-
result:
|
|
631
|
+
result: unknown[],
|
|
527
632
|
requestedMaxItems?: number,
|
|
528
633
|
userSpecifiedMaxItems?: boolean,
|
|
529
634
|
useRawJson?: boolean,
|
|
@@ -573,13 +678,14 @@ function formatNonPaginatedResults(
|
|
|
573
678
|
}
|
|
574
679
|
}
|
|
575
680
|
|
|
576
|
-
function formatItemsGeneric(items:
|
|
681
|
+
function formatItemsGeneric(items: unknown[]): void {
|
|
577
682
|
// Fallback formatting for items without schema metadata
|
|
578
683
|
items.forEach((item, index) => {
|
|
579
|
-
const
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
684
|
+
const itemObj = item as Record<string, unknown>;
|
|
685
|
+
const name = itemObj?.name || itemObj?.key || itemObj?.id || "Item";
|
|
686
|
+
console.log(`${chalk.gray(`${index + 1}.`)} ${chalk.cyan(String(name))}`);
|
|
687
|
+
if (itemObj?.description) {
|
|
688
|
+
console.log(` ${chalk.dim(String(itemObj.description))}`);
|
|
583
689
|
}
|
|
584
690
|
console.log();
|
|
585
691
|
});
|