@zapier/zapier-sdk-cli 0.8.4 → 0.10.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.
Files changed (54) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +35 -51
  3. package/dist/cli.cjs +950 -433
  4. package/dist/cli.mjs +951 -434
  5. package/dist/index.cjs +729 -336
  6. package/dist/index.mjs +730 -337
  7. package/dist/package.json +1 -1
  8. package/dist/src/plugins/add/ast-generator.d.ts +37 -0
  9. package/dist/src/plugins/add/ast-generator.js +403 -0
  10. package/dist/src/plugins/add/index.d.ts +13 -0
  11. package/dist/src/plugins/add/index.js +120 -0
  12. package/dist/src/plugins/add/schemas.d.ts +18 -0
  13. package/dist/src/plugins/add/schemas.js +19 -0
  14. package/dist/src/plugins/getLoginConfigPath/index.d.ts +15 -0
  15. package/dist/src/plugins/getLoginConfigPath/index.js +19 -0
  16. package/dist/src/plugins/getLoginConfigPath/schemas.d.ts +3 -0
  17. package/dist/src/plugins/getLoginConfigPath/schemas.js +5 -0
  18. package/dist/src/plugins/index.d.ts +2 -2
  19. package/dist/src/plugins/index.js +2 -2
  20. package/dist/src/sdk.js +3 -3
  21. package/dist/src/utils/cli-generator-utils.d.ts +2 -1
  22. package/dist/src/utils/cli-generator-utils.js +11 -5
  23. package/dist/src/utils/cli-generator.js +65 -65
  24. package/dist/src/utils/parameter-resolver.d.ts +4 -1
  25. package/dist/src/utils/parameter-resolver.js +92 -15
  26. package/dist/src/utils/schema-formatter.d.ts +5 -1
  27. package/dist/src/utils/schema-formatter.js +48 -18
  28. package/dist/tsconfig.tsbuildinfo +1 -1
  29. package/package.json +4 -4
  30. package/src/plugins/add/ast-generator.ts +777 -0
  31. package/src/plugins/add/index.test.ts +58 -0
  32. package/src/plugins/add/index.ts +187 -0
  33. package/src/plugins/add/schemas.ts +26 -0
  34. package/src/plugins/getLoginConfigPath/index.ts +45 -0
  35. package/src/plugins/getLoginConfigPath/schemas.ts +10 -0
  36. package/src/plugins/index.ts +2 -2
  37. package/src/sdk.ts +4 -4
  38. package/src/utils/cli-generator-utils.ts +17 -5
  39. package/src/utils/cli-generator.ts +90 -79
  40. package/src/utils/parameter-resolver.ts +155 -21
  41. package/src/utils/schema-formatter.ts +68 -33
  42. package/tsup.config.ts +1 -1
  43. package/dist/src/plugins/generateTypes/index.d.ts +0 -21
  44. package/dist/src/plugins/generateTypes/index.js +0 -312
  45. package/dist/src/plugins/generateTypes/schemas.d.ts +0 -18
  46. package/dist/src/plugins/generateTypes/schemas.js +0 -14
  47. package/dist/src/plugins/getConfigPath/index.d.ts +0 -15
  48. package/dist/src/plugins/getConfigPath/index.js +0 -19
  49. package/dist/src/plugins/getConfigPath/schemas.d.ts +0 -3
  50. package/dist/src/plugins/getConfigPath/schemas.js +0 -5
  51. package/src/plugins/generateTypes/index.ts +0 -444
  52. package/src/plugins/generateTypes/schemas.ts +0 -23
  53. package/src/plugins/getConfigPath/index.ts +0 -42
  54. package/src/plugins/getConfigPath/schemas.ts +0 -8
@@ -2,45 +2,16 @@ import type { Command } from "commander";
2
2
  import { z } from "zod";
3
3
  import type { ZapierSdk } from "@zapier/zapier-sdk";
