@zapier/zapier-sdk-cli 0.0.3 ā 0.1.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/dist/cli.js +1 -3
- package/dist/utils/cli-generator.d.ts +2 -3
- package/dist/utils/cli-generator.js +98 -124
- package/dist/utils/parameter-resolver.d.ts +6 -11
- package/dist/utils/parameter-resolver.js +223 -329
- package/dist/utils/schema-formatter.js +8 -3
- package/package.json +5 -3
- package/src/cli.ts +3 -6
- package/src/utils/cli-generator.ts +123 -161
- package/src/utils/parameter-resolver.ts +277 -432
- package/src/utils/schema-formatter.ts +23 -5
- package/tsconfig.json +1 -1
- package/dist/commands/action.d.ts +0 -2
- package/dist/commands/action.js +0 -295
- package/dist/commands/browse.d.ts +0 -2
- package/dist/commands/browse.js +0 -257
- package/dist/commands/bundle.d.ts +0 -2
- package/dist/commands/bundle.js +0 -101
- package/dist/commands/generate.d.ts +0 -9
- package/dist/commands/generate.js +0 -281
- package/dist/utils/auth-picker.d.ts +0 -17
- package/dist/utils/auth-picker.js +0 -121
- package/dist/utils/schema-generator.d.ts +0 -4
- package/dist/utils/schema-generator.js +0 -389
package/dist/cli.js
CHANGED
|
@@ -14,12 +14,10 @@ program
|
|
|
14
14
|
const isDebugMode = process.env.DEBUG === "true" || process.argv.includes("--debug");
|
|
15
15
|
// Create SDK instance for CLI operations
|
|
16
16
|
// Auth will be resolved from environment variables or command options
|
|
17
|
-
const sdk = (0, zapier_sdk_1.
|
|
17
|
+
const sdk = (0, zapier_sdk_1.createZapierSdk)({
|
|
18
18
|
// Token will be picked up from ZAPIER_TOKEN env var or provided via options
|
|
19
19
|
debug: isDebugMode,
|
|
20
20
|
});
|
|
21
21
|
// Generate CLI commands from SDK schemas
|
|
22
22
|
(0, cli_generator_1.generateCliCommands)(program, sdk);
|
|
23
|
-
// Add enhanced help information
|
|
24
|
-
(0, cli_generator_1.enhanceCommandHelp)(program);
|
|
25
23
|
program.parse();
|
|
@@ -1,4 +1,3 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
|
-
import {
|
|
3
|
-
export declare function generateCliCommands(program: Command, sdk:
|
|
4
|
-
export declare function enhanceCommandHelp(program: Command): void;
|
|
2
|
+
import { ZapierSdk } from "@zapier/zapier-sdk";
|
|
3
|
+
export declare function generateCliCommands(program: Command, sdk: ZapierSdk): void;
|
|
@@ -4,7 +4,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.generateCliCommands = generateCliCommands;
|
|
7
|
-
exports.enhanceCommandHelp = enhanceCommandHelp;
|
|
8
7
|
const zod_1 = require("zod");
|
|
9
8
|
const zapier_sdk_1 = require("@zapier/zapier-sdk");
|
|
10
9
|
const parameter_resolver_1 = require("./parameter-resolver");
|
|
@@ -80,7 +79,6 @@ function analyzeZodField(name, schema) {
|
|
|
80
79
|
paramType = "string";
|
|
81
80
|
}
|
|
82
81
|
// Extract resolver metadata
|
|
83
|
-
const resolverMeta = schema._def.resolverMeta;
|
|
84
82
|
return {
|
|
85
83
|
name,
|
|
86
84
|
type: paramType,
|
|
@@ -88,81 +86,75 @@ function analyzeZodField(name, schema) {
|
|
|
88
86
|
description: schema.description,
|
|
89
87
|
default: defaultValue,
|
|
90
88
|
choices,
|
|
91
|
-
|
|
89
|
+
hasResolver: (0, zapier_sdk_1.hasResolver)(name),
|
|
92
90
|
};
|
|
93
91
|
}
|
|
94
92
|
// ============================================================================
|
|
95
|
-
// CLI
|
|
93
|
+
// CLI Structure Derivation - Purely Generic
|
|
94
|
+
// ============================================================================
|
|
95
|
+
/**
|
|
96
|
+
* Convert camelCase to kebab-case
|
|
97
|
+
* e.g., listApps -> list-apps, generateTypes -> generate-types
|
|
98
|
+
*/
|
|
99
|
+
function toKebabCase(str) {
|
|
100
|
+
return str.replace(/([A-Z])/g, "-$1").toLowerCase();
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Convert SDK method name directly to CLI command
|
|
104
|
+
* e.g., listApps -> list-apps, getApp -> get-app, generateTypes -> generate-types
|
|
105
|
+
*/
|
|
106
|
+
function methodNameToCliCommand(methodName) {
|
|
107
|
+
return toKebabCase(methodName);
|
|
108
|
+
}
|
|
109
|
+
// ============================================================================
|
|
110
|
+
// CLI Command Generation - Completely Generic
|
|
96
111
|
// ============================================================================
|
|
97
112
|
function generateCliCommands(program, sdk) {
|
|
98
|
-
// Check if
|
|
99
|
-
if (!
|
|
100
|
-
console.error("
|
|
113
|
+
// Check if SDK has registry
|
|
114
|
+
if (!sdk.__registry) {
|
|
115
|
+
console.error("SDK registry not available");
|
|
101
116
|
return;
|
|
102
117
|
}
|
|
103
|
-
// Generate
|
|
104
|
-
|
|
105
|
-
if (
|
|
106
|
-
|
|
118
|
+
// Generate one flat command for each function in the registry
|
|
119
|
+
sdk.__registry.forEach((fnInfo) => {
|
|
120
|
+
if (!fnInfo.inputSchema) {
|
|
121
|
+
console.warn(`Schema not found for ${fnInfo.name}`);
|
|
107
122
|
return;
|
|
108
123
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
Object.entries(methods).forEach(([method, schema]) => {
|
|
114
|
-
const config = createCommandConfig(namespace, method, schema, sdk);
|
|
115
|
-
addSubCommand(namespaceCommand, method, config);
|
|
116
|
-
});
|
|
117
|
-
}
|
|
124
|
+
// Convert methodName to kebab-case CLI command
|
|
125
|
+
const cliCommandName = methodNameToCliCommand(fnInfo.name);
|
|
126
|
+
const config = createCommandConfig(cliCommandName, fnInfo.name, fnInfo.inputSchema, sdk);
|
|
127
|
+
addCommand(program, cliCommandName, config);
|
|
118
128
|
});
|
|
119
|
-
// Generate root tool commands
|
|
120
|
-
if (zapier_sdk_1.SdkSchemas.generate) {
|
|
121
|
-
const generateConfig = createCommandConfig("", "generate", zapier_sdk_1.SdkSchemas.generate, sdk);
|
|
122
|
-
addSubCommand(program, "generate", generateConfig);
|
|
123
|
-
}
|
|
124
|
-
if (zapier_sdk_1.SdkSchemas.bundle) {
|
|
125
|
-
const bundleConfig = createCommandConfig("", "bundle", zapier_sdk_1.SdkSchemas.bundle, sdk);
|
|
126
|
-
addSubCommand(program, "bundle", bundleConfig);
|
|
127
|
-
}
|
|
128
129
|
}
|
|
129
|
-
function createCommandConfig(
|
|
130
|
+
function createCommandConfig(cliCommandName, sdkMethodName, schema, sdk) {
|
|
130
131
|
const parameters = analyzeZodSchema(schema);
|
|
131
|
-
const description = schema.description || `${
|
|
132
|
+
const description = schema.description || `${cliCommandName} command`;
|
|
132
133
|
const handler = async (...args) => {
|
|
133
134
|
try {
|
|
134
135
|
// The last argument is always the command object with parsed options
|
|
135
|
-
const
|
|
136
|
-
const options =
|
|
137
|
-
// Check if this is a list command
|
|
138
|
-
const isListCommand =
|
|
136
|
+
const commandObj = args[args.length - 1];
|
|
137
|
+
const options = commandObj.opts();
|
|
138
|
+
// Check if this is a list command for pagination
|
|
139
|
+
const isListCommand = cliCommandName.startsWith("list-");
|
|
139
140
|
const hasPaginationParams = parameters.some((p) => p.name === "limit" || p.name === "offset");
|
|
140
141
|
const hasUserSpecifiedLimit = "limit" in options && options.limit !== undefined;
|
|
141
142
|
const shouldUsePaging = isListCommand && hasPaginationParams && !hasUserSpecifiedLimit;
|
|
142
143
|
const shouldUseJson = options.json;
|
|
143
144
|
// Convert CLI args to SDK method parameters
|
|
144
145
|
const rawParams = convertCliArgsToSdkParams(parameters, args.slice(0, -1), options);
|
|
145
|
-
//
|
|
146
|
+
// Resolve missing parameters interactively using schema metadata
|
|
146
147
|
const resolver = new parameter_resolver_1.SchemaParameterResolver();
|
|
147
148
|
const resolvedParams = await resolver.resolveParameters(schema, rawParams, sdk);
|
|
148
149
|
if (shouldUsePaging && !shouldUseJson) {
|
|
149
150
|
// Use interactive paging for list commands
|
|
150
|
-
await handlePaginatedList(
|
|
151
|
+
await handlePaginatedList(sdkMethodName, resolvedParams, sdk, schema);
|
|
151
152
|
}
|
|
152
153
|
else {
|
|
153
|
-
// Call the
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
result = await sdk[method](resolvedParams);
|
|
158
|
-
}
|
|
159
|
-
else {
|
|
160
|
-
// Regular namespace method
|
|
161
|
-
result = await sdk[namespace][method](resolvedParams);
|
|
162
|
-
}
|
|
163
|
-
// Special handling for generate and bundle commands - don't output to console if writing to file
|
|
164
|
-
const isRootCommandWithOutput = namespace === "" && (method === "generate" || method === "bundle");
|
|
165
|
-
const hasOutputFile = isRootCommandWithOutput && resolvedParams.output;
|
|
154
|
+
// Call the SDK method directly
|
|
155
|
+
const result = await sdk[sdkMethodName](resolvedParams);
|
|
156
|
+
// Special handling for commands that write to files
|
|
157
|
+
const hasOutputFile = resolvedParams.output;
|
|
166
158
|
// Output result (JSON or formatted)
|
|
167
159
|
if (!hasOutputFile && (shouldUseJson || !isListCommand)) {
|
|
168
160
|
// Use raw JSON if --json flag is specified, otherwise use pretty formatting
|
|
@@ -175,17 +167,34 @@ function createCommandConfig(namespace, method, schema, sdk) {
|
|
|
175
167
|
}
|
|
176
168
|
else if (!hasOutputFile) {
|
|
177
169
|
// Format list results nicely (non-paginated)
|
|
178
|
-
formatNonPaginatedResults(
|
|
170
|
+
formatNonPaginatedResults(result, resolvedParams.limit, hasUserSpecifiedLimit, shouldUseJson, schema, sdkMethodName);
|
|
179
171
|
}
|
|
180
172
|
else if (hasOutputFile) {
|
|
181
173
|
// Show success message for file output instead of printing generated content
|
|
182
|
-
console.log(chalk_1.default.green(`ā
${
|
|
174
|
+
console.log(chalk_1.default.green(`ā
${cliCommandName} completed successfully!`));
|
|
183
175
|
console.log(chalk_1.default.gray(`Output written to: ${resolvedParams.output}`));
|
|
184
176
|
}
|
|
185
177
|
}
|
|
186
178
|
}
|
|
187
179
|
catch (error) {
|
|
188
|
-
|
|
180
|
+
// Handle Zod validation errors more gracefully
|
|
181
|
+
if (error instanceof Error && error.message.includes('"code"')) {
|
|
182
|
+
try {
|
|
183
|
+
const validationErrors = JSON.parse(error.message);
|
|
184
|
+
console.error(chalk_1.default.red("ā Validation Error:"));
|
|
185
|
+
validationErrors.forEach((err) => {
|
|
186
|
+
const field = err.path?.join(".") || "unknown";
|
|
187
|
+
console.error(chalk_1.default.yellow(` ⢠${field}: ${err.message}`));
|
|
188
|
+
});
|
|
189
|
+
console.error("\n" + chalk_1.default.dim(`Use --help to see available options`));
|
|
190
|
+
}
|
|
191
|
+
catch {
|
|
192
|
+
console.error(chalk_1.default.red("Error:"), error.message);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
console.error(chalk_1.default.red("Error:"), error instanceof Error ? error.message : "Unknown error");
|
|
197
|
+
}
|
|
189
198
|
process.exit(1);
|
|
190
199
|
}
|
|
191
200
|
};
|
|
@@ -195,23 +204,23 @@ function createCommandConfig(namespace, method, schema, sdk) {
|
|
|
195
204
|
handler,
|
|
196
205
|
};
|
|
197
206
|
}
|
|
198
|
-
function
|
|
199
|
-
const command =
|
|
207
|
+
function addCommand(program, commandName, config) {
|
|
208
|
+
const command = program.command(commandName).description(config.description);
|
|
200
209
|
// Add parameters to command
|
|
201
210
|
config.parameters.forEach((param) => {
|
|
202
|
-
|
|
211
|
+
// Convert camelCase to kebab-case for CLI display
|
|
212
|
+
const kebabName = param.name.replace(/([A-Z])/g, "-$1").toLowerCase();
|
|
213
|
+
if (param.hasResolver && param.required) {
|
|
203
214
|
// Required parameters with resolvers become optional positional arguments (resolver handles prompting)
|
|
204
|
-
command.argument(`[${
|
|
215
|
+
command.argument(`[${kebabName}]`, param.description || `${kebabName} parameter`);
|
|
205
216
|
}
|
|
206
217
|
else if (param.required) {
|
|
207
218
|
// Required parameters without resolvers become required positional arguments
|
|
208
|
-
command.argument(`<${
|
|
219
|
+
command.argument(`<${kebabName}>`, param.description || `${kebabName} parameter`);
|
|
209
220
|
}
|
|
210
221
|
else {
|
|
211
222
|
// Optional parameters become flags (whether they have resolvers or not)
|
|
212
|
-
const flags = [
|
|
213
|
-
`--${param.name.replace(/([A-Z])/g, "-$1").toLowerCase()}`,
|
|
214
|
-
];
|
|
223
|
+
const flags = [`--${kebabName}`];
|
|
215
224
|
if (param.type === "boolean") {
|
|
216
225
|
command.option(flags.join(", "), param.description);
|
|
217
226
|
}
|
|
@@ -234,6 +243,7 @@ function convertCliArgsToSdkParams(parameters, positionalArgs, options) {
|
|
|
234
243
|
let argIndex = 0;
|
|
235
244
|
parameters.forEach((param) => {
|
|
236
245
|
if (param.required && argIndex < positionalArgs.length) {
|
|
246
|
+
// Use the original camelCase parameter name for the SDK
|
|
237
247
|
sdkParams[param.name] = convertValue(positionalArgs[argIndex], param.type);
|
|
238
248
|
argIndex++;
|
|
239
249
|
}
|
|
@@ -275,9 +285,9 @@ function convertValue(value, type) {
|
|
|
275
285
|
// ============================================================================
|
|
276
286
|
// Pagination Handlers
|
|
277
287
|
// ============================================================================
|
|
278
|
-
async function handlePaginatedList(
|
|
288
|
+
async function handlePaginatedList(sdkMethodName, baseParams, sdk, schema) {
|
|
279
289
|
const limit = baseParams.limit || 20;
|
|
280
|
-
const itemName =
|
|
290
|
+
const itemName = getItemNameFromMethod(sdkMethodName);
|
|
281
291
|
console.log(chalk_1.default.blue(`š Fetching ${itemName}...`));
|
|
282
292
|
const pager = (0, pager_1.createPager)({
|
|
283
293
|
pageSize: Math.min(limit, 20),
|
|
@@ -288,18 +298,14 @@ async function handlePaginatedList(namespace, method, baseParams, sdk) {
|
|
|
288
298
|
if (items.length > 0) {
|
|
289
299
|
console.clear();
|
|
290
300
|
}
|
|
291
|
-
console.log(chalk_1.default.blue(`š ${
|
|
301
|
+
console.log(chalk_1.default.blue(`š ${getListTitleFromMethod(sdkMethodName)}\n`));
|
|
292
302
|
if (items.length === 0) {
|
|
293
303
|
console.log(chalk_1.default.yellow(`No ${itemName} found.`));
|
|
294
304
|
return;
|
|
295
305
|
}
|
|
296
|
-
//
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
? schema.list
|
|
300
|
-
: null;
|
|
301
|
-
if (listSchema) {
|
|
302
|
-
(0, schema_formatter_1.formatItemsFromSchema)(listSchema, items);
|
|
306
|
+
// Use schema for formatting
|
|
307
|
+
if (schema) {
|
|
308
|
+
(0, schema_formatter_1.formatItemsFromSchema)(schema, items);
|
|
303
309
|
}
|
|
304
310
|
else {
|
|
305
311
|
// Fallback to generic formatting
|
|
@@ -310,12 +316,12 @@ async function handlePaginatedList(namespace, method, baseParams, sdk) {
|
|
|
310
316
|
: "";
|
|
311
317
|
console.log(chalk_1.default.green(`\nā
Showing ${totalShown}${totalInfo} ${itemName}`));
|
|
312
318
|
};
|
|
313
|
-
await pager.paginate((params) => sdk[
|
|
319
|
+
await pager.paginate((params) => sdk[sdkMethodName]({
|
|
314
320
|
...baseParams,
|
|
315
321
|
...params,
|
|
316
322
|
}), {}, displayFunction);
|
|
317
323
|
}
|
|
318
|
-
function formatNonPaginatedResults(
|
|
324
|
+
function formatNonPaginatedResults(result, requestedLimit, userSpecifiedLimit, useRawJson, schema, methodName) {
|
|
319
325
|
if (!Array.isArray(result)) {
|
|
320
326
|
if (useRawJson) {
|
|
321
327
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -329,19 +335,15 @@ function formatNonPaginatedResults(namespace, result, requestedLimit, userSpecif
|
|
|
329
335
|
console.log(JSON.stringify(result, null, 2));
|
|
330
336
|
return;
|
|
331
337
|
}
|
|
332
|
-
const itemName =
|
|
338
|
+
const itemName = methodName ? getItemNameFromMethod(methodName) : "items";
|
|
333
339
|
if (result.length === 0) {
|
|
334
340
|
console.log(chalk_1.default.yellow(`No ${itemName} found.`));
|
|
335
341
|
return;
|
|
336
342
|
}
|
|
337
343
|
console.log(chalk_1.default.green(`\nā
Found ${result.length} ${itemName}:\n`));
|
|
338
|
-
//
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
? schema.list
|
|
342
|
-
: null;
|
|
343
|
-
if (listSchema) {
|
|
344
|
-
(0, schema_formatter_1.formatItemsFromSchema)(listSchema, result);
|
|
344
|
+
// Use schema for formatting
|
|
345
|
+
if (schema) {
|
|
346
|
+
(0, schema_formatter_1.formatItemsFromSchema)(schema, result);
|
|
345
347
|
}
|
|
346
348
|
else {
|
|
347
349
|
// Fallback to generic formatting
|
|
@@ -366,49 +368,21 @@ function formatItemsGeneric(items) {
|
|
|
366
368
|
console.log();
|
|
367
369
|
});
|
|
368
370
|
}
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
case "auths":
|
|
376
|
-
return "authentications";
|
|
377
|
-
case "fields":
|
|
378
|
-
return "fields";
|
|
379
|
-
default:
|
|
380
|
-
return "items";
|
|
371
|
+
// Generic helper functions that infer from schema description or method name
|
|
372
|
+
function getItemNameFromMethod(methodName) {
|
|
373
|
+
// Extract from method name: listApps -> apps, listActions -> actions
|
|
374
|
+
const listMatch = methodName.match(/^list(.+)$/);
|
|
375
|
+
if (listMatch) {
|
|
376
|
+
return listMatch[1].toLowerCase();
|
|
381
377
|
}
|
|
378
|
+
// Fallback to generic
|
|
379
|
+
return "items";
|
|
382
380
|
}
|
|
383
|
-
function
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
return "Available Authentications";
|
|
391
|
-
case "fields":
|
|
392
|
-
return "Available Fields";
|
|
393
|
-
default:
|
|
394
|
-
return "Available Items";
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
// ============================================================================
|
|
398
|
-
// Help Text Enhancement
|
|
399
|
-
// ============================================================================
|
|
400
|
-
function enhanceCommandHelp(program) {
|
|
401
|
-
// Add custom help that shows schema-driven nature
|
|
402
|
-
program.on("--help", () => {
|
|
403
|
-
console.log("");
|
|
404
|
-
console.log("Commands are automatically generated from SDK schemas.");
|
|
405
|
-
console.log("Each command maps directly to an SDK method with the same parameters.");
|
|
406
|
-
console.log("");
|
|
407
|
-
console.log("Examples:");
|
|
408
|
-
console.log(" zapier-sdk apps list --category=productivity --limit=10");
|
|
409
|
-
console.log(' zapier-sdk actions run slack search user_by_email --inputs=\'{"email":"user@example.com"}\'');
|
|
410
|
-
console.log(" zapier-sdk generate my-app --output=./generated/");
|
|
411
|
-
console.log(" zsdk apps list --limit=5 # Using the shorter alias");
|
|
412
|
-
console.log("");
|
|
413
|
-
});
|
|
381
|
+
function getListTitleFromMethod(methodName) {
|
|
382
|
+
const itemName = getItemNameFromMethod(methodName);
|
|
383
|
+
if (itemName === "items")
|
|
384
|
+
return "Available Items";
|
|
385
|
+
// Capitalize first letter: apps -> Apps
|
|
386
|
+
const capitalized = itemName.charAt(0).toUpperCase() + itemName.slice(1);
|
|
387
|
+
return `Available ${capitalized}`;
|
|
414
388
|
}
|
|
@@ -1,18 +1,13 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import {
|
|
2
|
+
import { ZapierSdk } from "@zapier/zapier-sdk";
|
|
3
3
|
export declare class SchemaParameterResolver {
|
|
4
|
-
resolveParameters(schema: z.ZodSchema, providedParams: any, sdk:
|
|
5
|
-
private
|
|
6
|
-
private
|
|
7
|
-
private
|
|
8
|
-
private analyzeSchemaField;
|
|
9
|
-
private sortByDependencies;
|
|
4
|
+
resolveParameters(schema: z.ZodSchema, providedParams: any, sdk: ZapierSdk): Promise<any>;
|
|
5
|
+
private extractParametersFromSchema;
|
|
6
|
+
private analyzeFieldSchema;
|
|
7
|
+
private createResolvableParameter;
|
|
10
8
|
private resolveParameter;
|
|
11
|
-
private promptStaticInput;
|
|
12
|
-
private resolveDynamicParameter;
|
|
13
|
-
private resolveFieldsParameter;
|
|
14
|
-
private promptForField;
|
|
15
9
|
private getNestedValue;
|
|
16
10
|
private setNestedValue;
|
|
11
|
+
private promptForField;
|
|
17
12
|
private isUserCancellation;
|
|
18
13
|
}
|