@zapier/zapier-sdk-cli 0.0.3 → 0.1.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/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.createActionsSdk)({
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 { ActionsSdk } from "@zapier/zapier-sdk";
3
- export declare function generateCliCommands(program: Command, sdk: ActionsSdk): void;
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,76 @@ function analyzeZodField(name, schema) {
88
86
  description: schema.description,
89
87
  default: defaultValue,
90
88
  choices,
91
- resolverMeta,
89
+ hasResolver: (0, zapier_sdk_1.hasResolver)(name),
90
+ isPositional: (0, zapier_sdk_1.isPositional)(schema),
92
91
  };
93
92
  }
94
93
  // ============================================================================
95
- // CLI Command Generation
94
+ // CLI Structure Derivation - Purely Generic
95
+ // ============================================================================
96
+ /**
97
+ * Convert camelCase to kebab-case
98
+ * e.g., listApps -> list-apps, generateTypes -> generate-types
99
+ */
100
+ function toKebabCase(str) {
101
+ return str.replace(/([A-Z])/g, "-$1").toLowerCase();
102
+ }
103
+ /**
104
+ * Convert SDK method name directly to CLI command
105
+ * e.g., listApps -> list-apps, getApp -> get-app, generateTypes -> generate-types
106
+ */
107
+ function methodNameToCliCommand(methodName) {
108
+ return toKebabCase(methodName);
109
+ }
110
+ // ============================================================================
111
+ // CLI Command Generation - Completely Generic
96
112
  // ============================================================================
97
113
  function generateCliCommands(program, sdk) {
98
- // Check if SdkSchemas is available
99
- if (!zapier_sdk_1.SdkSchemas) {
100
- console.error("SdkSchemas not available");
114
+ // Check if SDK has registry
115
+ if (!sdk.__registry) {
116
+ console.error("SDK registry not available");
101
117
  return;
102
118
  }
103
- // Generate namespace commands (apps, actions, auths, fields)
104
- Object.entries(zapier_sdk_1.SdkSchemas).forEach(([namespace, methods]) => {
105
- if (namespace === "generate" || namespace === "bundle") {
106
- // Handle root tools separately
119
+ // Generate one flat command for each function in the registry
120
+ sdk.__registry.forEach((fnInfo) => {
121
+ if (!fnInfo.inputSchema) {
122
+ console.warn(`Schema not found for ${fnInfo.name}`);
107
123
  return;
108
124
  }
109
- const namespaceCommand = program
110
- .command(namespace)
111
- .description(`${namespace} management commands`);
112
- if (typeof methods === "object" && methods !== null) {
113
- Object.entries(methods).forEach(([method, schema]) => {
114
- const config = createCommandConfig(namespace, method, schema, sdk);
115
- addSubCommand(namespaceCommand, method, config);
116
- });
117
- }
125
+ // Convert methodName to kebab-case CLI command
126
+ const cliCommandName = methodNameToCliCommand(fnInfo.name);
127
+ const config = createCommandConfig(cliCommandName, fnInfo.name, fnInfo.inputSchema, sdk);
128
+ addCommand(program, cliCommandName, config);
118
129
  });
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
130
  }
129
- function createCommandConfig(namespace, method, schema, sdk) {
131
+ function createCommandConfig(cliCommandName, sdkMethodName, schema, sdk) {
130
132
  const parameters = analyzeZodSchema(schema);
131
- const description = schema.description || `${namespace} ${method} command`;
133
+ const description = schema.description || `${cliCommandName} command`;
132
134
  const handler = async (...args) => {
133
135
  try {
134
136
  // The last argument is always the command object with parsed options
135
- const command = args[args.length - 1];
136
- const options = command.opts();
137
- // Check if this is a list command with pagination support
138
- const isListCommand = method === "list";
137
+ const commandObj = args[args.length - 1];
138
+ const options = commandObj.opts();
139
+ // Check if this is a list command for pagination
140
+ const isListCommand = cliCommandName.startsWith("list-");
139
141
  const hasPaginationParams = parameters.some((p) => p.name === "limit" || p.name === "offset");
140
142
  const hasUserSpecifiedLimit = "limit" in options && options.limit !== undefined;
141
143
  const shouldUsePaging = isListCommand && hasPaginationParams && !hasUserSpecifiedLimit;
142
144
  const shouldUseJson = options.json;
143
145
  // Convert CLI args to SDK method parameters
144
146
  const rawParams = convertCliArgsToSdkParams(parameters, args.slice(0, -1), options);
145
- // NEW: Resolve missing parameters interactively using schema metadata
147
+ // Resolve missing parameters interactively using schema metadata
146
148
  const resolver = new parameter_resolver_1.SchemaParameterResolver();
147
149
  const resolvedParams = await resolver.resolveParameters(schema, rawParams, sdk);
148
150
  if (shouldUsePaging && !shouldUseJson) {
149
151
  // Use interactive paging for list commands
150
- await handlePaginatedList(namespace, method, resolvedParams, sdk);
152
+ await handlePaginatedList(sdkMethodName, resolvedParams, sdk, schema);
151
153
  }
152
154
  else {
153
- // Call the appropriate SDK method with complete, validated parameters
154
- let result;
155
- if (namespace === "") {
156
- // Root tool (generate, bundle)
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;
155
+ // Call the SDK method directly
156
+ const result = await sdk[sdkMethodName](resolvedParams);
157
+ // Special handling for commands that write to files
158
+ const hasOutputFile = resolvedParams.output;
166
159
  // Output result (JSON or formatted)
167
160
  if (!hasOutputFile && (shouldUseJson || !isListCommand)) {
168
161
  // Use raw JSON if --json flag is specified, otherwise use pretty formatting
@@ -175,17 +168,34 @@ function createCommandConfig(namespace, method, schema, sdk) {
175
168
  }
176
169
  else if (!hasOutputFile) {
177
170
  // Format list results nicely (non-paginated)
178
- formatNonPaginatedResults(namespace, result, resolvedParams.limit, hasUserSpecifiedLimit, shouldUseJson);
171
+ formatNonPaginatedResults(result, resolvedParams.limit, hasUserSpecifiedLimit, shouldUseJson, schema, sdkMethodName);
179
172
  }
180
173
  else if (hasOutputFile) {
181
174
  // Show success message for file output instead of printing generated content
182
- console.log(chalk_1.default.green(`āœ… ${method} completed successfully!`));
175
+ console.log(chalk_1.default.green(`āœ… ${cliCommandName} completed successfully!`));
183
176
  console.log(chalk_1.default.gray(`Output written to: ${resolvedParams.output}`));
184
177
  }
185
178
  }
186
179
  }
187
180
  catch (error) {
188
- console.error("Error:", error instanceof Error ? error.message : "Unknown error");
181
+ // Handle Zod validation errors more gracefully
182
+ if (error instanceof Error && error.message.includes('"code"')) {
183
+ try {
184
+ const validationErrors = JSON.parse(error.message);
185
+ console.error(chalk_1.default.red("āŒ Validation Error:"));
186
+ validationErrors.forEach((err) => {
187
+ const field = err.path?.join(".") || "unknown";
188
+ console.error(chalk_1.default.yellow(` • ${field}: ${err.message}`));
189
+ });
190
+ console.error("\n" + chalk_1.default.dim(`Use --help to see available options`));
191
+ }
192
+ catch {
193
+ console.error(chalk_1.default.red("Error:"), error.message);
194
+ }
195
+ }
196
+ else {
197
+ console.error(chalk_1.default.red("Error:"), error instanceof Error ? error.message : "Unknown error");
198
+ }
189
199
  process.exit(1);
190
200
  }
191
201
  };
@@ -195,23 +205,27 @@ function createCommandConfig(namespace, method, schema, sdk) {
195
205
  handler,
196
206
  };
197
207
  }
198
- function addSubCommand(parentCommand, name, config) {
199
- const command = parentCommand.command(name).description(config.description);
208
+ function addCommand(program, commandName, config) {
209
+ const command = program.command(commandName).description(config.description);
200
210
  // Add parameters to command
201
211
  config.parameters.forEach((param) => {
202
- if (param.resolverMeta?.resolver && param.required) {
212
+ // Convert camelCase to kebab-case for CLI display
213
+ const kebabName = param.name.replace(/([A-Z])/g, "-$1").toLowerCase();
214
+ if (param.hasResolver && param.required) {
203
215
  // Required parameters with resolvers become optional positional arguments (resolver handles prompting)
204
- command.argument(`[${param.name}]`, param.description || `${param.name} parameter`);
216
+ command.argument(`[${kebabName}]`, param.description || `${kebabName} parameter`);
205
217
  }
206
218
  else if (param.required) {
207
219
  // Required parameters without resolvers become required positional arguments
208
- command.argument(`<${param.name}>`, param.description || `${param.name} parameter`);
220
+ command.argument(`<${kebabName}>`, param.description || `${kebabName} parameter`);
221
+ }
222
+ else if (param.isPositional) {
223
+ // Optional parameters marked as positional become optional positional arguments
224
+ command.argument(`[${kebabName}]`, param.description || `${kebabName} parameter`);
209
225
  }
210
226
  else {
211
227
  // Optional parameters become flags (whether they have resolvers or not)
212
- const flags = [
213
- `--${param.name.replace(/([A-Z])/g, "-$1").toLowerCase()}`,
214
- ];
228
+ const flags = [`--${kebabName}`];
215
229
  if (param.type === "boolean") {
216
230
  command.option(flags.join(", "), param.description);
217
231
  }
@@ -230,10 +244,12 @@ function addSubCommand(parentCommand, name, config) {
230
244
  // ============================================================================
231
245
  function convertCliArgsToSdkParams(parameters, positionalArgs, options) {
232
246
  const sdkParams = {};
233
- // Handle positional arguments (required parameters only, whether they have resolvers or not)
247
+ // Handle positional arguments (required parameters or optional positional parameters)
234
248
  let argIndex = 0;
235
249
  parameters.forEach((param) => {
236
- if (param.required && argIndex < positionalArgs.length) {
250
+ if ((param.required || param.isPositional) &&
251
+ argIndex < positionalArgs.length) {
252
+ // Use the original camelCase parameter name for the SDK
237
253
  sdkParams[param.name] = convertValue(positionalArgs[argIndex], param.type);
238
254
  argIndex++;
239
255
  }
@@ -275,9 +291,9 @@ function convertValue(value, type) {
275
291
  // ============================================================================
276
292
  // Pagination Handlers
277
293
  // ============================================================================
278
- async function handlePaginatedList(namespace, method, baseParams, sdk) {
294
+ async function handlePaginatedList(sdkMethodName, baseParams, sdk, schema) {
279
295
  const limit = baseParams.limit || 20;
280
- const itemName = getItemName(namespace);
296
+ const itemName = getItemNameFromMethod(sdkMethodName);
281
297
  console.log(chalk_1.default.blue(`šŸ“‹ Fetching ${itemName}...`));
282
298
  const pager = (0, pager_1.createPager)({
283
299
  pageSize: Math.min(limit, 20),
@@ -288,18 +304,14 @@ async function handlePaginatedList(namespace, method, baseParams, sdk) {
288
304
  if (items.length > 0) {
289
305
  console.clear();
290
306
  }
291
- console.log(chalk_1.default.blue(`šŸ“‹ ${getListTitle(namespace)}\n`));
307
+ console.log(chalk_1.default.blue(`šŸ“‹ ${getListTitleFromMethod(sdkMethodName)}\n`));
292
308
  if (items.length === 0) {
293
309
  console.log(chalk_1.default.yellow(`No ${itemName} found.`));
294
310
  return;
295
311
  }
296
- // Get the schema for this namespace/method to extract formatting info
297
- const schema = zapier_sdk_1.SdkSchemas[namespace];
298
- const listSchema = schema && typeof schema === "object" && "list" in schema
299
- ? schema.list
300
- : null;
301
- if (listSchema) {
302
- (0, schema_formatter_1.formatItemsFromSchema)(listSchema, items);
312
+ // Use schema for formatting
313
+ if (schema) {
314
+ (0, schema_formatter_1.formatItemsFromSchema)(schema, items);
303
315
  }
304
316
  else {
305
317
  // Fallback to generic formatting
@@ -310,12 +322,12 @@ async function handlePaginatedList(namespace, method, baseParams, sdk) {
310
322
  : "";
311
323
  console.log(chalk_1.default.green(`\nāœ… Showing ${totalShown}${totalInfo} ${itemName}`));
312
324
  };
313
- await pager.paginate((params) => sdk[namespace][method]({
325
+ await pager.paginate((params) => sdk[sdkMethodName]({
314
326
  ...baseParams,
315
327
  ...params,
316
328
  }), {}, displayFunction);
317
329
  }
318
- function formatNonPaginatedResults(namespace, result, requestedLimit, userSpecifiedLimit, useRawJson) {
330
+ function formatNonPaginatedResults(result, requestedLimit, userSpecifiedLimit, useRawJson, schema, methodName) {
319
331
  if (!Array.isArray(result)) {
320
332
  if (useRawJson) {
321
333
  console.log(JSON.stringify(result, null, 2));
@@ -329,19 +341,15 @@ function formatNonPaginatedResults(namespace, result, requestedLimit, userSpecif
329
341
  console.log(JSON.stringify(result, null, 2));
330
342
  return;
331
343
  }
332
- const itemName = getItemName(namespace);
344
+ const itemName = methodName ? getItemNameFromMethod(methodName) : "items";
333
345
  if (result.length === 0) {
334
346
  console.log(chalk_1.default.yellow(`No ${itemName} found.`));
335
347
  return;
336
348
  }
337
349
  console.log(chalk_1.default.green(`\nāœ… Found ${result.length} ${itemName}:\n`));
338
- // Get the schema for this namespace/method to extract formatting info
339
- const schema = zapier_sdk_1.SdkSchemas[namespace];
340
- const listSchema = schema && typeof schema === "object" && "list" in schema
341
- ? schema.list
342
- : null;
343
- if (listSchema) {
344
- (0, schema_formatter_1.formatItemsFromSchema)(listSchema, result);
350
+ // Use schema for formatting
351
+ if (schema) {
352
+ (0, schema_formatter_1.formatItemsFromSchema)(schema, result);
345
353
  }
346
354
  else {
347
355
  // Fallback to generic formatting
@@ -366,49 +374,21 @@ function formatItemsGeneric(items) {
366
374
  console.log();
367
375
  });
368
376
  }
369
- function getItemName(namespace) {
370
- switch (namespace) {
371
- case "apps":
372
- return "apps";
373
- case "actions":
374
- return "actions";
375
- case "auths":
376
- return "authentications";
377
- case "fields":
378
- return "fields";
379
- default:
380
- return "items";
381
- }
382
- }
383
- function getListTitle(namespace) {
384
- switch (namespace) {
385
- case "apps":
386
- return "Available Apps";
387
- case "actions":
388
- return "Available Actions";
389
- case "auths":
390
- return "Available Authentications";
391
- case "fields":
392
- return "Available Fields";
393
- default:
394
- return "Available Items";
377
+ // Generic helper functions that infer from schema description or method name
378
+ function getItemNameFromMethod(methodName) {
379
+ // Extract from method name: listApps -> apps, listActions -> actions
380
+ const listMatch = methodName.match(/^list(.+)$/);
381
+ if (listMatch) {
382
+ return listMatch[1].toLowerCase();
395
383
  }
384
+ // Fallback to generic
385
+ return "items";
396
386
  }
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
- });
387
+ function getListTitleFromMethod(methodName) {
388
+ const itemName = getItemNameFromMethod(methodName);
389
+ if (itemName === "items")
390
+ return "Available Items";
391
+ // Capitalize first letter: apps -> Apps
392
+ const capitalized = itemName.charAt(0).toUpperCase() + itemName.slice(1);
393
+ return `Available ${capitalized}`;
414
394
  }
@@ -1,18 +1,13 @@
1
1
  import { z } from "zod";
2
- import { ActionsSdk } from "@zapier/zapier-sdk";
2
+ import { ZapierSdk } from "@zapier/zapier-sdk";
3
3
  export declare class SchemaParameterResolver {
4
- resolveParameters(schema: z.ZodSchema, providedParams: any, sdk: ActionsSdk): Promise<any>;
5
- private findAllResolvableParameters;
6
- private findResolvableParameters;
7
- private analyzeSchema;
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
  }