4
4
  import {
5
- hasResolver,
6
5
  isPositional,
7
6
  formatErrorMessage,
8
7
  ZapierError,
8
+ type FunctionRegistryEntry,
9
9
  } from "@zapier/zapier-sdk";
10
10
  import { SchemaParameterResolver } from "./parameter-resolver";
11
- import { formatItemsFromSchema } from "./schema-formatter";
11
+ import { formatItemsFromSchema, formatJsonOutput } from "./schema-formatter";
12
12
  import chalk from "chalk";
13
- import util from "util";
14
13
  import inquirer from "inquirer";
15
14
 
16
- // ============================================================================
17
- // JSON Formatting
18
- // ============================================================================
19
-
20
- function formatJsonOutput(data: unknown): void {
21
- // Don't print anything for undefined results (commands that just perform actions)
22
- if (data === undefined) {
23
- return;
24
- }
25
-
26
- // Show success message for action results
27
- if (
28
- data &&
29
- typeof data === "object" &&
30
- !Array.isArray(data) &&
31
- ((data as Record<string, unknown>).success !== undefined ||
32
- (data as Record<string, unknown>).id ||
33
- (data as Record<string, unknown>).status)
34
- ) {
35
- console.log(chalk.green("✅ Action completed successfully!\n"));
36
- }
37
-
38
- // Use util.inspect for colored output
39
- console.log(
40
- util.inspect(data, { colors: true, depth: null, breakLength: 80 }),
41
- );
42
- }
43
-
44
15
  // ============================================================================
45
16
  // Types
46
17
  // ============================================================================
@@ -66,7 +37,10 @@ interface CliParameter {
66
37
  // Schema Analysis
67
38
  // ============================================================================
68
39
 
69
- function analyzeZodSchema(schema: z.ZodSchema): CliParameter[] {
40
+ function analyzeZodSchema(
41
+ schema: z.ZodSchema,
42
+ functionInfo?: FunctionRegistryEntry,
43
+ ): CliParameter[] {
70
44
  const parameters: CliParameter[] = [];
71
45
 
72
46
  // Handle ZodEffects (schemas with .refine(), .transform(), etc.)
@@ -78,14 +52,18 @@ function analyzeZodSchema(schema: z.ZodSchema): CliParameter[] {
78
52
  // Get the underlying schema
79
53
  const innerSchema = (schema as unknown as { _def: { schema: z.ZodSchema } })
80
54
  ._def.schema;
81
- return analyzeZodSchema(innerSchema);
55
+ return analyzeZodSchema(innerSchema, functionInfo);
82
56
  }
83
57
 
84
58
  if (schema instanceof z.ZodObject) {
85
59
  const shape = schema.shape;
86
60
 
87
61
  for (const [key, fieldSchema] of Object.entries(shape)) {
88
- const param = analyzeZodField(key, fieldSchema as z.ZodSchema);
62
+ const param = analyzeZodField(
63
+ key,
64
+ fieldSchema as z.ZodSchema,
65
+ functionInfo,
66
+ );
89
67
  if (param) {
90
68
  parameters.push(param);
91
69
  }
@@ -98,6 +76,7 @@ function analyzeZodSchema(schema: z.ZodSchema): CliParameter[] {
98
76
  function analyzeZodField(
99
77
  name: string,
100
78
  schema: z.ZodSchema,
79
+ functionInfo?: FunctionRegistryEntry,
101
80
  ): CliParameter | null {
102
81
  let baseSchema = schema;
103
82
  let required = true;
@@ -150,6 +129,14 @@ function analyzeZodField(
150
129
  paramType = "string";
151
130
  }
152
131
 
132
+ // Check if this parameter has a resolver
133
+ let paramHasResolver = false;
134
+
135
+ // Check function-specific resolvers first
136
+ if (functionInfo?.resolvers?.[name]) {
137
+ paramHasResolver = true;
138
+ }
139
+
153
140
  // Extract resolver metadata
154
141
  return {
155
142
  name,
@@ -158,7 +145,7 @@ function analyzeZodField(
158
145
  description: schema.description,
159
146
  default: defaultValue,
160
147
  choices,
161
- hasResolver: hasResolver(name),
148
+ hasResolver: paramHasResolver,
162
149
  isPositional: isPositional(schema),
163
150
  };
164
151
  }
@@ -206,12 +193,7 @@ export function generateCliCommands(program: Command, sdk: ZapierSdk): void {
206
193
  // Convert methodName to kebab-case CLI command
207
194
  const cliCommandName = methodNameToCliCommand(fnInfo.name);
208
195
 
209
- const config = createCommandConfig(
210
- cliCommandName,
211
- fnInfo.name,
212
- fnInfo.inputSchema as z.ZodSchema,
213
- sdk,
214
- );
196
+ const config = createCommandConfig(cliCommandName, fnInfo, sdk);
215
197
 
216
198
  addCommand(program, cliCommandName, config);
217
199
  });
@@ -288,11 +270,11 @@ export function generateCliCommands(program: Command, sdk: ZapierSdk): void {
288
270
 
289
271
  function createCommandConfig(
290
272
  cliCommandName: string,
291
- sdkMethodName: string,
292
- schema: z.ZodSchema,
273
+ functionInfo: FunctionRegistryEntry,
293
274
  sdk: ZapierSdk,
294
275
  ): CliCommandConfig {
295
- const parameters = analyzeZodSchema(schema);
276
+ const schema = functionInfo.inputSchema as z.ZodSchema;
277
+ const parameters = analyzeZodSchema(schema, functionInfo);
296
278
  const description = schema.description || `${cliCommandName} command`;
297
279
 
298
280
  const handler = async (...args: unknown[]) => {
@@ -304,7 +286,7 @@ function createCommandConfig(
304
286
  const options = commandObj.opts();
305
287
 
306
288
  // Check if this is a list command for pagination
307
- const isListCommand = cliCommandName.startsWith("list-");
289
+ const isListCommand = functionInfo.type === "list";
308
290
  const hasPaginationParams = parameters.some(
309
291
  (p) => p.name === "maxItems" || p.name === "pageSize",
310
292
  );
@@ -325,6 +307,7 @@ function createCommandConfig(
325
307
  schema,
326
308
  rawParams,
327
309
  sdk,
310
+ functionInfo.name,
328
311
  );
329
312
 
330
313
  // Handle paginated list commands with async iteration
@@ -339,11 +322,11 @@ function createCommandConfig(
339
322
  string,
340
323
  (params: unknown) => Promise<unknown> & AsyncIterable<unknown>
341
324
  >;
342
- const sdkIterator = sdkObj[sdkMethodName](resolvedParams);
325
+ const sdkIterator = sdkObj[functionInfo.name](resolvedParams);
343
326
  await handlePaginatedListWithAsyncIteration(
344
- sdkMethodName,
327
+ functionInfo.name,
345
328
  sdkIterator,
346
- schema,
329
+ functionInfo,
347
330
  );
348
331
  } else {
349
332
  // Special handling for commands that write to files
@@ -354,7 +337,7 @@ function createCommandConfig(
354
337
  string,
355
338
  (params: unknown) => Promise<unknown>
356
339
  >;
357
- await sdkObj[sdkMethodName](resolvedParams);
340
+ await sdkObj[functionInfo.name](resolvedParams);
358
341
  console.log(
359
342
  chalk.green(`✅ ${cliCommandName} completed successfully!`),
360
343
  );
@@ -367,7 +350,7 @@ function createCommandConfig(
367
350
  string,
368
351
  (params: unknown) => Promise<unknown>
369
352
  >;
370
- const result: unknown = await sdkObj[sdkMethodName](resolvedParams);
353
+ const result: unknown = await sdkObj[functionInfo.name](resolvedParams);
371
354
  const items = (result as { data?: unknown })?.data
372
355
  ? (result as { data: unknown }).data
373
356
  : result;
@@ -380,8 +363,7 @@ function createCommandConfig(
380
363
  (resolvedParams as { maxItems?: number }).maxItems,
381
364
  hasUserSpecifiedMaxItems,
382
365
  shouldUseJson as boolean,
383
- schema,
384
- sdkMethodName,
366
+ functionInfo,
385
367
  );
386
368
  } else {
387
369
  formatJsonOutput(items);
@@ -436,6 +418,9 @@ function addCommand(
436
418
  ): void {
437
419
  const command = program.command(commandName).description(config.description);
438
420
 
421
+ // Track whether we've already used a positional array parameter
422
+ let hasPositionalArray = false;
423
+
439
424
  // Add parameters to command
440
425
  config.parameters.forEach((param) => {
441
426
  // Convert camelCase to kebab-case for CLI display
@@ -447,6 +432,25 @@ function addCommand(
447
432
  `[${kebabName}]`,
448
433
  param.description || `${kebabName} parameter`,
449
434
  );
435
+ } else if (
436
+ param.required &&
437
+ param.type === "array" &&
438
+ !hasPositionalArray
439
+ ) {
440
+ // First required array parameter becomes a variadic positional argument
441
+ hasPositionalArray = true;
442
+ command.argument(
443
+ `<${kebabName}...>`,
444
+ param.description || `${kebabName} parameter`,
445
+ );
446
+ } else if (param.required && param.type === "array") {
447
+ // Subsequent required array parameters become required flags
448
+ const flags = [`--${kebabName}`];
449
+ const flagSignature = flags.join(", ") + ` <values...>`;
450
+ command.requiredOption(
451
+ flagSignature,
452
+ param.description || `${kebabName} parameter (required)`,
453
+ );
450
454
  } else if (param.required) {
451
455
  // Required parameters without resolvers become required positional arguments
452
456
  command.argument(
@@ -532,6 +536,11 @@ function convertCliArgsToSdkParams(
532
536
  }
533
537
 
534
538
  function convertValue(value: unknown, type: CliParameter["type"]): unknown {
539
+ // Don't convert undefined values - let the resolver system handle them
540
+ if (value === undefined) {
541
+ return undefined;
542
+ }
543
+
535
544
  switch (type) {
536
545
  case "number":
537
546
  return Number(value);
@@ -563,13 +572,15 @@ function convertValue(value: unknown, type: CliParameter["type"]): unknown {
563
572
  async function handlePaginatedListWithAsyncIteration(
564
573
  sdkMethodName: string,
565
574
  sdkResult: unknown,
566
- schema: z.ZodSchema,
575
+ functionInfo: FunctionRegistryEntry,
567
576
  ): Promise<void> {
568
- const itemName = getItemNameFromMethod(sdkMethodName);
577
+ const itemName = getItemNameFromMethod(functionInfo);
569
578
  let totalShown = 0;
570
579
  let pageCount = 0;
571
580
 
572
- console.log(chalk.blue(`📋 ${getListTitleFromMethod(sdkMethodName)}\n`));
581
+ console.log(
582
+ chalk.blue(`📋 ${getListTitleFromMethod(sdkMethodName, functionInfo)}\n`),
583
+ );
573
584
 
574
585
  try {
575
586
  // Use async iteration to go through pages
@@ -598,13 +609,15 @@ async function handlePaginatedListWithAsyncIteration(
598
609
  if (pageCount > 1) {
599
610
  console.clear();
600
611
  console.log(
601
- chalk.blue(`📋 ${getListTitleFromMethod(sdkMethodName)}\n`),
612
+ chalk.blue(
613
+ `📋 ${getListTitleFromMethod(sdkMethodName, functionInfo)}\n`,
614
+ ),
602
615
  );
603
616
  }
604
617
 
605
- // Format and display items using schema
606
- if (schema) {
607
- formatItemsFromSchema(schema as z.ZodType, items, totalShown);
618
+ // Format and display items using function info
619
+ if (functionInfo) {
620
+ formatItemsFromSchema(functionInfo, items, totalShown);
608
621
  } else {
609
622
  formatItemsGeneric(items, totalShown);
610
623
  }
@@ -646,8 +659,8 @@ async function handlePaginatedListWithAsyncIteration(
646
659
  return;
647
660
  }
648
661
 
649
- if (schema) {
650
- formatItemsFromSchema(schema as z.ZodType, items, 0);
662
+ if (functionInfo) {
663
+ formatItemsFromSchema(functionInfo, items, 0);
651
664
  } else {
652
665
  formatItemsGeneric(items, 0);
653
666
  }
@@ -664,8 +677,7 @@ function formatNonPaginatedResults(
664
677
  requestedMaxItems?: number,
665
678
  userSpecifiedMaxItems?: boolean,
666
679
  useRawJson?: boolean,
667
- schema?: z.ZodSchema,
668
- methodName?: string,
680
+ functionInfo?: FunctionRegistryEntry,
669
681
  ): void {
670
682
  if (!Array.isArray(result)) {
671
683
  if (useRawJson) {
@@ -681,7 +693,7 @@ function formatNonPaginatedResults(
681
693
  return;
682
694
  }
683
695
 
684
- const itemName = methodName ? getItemNameFromMethod(methodName) : "items";
696
+ const itemName = functionInfo ? getItemNameFromMethod(functionInfo) : "items";
685
697
 
686
698
  if (result.length === 0) {
687
699
  console.log(chalk.yellow(`No ${itemName} found.`));
@@ -690,9 +702,9 @@ function formatNonPaginatedResults(
690
702
 
691
703
  console.log(chalk.green(`\n✅ Found ${result.length} ${itemName}:\n`));
692
704
 
693
- // Use schema for formatting
694
- if (schema) {
695
- formatItemsFromSchema(schema as z.ZodType, result);
705
+ // Use function info for formatting
706
+ if (functionInfo) {
707
+ formatItemsFromSchema(functionInfo, result);
696
708
  } else {
697
709
  // Fallback to generic formatting
698
710
  formatItemsGeneric(result);
@@ -729,22 +741,21 @@ function formatItemsGeneric(
729
741
  }
730
742
 
731
743
  // Generic helper functions that infer from schema description or method name
732
- function getItemNameFromMethod(methodName: string): string {
733
- // Extract from method name: listApps -> apps, listActions -> actions
734
- const listMatch = methodName.match(/^list(.+)$/);
735
- if (listMatch) {
736
- return listMatch[1].toLowerCase();
744
+ function getItemNameFromMethod(functionInfo: FunctionRegistryEntry): string {
745
+ if (functionInfo.itemType) {
746
+ return `${functionInfo.itemType} items`;
737
747
  }
738
748
 
739
- // Fallback to generic
740
749
  return "items";
741
750
  }
742
751
 
743
- function getListTitleFromMethod(methodName: string): string {
744
- const itemName = getItemNameFromMethod(methodName);
745
- if (itemName === "items") return "Available Items";
752
+ function getListTitleFromMethod(
753
+ methodName: string,
754
+ functionInfo: FunctionRegistryEntry,
755
+ ): string {
756
+ if (functionInfo.itemType) {
757
+ return `Available ${functionInfo.itemType} items`;
758
+ }
746
759
 
747
- // Capitalize first letter: apps -> Apps
748
- const capitalized = itemName.charAt(0).toUpperCase() + itemName.slice(1);
749
- return `Available ${capitalized}`;
760
+ return `${methodName} items`;
750
761
  }
@@ -2,11 +2,6 @@ import inquirer from "inquirer";
2
2
  import chalk from "chalk";
3
3
  import { z } from "zod";
4
4
  import type { ZapierSdk } from "@zapier/zapier-sdk";
5
- import {
6
- getResolver,
7
- hasResolver,
8
- getResolutionOrderForParams,
9
- } from "@zapier/zapier-sdk";
10
5
 
11
6
  // ============================================================================
12
7
  // Types
@@ -24,6 +19,66 @@ interface ResolverContext {
24
19
  sdk: ZapierSdk;
25
20
  currentParams: Record<string, unknown>;
26
21
  resolvedParams: Record<string, unknown>;
22
+ functionName?: string;
23
+ }
24
+
25
+ // ============================================================================
26
+ // Local Resolution Helper Functions
27
+ // ============================================================================
28
+
29
+ /**
30
+ * Resolve dependency chain for a parameter using local resolvers
31
+ * Returns parameters in the order they need to be resolved
32
+ */
33
+ function getLocalResolutionOrder(
34
+ paramName: string,
35
+ resolvers: Record<string, any>,
36
+ resolved: Set<string> = new Set(),
37
+ ): string[] {
38
+ const resolver = resolvers[paramName];
39
+ if (!resolver || resolver.type === "static") {
40
+ return [paramName];
41
+ }
42
+
43
+ const order: string[] = [];
44
+
45
+ if ("depends" in resolver && resolver.depends) {
46
+ for (const dependency of resolver.depends) {
47
+ if (!resolved.has(dependency)) {
48
+ order.push(...getLocalResolutionOrder(dependency, resolvers, resolved));
49
+ resolved.add(dependency);
50
+ }
51
+ }
52
+ }
53
+
54
+ if (!resolved.has(paramName)) {
55
+ order.push(paramName);
56
+ resolved.add(paramName);
57
+ }
58
+
59
+ return order;
60
+ }
61
+
62
+ /**
63
+ * Get resolution order for multiple parameters using local resolvers
64
+ */
65
+ function getLocalResolutionOrderForParams(
66
+ paramNames: string[],
67
+ resolvers: Record<string, any>,
68
+ ): string[] {
69
+ const resolved = new Set<string>();
70
+ const order: string[] = [];
71
+
72
+ for (const paramName of paramNames) {
73
+ const paramOrder = getLocalResolutionOrder(paramName, resolvers, resolved);
74
+ for (const param of paramOrder) {
75
+ if (!order.includes(param)) {
76
+ order.push(param);
77
+ }
78
+ }
79
+ }
80
+
81
+ return order;
27
82
  }
28
83
 
29
84
  // ============================================================================
@@ -35,6 +90,7 @@ export class SchemaParameterResolver {
35
90
  schema: z.ZodSchema,
36
91
  providedParams: unknown,
37
92
  sdk: ZapierSdk,
93
+ functionName?: string,
38
94
  ): Promise<unknown> {
39
95
  // 1. Try to parse with current parameters
40
96
  const parseResult = schema.safeParse(providedParams);
@@ -42,7 +98,7 @@ export class SchemaParameterResolver {
42
98
  // Get all schema parameters to check which ones have resolvers
43
99
  const allParams = this.extractParametersFromSchema(schema);
44
100
  const resolvableParams = allParams.filter((param) =>
45
- hasResolver(param.name),
101
+ this.hasResolver(param.name, sdk, functionName),
46
102
  );
47
103
 
48
104
  // Get all missing parameters that have resolvers
@@ -108,12 +164,18 @@ export class SchemaParameterResolver {
108
164
  sdk,
109
165
  currentParams: providedParams as Record<string, unknown>,
110
166
  resolvedParams,
167
+ functionName,
111
168
  };
112
169
 
170
+ // Get local resolvers for this function
171
+ const localResolvers = this.getLocalResolvers(sdk, functionName);
172
+
113
173
  if (functionallyRequired.length > 0) {
114
174
  const requiredParamNames = functionallyRequired.map((p) => p.name);
115
- const requiredResolutionOrder =
116
- getResolutionOrderForParams(requiredParamNames);
175
+ const requiredResolutionOrder = getLocalResolutionOrderForParams(
176
+ requiredParamNames,
177
+ localResolvers,
178
+ );
117
179
 
118
180
  // Find all parameters that need to be resolved (including dependencies)
119
181
  // from the available resolvable parameters
@@ -135,7 +197,11 @@ export class SchemaParameterResolver {
135
197
 
136
198
  for (const param of orderedRequiredParams) {
137
199
  try {
138
- const value = await this.resolveParameter(param, context);
200
+ const value = await this.resolveParameter(
201
+ param,
202
+ context,
203
+ functionName,
204
+ );
139
205
  this.setNestedValue(resolvedParams, param.path, value);
140
206
 
141
207
  // Update context with newly resolved value
@@ -168,8 +234,10 @@ export class SchemaParameterResolver {
168
234
  // 3. Resolve parameters that should always be prompted for (but can be skipped)
169
235
  if (alwaysPrompt.length > 0) {
170
236
  const alwaysPromptNames = alwaysPrompt.map((p) => p.name);
171
- const alwaysPromptResolutionOrder =
172
- getResolutionOrderForParams(alwaysPromptNames);
237
+ const alwaysPromptResolutionOrder = getLocalResolutionOrderForParams(
238
+ alwaysPromptNames,
239
+ localResolvers,
240
+ );
173
241
 
174
242
  const orderedAlwaysPromptParams = alwaysPromptResolutionOrder
175
243
  .map((paramName) => alwaysPrompt.find((p) => p.name === paramName))
@@ -177,7 +245,11 @@ export class SchemaParameterResolver {
177
245
 
178
246
  for (const param of orderedAlwaysPromptParams) {
179
247
  try {
180
- const value = await this.resolveParameter(param, context);
248
+ const value = await this.resolveParameter(
249
+ param,
250
+ context,
251
+ functionName,
252
+ );
181
253
  this.setNestedValue(resolvedParams, param.path, value);
182
254
 
183
255
  // Update context with newly resolved value
@@ -207,8 +279,10 @@ export class SchemaParameterResolver {
207
279
  if (shouldResolveOptional.resolveOptional) {
208
280
  // Resolve optional parameters using their resolvers
209
281
  const optionalParamNames = trulyOptional.map((p) => p.name);
210
- const optionalResolutionOrder =
211
- getResolutionOrderForParams(optionalParamNames);
282
+ const optionalResolutionOrder = getLocalResolutionOrderForParams(
283
+ optionalParamNames,
284
+ localResolvers,
285
+ );
212
286
 
213
287
  const orderedOptionalParams = optionalResolutionOrder
214
288
  .map((paramName) => trulyOptional.find((p) => p.name === paramName))
@@ -216,7 +290,11 @@ export class SchemaParameterResolver {
216
290
 
217
291
  for (const param of orderedOptionalParams) {
218
292
  try {
219
- const value = await this.resolveParameter(param, context);
293
+ const value = await this.resolveParameter(
294
+ param,
295
+ context,
296
+ functionName,
297
+ );
220
298
  this.setNestedValue(resolvedParams, param.path, value);
221
299
 
222
300
  // Update context with newly resolved value
@@ -306,8 +384,9 @@ export class SchemaParameterResolver {
306
384
  private async resolveParameter(
307
385
  param: ResolvableParameter,
308
386
  context: ResolverContext,
387
+ functionName?: string,
309
388
  ): Promise<unknown> {
310
- const resolver = getResolver(param.name);
389
+ const resolver = this.getResolver(param.name, context.sdk, functionName);
311
390
  if (!resolver) {
312
391
  throw new Error(`No resolver found for parameter: ${param.name}`);
313
392
  }
@@ -430,10 +509,10 @@ export class SchemaParameterResolver {
430
509
 
431
510
  // Separate new required and optional fields
432
511
  const newRequiredFields = newFields.filter(
433
- (field: unknown) => (field as { required: boolean }).required,
512
+ (field: unknown) => (field as { is_required: boolean }).is_required,
434
513
  );
435
514
  const newOptionalFields = newFields.filter(
436
- (field: unknown) => !(field as { required: boolean }).required,
515
+ (field: unknown) => !(field as { is_required: boolean }).is_required,
437
516
  );
438
517
 
439
518
  // Prompt for new required fields
@@ -536,7 +615,7 @@ export class SchemaParameterResolver {
536
615
  type?: string;
537
616
  key: string;
538
617
  label?: string;
539
- required?: boolean;
618
+ is_required?: boolean;
540
619
  helpText?: string;
541
620
  default?: unknown;
542
621
  choices?: Array<{ label?: string; value: unknown }>;
@@ -545,7 +624,7 @@ export class SchemaParameterResolver {
545
624
  const fieldPrompt: Record<string, unknown> = {
546
625
  type: fieldObj.type === "boolean" ? "confirm" : "input",
547
626
  name: fieldObj.key,
548
- message: `${fieldObj.label || fieldObj.key}${fieldObj.required ? " (required)" : " (optional)"}:`,
627
+ message: `${fieldObj.label || fieldObj.key}${fieldObj.is_required ? " (required)" : " (optional)"}:`,
549
628
  };
550
629
 
551
630
  if (fieldObj.helpText) {
@@ -574,7 +653,7 @@ export class SchemaParameterResolver {
574
653
 
575
654
  if (answer[fieldObj.key] !== undefined && answer[fieldObj.key] !== "") {
576
655
  inputs[fieldObj.key] = answer[fieldObj.key];
577
- } else if (fieldObj.required) {
656
+ } else if (fieldObj.is_required) {
578
657
  throw new Error(`Required field ${fieldObj.key} cannot be empty`);
579
658
  }
580
659
  } catch (error) {
@@ -598,4 +677,59 @@ export class SchemaParameterResolver {
598
677
  errorObj?.isTTYError === true
599
678
  );
600
679
  }
680
+
681
+ private hasResolver(
682
+ paramName: string,
683
+ sdk: ZapierSdk,
684
+ functionName?: string,
685
+ ): boolean {
686
+ // Check plugin-specific resolvers first
687
+ if (functionName && typeof sdk.getRegistry === "function") {
688
+ const registry = sdk.getRegistry();
689
+ const functionInfo = registry.functions.find(
690
+ (f) => f.name === functionName,
691
+ );
692
+ if (functionInfo && functionInfo.resolvers?.[paramName]) {
693
+ return true;
694
+ }
695
+ }
696
+
697
+ // No global registry fallback
698
+ return false;
699
+ }
700
+
701
+ private getResolver(
702
+ paramName: string,
703
+ sdk: ZapierSdk,
704
+ functionName?: string,
705
+ ): any {
706
+ // Check plugin-specific resolvers first
707
+ if (functionName && typeof sdk.getRegistry === "function") {
708
+ const registry = sdk.getRegistry();
709
+ const functionInfo = registry.functions.find(
710
+ (f) => f.name === functionName,
711
+ );
712
+ if (functionInfo && functionInfo.resolvers?.[paramName]) {
713
+ return functionInfo.resolvers[paramName];
714
+ }
715
+ }
716
+
717
+ // No global registry fallback
718
+ return null;
719
+ }
720
+
721
+ private getLocalResolvers(
722
+ sdk: ZapierSdk,
723
+ functionName?: string,
724
+ ): Record<string, any> {
725
+ if (!functionName || typeof sdk.getRegistry !== "function") {
726
+ return {};
727
+ }
728
+
729
+ const registry = sdk.getRegistry();
730
+ const functionInfo = registry.functions.find(
731
+ (f) => f.name === functionName,
732
+ );
733
+ return functionInfo?.resolvers || {};
734
+ }
601
735
  }