@zapier/zapier-sdk-cli 0.35.1 → 0.36.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.cjs CHANGED
@@ -6,13 +6,14 @@ var zod = require('zod');
6
6
  var zapierSdk = require('@zapier/zapier-sdk');
7
7
  var inquirer = require('inquirer');
8
8
  var chalk7 = require('chalk');
9
+ var ora = require('ora');
9
10
  var util = require('util');
11
+ var wrapAnsi = require('wrap-ansi');
10
12
  var cliLogin = require('@zapier/zapier-sdk-cli-login');
11
13
  var open = require('open');
12
14
  var crypto = require('crypto');
13
15
  var express = require('express');
14
16
  var pkceChallenge = require('pkce-challenge');
15
- var ora = require('ora');
16
17
  var zapierSdkMcp = require('@zapier/zapier-sdk-mcp');
17
18
  var esbuild = require('esbuild');
18
19
  var fs = require('fs');
@@ -49,13 +50,14 @@ function _interopNamespace(e) {
49
50
 
50
51
  var inquirer__default = /*#__PURE__*/_interopDefault(inquirer);
51
52
  var chalk7__default = /*#__PURE__*/_interopDefault(chalk7);
53
+ var ora__default = /*#__PURE__*/_interopDefault(ora);
52
54
  var util__default = /*#__PURE__*/_interopDefault(util);
55
+ var wrapAnsi__default = /*#__PURE__*/_interopDefault(wrapAnsi);
53
56
  var cliLogin__namespace = /*#__PURE__*/_interopNamespace(cliLogin);
54
57
  var open__default = /*#__PURE__*/_interopDefault(open);
55
58
  var crypto__default = /*#__PURE__*/_interopDefault(crypto);
56
59
  var express__default = /*#__PURE__*/_interopDefault(express);
57
60
  var pkceChallenge__default = /*#__PURE__*/_interopDefault(pkceChallenge);
58
- var ora__default = /*#__PURE__*/_interopDefault(ora);
59
61
  var fs__namespace = /*#__PURE__*/_interopNamespace(fs);
60
62
  var path__namespace = /*#__PURE__*/_interopNamespace(path);
61
63
  var ts__namespace = /*#__PURE__*/_interopNamespace(ts);
@@ -143,9 +145,31 @@ function getLocalResolutionOrderForParams(paramNames, resolvers) {
143
145
  return order;
144
146
  }
145
147
  var SchemaParameterResolver = class {
148
+ constructor() {
149
+ this.debug = false;
150
+ this.spinner = null;
151
+ }
152
+ debugLog(message) {
153
+ if (this.debug) {
154
+ this.stopSpinner();
155
+ console.log(chalk7__default.default.gray(`[Zapier CLI] ${message}`));
156
+ }
157
+ }
158
+ startSpinner() {
159
+ if (!this.debug && !this.spinner) {
160
+ this.spinner = ora__default.default({ text: "", spinner: "dots" }).start();
161
+ }
162
+ }
163
+ stopSpinner() {
164
+ if (this.spinner) {
165
+ this.spinner.stop();
166
+ this.spinner = null;
167
+ }
168
+ }
146
169
  async resolveParameters(schema, providedParams, sdk2, functionName, options) {
147
170
  return zapierSdk.runWithTelemetryContext(async () => {
148
- const interactiveMode = options?.interactiveMode ?? true;
171
+ this.debug = options?.debug ?? false;
172
+ const interactiveMode = (options?.interactiveMode ?? true) && !!process.stdin.isTTY;
149
173
  const parseResult = schema.safeParse(providedParams);
150
174
  const allParams = this.extractParametersFromSchema(schema);
151
175
  const resolvableParams = allParams.filter(
@@ -155,27 +179,18 @@ var SchemaParameterResolver = class {
155
179
  const hasValue = this.getNestedValue(providedParams, param.path) !== void 0;
156
180
  return !hasValue;
157
181
  });
158
- const functionallyRequired = missingResolvable.filter((param) => {
182
+ const required = missingResolvable.filter((param) => {
159
183
  if (param.isRequired) return true;
160
- if (param.name === "inputs") {
161
- return interactiveMode;
162
- }
184
+ if (param.name === "inputs") return interactiveMode;
163
185
  return false;
164
186
  });
165
- const alwaysPrompt = missingResolvable.filter((param) => {
166
- if (functionallyRequired.includes(param)) return false;
167
- if (param.name === "connectionId") {
168
- return true;
169
- }
170
- return false;
171
- });
172
- const trulyOptional = missingResolvable.filter(
173
- (param) => !functionallyRequired.includes(param) && !alwaysPrompt.includes(param)
187
+ const optional = missingResolvable.filter(
188
+ (param) => !required.includes(param)
174
189
  );
175
- if (parseResult.success && functionallyRequired.length === 0 && alwaysPrompt.length === 0) {
190
+ if (parseResult.success && required.length === 0 && optional.length === 0) {
176
191
  return parseResult.data;
177
192
  }
178
- if (functionallyRequired.length === 0 && alwaysPrompt.length === 0) {
193
+ if (required.length === 0 && optional.length === 0) {
179
194
  if (!parseResult.success) {
180
195
  throw new ZapierCliValidationError(formatZodError(parseResult.error));
181
196
  }
@@ -189,19 +204,16 @@ var SchemaParameterResolver = class {
189
204
  functionName
190
205
  };
191
206
  const localResolvers = this.getLocalResolvers(sdk2, functionName);
192
- if (functionallyRequired.length > 0) {
193
- const requiredParamNames = functionallyRequired.map((p) => p.name);
207
+ if (required.length > 0) {
208
+ const requiredParamNames = required.map((p) => p.name);
194
209
  const requiredResolutionOrder = getLocalResolutionOrderForParams(
195
210
  requiredParamNames,
196
211
  localResolvers
197
212
  );
198
213
  const orderedRequiredParams = requiredResolutionOrder.map((paramName) => {
199
- let param = functionallyRequired.find((p) => p.name === paramName);
200
- if (!param) {
201
- param = alwaysPrompt.find((p) => p.name === paramName);
202
- }
214
+ let param = required.find((p) => p.name === paramName);
203
215
  if (!param) {
204
- param = trulyOptional.find((p) => p.name === paramName);
216
+ param = optional.find((p) => p.name === paramName);
205
217
  }
206
218
  return param;
207
219
  }).filter((param) => param !== void 0);
@@ -234,33 +246,31 @@ var SchemaParameterResolver = class {
234
246
  const resolvedParamNames = new Set(
235
247
  orderedRequiredParams.map((p) => p.name)
236
248
  );
237
- alwaysPrompt.splice(
238
- 0,
239
- alwaysPrompt.length,
240
- ...alwaysPrompt.filter((p) => !resolvedParamNames.has(p.name))
241
- );
242
- trulyOptional.splice(
249
+ optional.splice(
243
250
  0,
244
- trulyOptional.length,
245
- ...trulyOptional.filter((p) => !resolvedParamNames.has(p.name))
251
+ optional.length,
252
+ ...optional.filter((p) => !resolvedParamNames.has(p.name))
246
253
  );
247
254
  }
248
- if (interactiveMode && alwaysPrompt.length > 0) {
249
- const alwaysPromptNames = alwaysPrompt.map((p) => p.name);
250
- const alwaysPromptResolutionOrder = getLocalResolutionOrderForParams(
251
- alwaysPromptNames,
255
+ if (interactiveMode && optional.length > 0) {
256
+ const optionalParamNames = optional.map((p) => p.name);
257
+ const optionalResolutionOrder = getLocalResolutionOrderForParams(
258
+ optionalParamNames,
252
259
  localResolvers
253
260
  );
254
- const orderedAlwaysPromptParams = alwaysPromptResolutionOrder.map((paramName) => alwaysPrompt.find((p) => p.name === paramName)).filter((param) => param !== void 0);
255
- for (const param of orderedAlwaysPromptParams) {
261
+ const orderedOptionalParams = optionalResolutionOrder.map((paramName) => optional.find((p) => p.name === paramName)).filter((param) => param !== void 0);
262
+ for (const param of orderedOptionalParams) {
256
263
  try {
257
264
  const value = await this.resolveParameter(
258
265
  param,
259
266
  context,
260
- functionName
267
+ functionName,
268
+ { isOptional: true }
261
269
  );
262
- this.setNestedValue(resolvedParams, param.path, value);
263
- context.resolvedParams = resolvedParams;
270
+ if (value !== void 0) {
271
+ this.setNestedValue(resolvedParams, param.path, value);
272
+ context.resolvedParams = resolvedParams;
273
+ }
264
274
  } catch (error) {
265
275
  if (this.isUserCancellation(error)) {
266
276
  console.log(chalk7__default.default.yellow("\n\nOperation cancelled by user"));
@@ -270,44 +280,6 @@ var SchemaParameterResolver = class {
270
280
  }
271
281
  }
272
282
  }
273
- if (interactiveMode && trulyOptional.length > 0) {
274
- const optionalNames = trulyOptional.map((p) => p.name).join(", ");
275
- const shouldResolveOptional = await inquirer__default.default.prompt([
276
- {
277
- type: "confirm",
278
- name: "resolveOptional",
279
- message: `Would you like to be prompted for optional parameters (${optionalNames})?`,
280
- default: false
281
- }
282
- ]);
283
- if (shouldResolveOptional.resolveOptional) {
284
- const optionalParamNames = trulyOptional.map((p) => p.name);
285
- const optionalResolutionOrder = getLocalResolutionOrderForParams(
286
- optionalParamNames,
287
- localResolvers
288
- );
289
- const orderedOptionalParams = optionalResolutionOrder.map((paramName) => trulyOptional.find((p) => p.name === paramName)).filter(
290
- (param) => param !== void 0
291
- );
292
- for (const param of orderedOptionalParams) {
293
- try {
294
- const value = await this.resolveParameter(
295
- param,
296
- context,
297
- functionName
298
- );
299
- this.setNestedValue(resolvedParams, param.path, value);
300
- context.resolvedParams = resolvedParams;
301
- } catch (error) {
302
- if (this.isUserCancellation(error)) {
303
- console.log(chalk7__default.default.yellow("\n\nOperation cancelled by user"));
304
- throw new ZapierCliUserCancellationError();
305
- }
306
- throw error;
307
- }
308
- }
309
- }
310
- }
311
283
  const finalResult = schema.safeParse(resolvedParams);
312
284
  if (!finalResult.success) {
313
285
  throw new ZapierCliValidationError(
@@ -402,7 +374,7 @@ var SchemaParameterResolver = class {
402
374
  throw new ZapierCliMissingParametersError(missingParams);
403
375
  }
404
376
  }
405
- async resolveParameter(param, context, functionName) {
377
+ async resolveParameter(param, context, functionName, options) {
406
378
  const resolver = this.getResolver(
407
379
  param.name,
408
380
  context.sdk,
@@ -411,53 +383,102 @@ var SchemaParameterResolver = class {
411
383
  if (!resolver) {
412
384
  throw new Error(`No resolver found for parameter: ${param.name}`);
413
385
  }
414
- console.log(chalk7__default.default.blue(`
415
- \u{1F50D} Resolving ${param.name}...`));
386
+ return this.resolveWithResolver(resolver, param, context, {
387
+ isOptional: options?.isOptional
388
+ });
389
+ }
390
+ async resolveWithResolver(resolver, param, context, options = {}) {
391
+ const { arrayIndex, isOptional } = options;
392
+ const inArrayContext = arrayIndex != null;
393
+ const promptLabel = inArrayContext ? `${param.name}[${arrayIndex}]` : param.name;
394
+ const promptName = inArrayContext ? "value" : param.name;
395
+ this.debugLog(`Resolving ${promptLabel}${isOptional ? " (optional)" : ""}`);
416
396
  if (resolver.type === "static") {
417
397
  const staticResolver = resolver;
418
398
  const promptConfig = {
419
399
  type: staticResolver.inputType === "password" ? "password" : "input",
420
- name: param.name,
421
- message: `Enter ${param.name}:`,
400
+ name: promptName,
401
+ message: `Enter ${promptLabel}${isOptional ? " (optional)" : ""}:`,
422
402
  ...staticResolver.placeholder && {
423
403
  default: staticResolver.placeholder
424
404
  }
425
405
  };
406
+ this.stopSpinner();
426
407
  const answers = await inquirer__default.default.prompt([promptConfig]);
427
- return answers[param.name];
408
+ const value = answers[promptName];
409
+ if (isOptional && (value === void 0 || value === "")) {
410
+ return void 0;
411
+ }
412
+ return value;
428
413
  } else if (resolver.type === "dynamic") {
429
414
  const dynamicResolver = resolver;
415
+ this.startSpinner();
430
416
  const autoResolution = await this.tryAutoResolve(
431
417
  dynamicResolver,
432
418
  context
433
419
  );
434
420
  if (autoResolution != null) {
421
+ this.stopSpinner();
435
422
  return autoResolution.resolvedValue;
436
423
  }
437
- if (param.isRequired && param.name !== "connectionId") {
438
- console.log(chalk7__default.default.gray(`Fetching options for ${param.name}...`));
439
- }
440
- const items = await dynamicResolver.fetch(
424
+ this.debugLog(`Fetching options for ${promptLabel}`);
425
+ const fetchResult = await dynamicResolver.fetch(
441
426
  context.sdk,
442
427
  context.resolvedParams
443
428
  );
444
- const safeItems = items || [];
429
+ const items = Array.isArray(fetchResult) ? fetchResult : fetchResult?.data ?? [];
445
430
  const promptConfig = dynamicResolver.prompt(
446
- safeItems,
431
+ items,
447
432
  context.resolvedParams
448
433
  );
434
+ promptConfig.name = promptName;
435
+ this.stopSpinner();
436
+ if (isOptional && promptConfig.choices) {
437
+ const SKIP_SENTINEL = Symbol("SKIP");
438
+ promptConfig.choices = [
439
+ { name: chalk7__default.default.dim("(Skip)"), value: SKIP_SENTINEL },
440
+ ...promptConfig.choices
441
+ ];
442
+ const answers2 = await inquirer__default.default.prompt([promptConfig]);
443
+ const value = answers2[promptName];
444
+ if (value === SKIP_SENTINEL) {
445
+ return void 0;
446
+ }
447
+ return value;
448
+ }
449
449
  const answers = await inquirer__default.default.prompt([promptConfig]);
450
- return answers[param.name];
450
+ return answers[promptName];
451
451
  } else if (resolver.type === "fields") {
452
+ if (isOptional && !inArrayContext) {
453
+ this.stopSpinner();
454
+ const { confirm } = await inquirer__default.default.prompt([
455
+ {
456
+ type: "confirm",
457
+ name: "confirm",
458
+ message: `Add ${promptLabel}?`,
459
+ default: false
460
+ }
461
+ ]);
462
+ if (!confirm) {
463
+ return void 0;
464
+ }
465
+ }
452
466
  return await this.resolveFieldsRecursively(
467
+ resolver,
468
+ context,
469
+ param,
470
+ { inArrayContext }
471
+ );
472
+ } else if (resolver.type === "array") {
473
+ return await this.resolveArrayRecursively(
453
474
  resolver,
454
475
  context,
455
476
  param
456
477
  );
457
478
  }
458
- throw new Error(`Unknown resolver type for ${param.name}`);
479
+ throw new Error(`Unknown resolver type for ${promptLabel}`);
459
480
  }
460
- async resolveFieldsRecursively(resolver, context, param) {
481
+ async resolveFieldsRecursively(resolver, context, param, options = {}) {
461
482
  const inputs = {};
462
483
  let processedFieldKeys = /* @__PURE__ */ new Set();
463
484
  let iteration = 0;
@@ -471,15 +492,15 @@ var SchemaParameterResolver = class {
471
492
  inputs
472
493
  }
473
494
  };
474
- console.log(
475
- chalk7__default.default.gray(
476
- `Fetching input fields for ${param.name}${iteration > 1 ? ` (iteration ${iteration})` : ""}...`
477
- )
495
+ this.debugLog(
496
+ `Fetching input fields for ${param.name}${iteration > 1 ? ` (iteration ${iteration})` : ""}`
478
497
  );
498
+ this.startSpinner();
479
499
  const rootFieldItems = await resolver.fetch(
480
500
  updatedContext.sdk,
481
501
  updatedContext.resolvedParams
482
502
  );
503
+ this.stopSpinner();
483
504
  if (!rootFieldItems || rootFieldItems.length === 0) {
484
505
  if (iteration === 1) {
485
506
  console.log(
@@ -494,7 +515,8 @@ var SchemaParameterResolver = class {
494
515
  processedFieldKeys,
495
516
  [],
496
517
  iteration,
497
- updatedContext
518
+ updatedContext,
519
+ { inArrayContext: options.inArrayContext }
498
520
  );
499
521
  if (fieldStats.newRequired === 0 && fieldStats.newOptional === 0) {
500
522
  break;
@@ -511,13 +533,60 @@ var SchemaParameterResolver = class {
511
533
  )
512
534
  );
513
535
  }
536
+ if (resolver.transform) {
537
+ return resolver.transform(inputs);
538
+ }
514
539
  return inputs;
515
540
  }
541
+ /**
542
+ * Resolves an array parameter by repeatedly prompting for items until user says no
543
+ */
544
+ async resolveArrayRecursively(resolver, context, param) {
545
+ const items = [];
546
+ const minItems = resolver.minItems ?? 0;
547
+ const maxItems = resolver.maxItems ?? Infinity;
548
+ while (items.length < maxItems) {
549
+ const currentIndex = items.length;
550
+ if (currentIndex >= minItems) {
551
+ this.stopSpinner();
552
+ const confirmAnswer = await inquirer__default.default.prompt([
553
+ {
554
+ type: "confirm",
555
+ name: "addItem",
556
+ message: `Add ${param.name}[${currentIndex}]?`,
557
+ default: false
558
+ }
559
+ ]);
560
+ if (!confirmAnswer.addItem) {
561
+ break;
562
+ }
563
+ }
564
+ const innerResolver = await resolver.fetch(
565
+ context.sdk,
566
+ context.resolvedParams
567
+ );
568
+ const itemValue = await this.resolveWithResolver(
569
+ innerResolver,
570
+ param,
571
+ context,
572
+ { arrayIndex: currentIndex }
573
+ );
574
+ items.push(itemValue);
575
+ context.resolvedParams = {
576
+ ...context.resolvedParams,
577
+ [param.name]: items
578
+ };
579
+ }
580
+ if (items.length >= maxItems) {
581
+ console.log(chalk7__default.default.gray(`Maximum of ${maxItems} items reached.`));
582
+ }
583
+ return items;
584
+ }
516
585
  /**
517
586
  * Recursively processes fieldsets and their fields, maintaining natural structure
518
587
  * and creating nested inputs as needed (e.g., fieldset "foo" becomes inputs.foo = [{}])
519
588
  */
520
- async processFieldItems(items, targetInputs, processedFieldKeys, fieldsetPath = [], iteration = 1, context) {
589
+ async processFieldItems(items, targetInputs, processedFieldKeys, fieldsetPath = [], iteration = 1, context, options = {}) {
521
590
  let newRequiredCount = 0;
522
591
  let newOptionalCount = 0;
523
592
  let optionalSkipped = false;
@@ -543,7 +612,8 @@ var SchemaParameterResolver = class {
543
612
  processedFieldKeys,
544
613
  nestedPath,
545
614
  iteration,
546
- context
615
+ context,
616
+ options
547
617
  );
548
618
  newRequiredCount += nestedStats.newRequired;
549
619
  newOptionalCount += nestedStats.newOptional;
@@ -557,15 +627,22 @@ var SchemaParameterResolver = class {
557
627
  const isRequired = typedItem.is_required || false;
558
628
  if (isRequired) {
559
629
  newRequiredCount++;
560
- if (newRequiredCount === 1 && fieldsetPath.length === 0) {
561
- console.log(
562
- chalk7__default.default.blue(
563
- `
564
- \u{1F4DD} Please provide values for the following ${iteration === 1 ? "" : "additional "}input fields:`
565
- )
630
+ if (typedItem.resolver && context) {
631
+ const param = {
632
+ name: typedItem.key,
633
+ path: [typedItem.key],
634
+ schema: zod.z.unknown(),
635
+ isRequired: true
636
+ };
637
+ targetInputs[typedItem.key] = await this.resolveWithResolver(
638
+ typedItem.resolver,
639
+ param,
640
+ context,
641
+ { isOptional: false }
566
642
  );
643
+ } else {
644
+ await this.promptForField(typedItem, targetInputs, context);
567
645
  }
568
- await this.promptForField(typedItem, targetInputs, context);
569
646
  processedFieldKeys.add(typedItem.key);
570
647
  } else {
571
648
  newOptionalCount++;
@@ -579,42 +656,50 @@ var SchemaParameterResolver = class {
579
656
  });
580
657
  if (optionalFields.length > 0) {
581
658
  const pathContext = fieldsetPath.length > 0 ? ` in ${fieldsetPath.join(" > ")}` : "";
582
- console.log(
583
- chalk7__default.default.gray(
584
- `
659
+ if (options.inArrayContext) {
660
+ for (const field of optionalFields) {
661
+ await this.promptForField(field, targetInputs, context);
662
+ const typedField = field;
663
+ processedFieldKeys.add(typedField.key);
664
+ }
665
+ } else {
666
+ console.log(
667
+ chalk7__default.default.gray(
668
+ `
585
669
  There are ${optionalFields.length} ${iteration === 1 ? "" : "additional "}optional field(s) available${pathContext}.`
586
- )
587
- );
588
- try {
589
- const shouldConfigureOptional = await inquirer__default.default.prompt([
590
- {
591
- type: "confirm",
592
- name: "configure",
593
- message: `Would you like to configure ${iteration === 1 ? "" : "these additional "}optional fields${pathContext}?`,
594
- default: false
595
- }
596
- ]);
597
- if (shouldConfigureOptional.configure) {
598
- console.log(chalk7__default.default.cyan(`
670
+ )
671
+ );
672
+ try {
673
+ const shouldConfigureOptional = await inquirer__default.default.prompt([
674
+ {
675
+ type: "confirm",
676
+ name: "configure",
677
+ message: `Would you like to configure ${iteration === 1 ? "" : "these additional "}optional fields${pathContext}?`,
678
+ default: false
679
+ }
680
+ ]);
681
+ if (shouldConfigureOptional.configure) {
682
+ console.log(chalk7__default.default.cyan(`
599
683
  Optional fields${pathContext}:`));
600
- for (const field of optionalFields) {
601
- await this.promptForField(field, targetInputs, context);
602
- const typedField = field;
603
- processedFieldKeys.add(typedField.key);
684
+ for (const field of optionalFields) {
685
+ await this.promptForField(field, targetInputs, context);
686
+ const typedField = field;
687
+ processedFieldKeys.add(typedField.key);
688
+ }
689
+ } else {
690
+ optionalSkipped = true;
691
+ optionalFields.forEach((field) => {
692
+ const typedField = field;
693
+ processedFieldKeys.add(typedField.key);
694
+ });
604
695
  }
605
- } else {
606
- optionalSkipped = true;
607
- optionalFields.forEach((field) => {
608
- const typedField = field;
609
- processedFieldKeys.add(typedField.key);
610
- });
611
- }
612
- } catch (error) {
613
- if (this.isUserCancellation(error)) {
614
- console.log(chalk7__default.default.yellow("\n\nOperation cancelled by user"));
615
- throw new ZapierCliUserCancellationError();
696
+ } catch (error) {
697
+ if (this.isUserCancellation(error)) {
698
+ console.log(chalk7__default.default.yellow("\n\nOperation cancelled by user"));
699
+ throw new ZapierCliUserCancellationError();
700
+ }
701
+ throw error;
616
702
  }
617
- throw error;
618
703
  }
619
704
  }
620
705
  }
@@ -654,10 +739,11 @@ Optional fields${pathContext}:`));
654
739
  isRequired: fieldObj.is_required || false,
655
740
  defaultValue: fieldObj.default_value ?? fieldObj.default,
656
741
  valueType,
657
- hasDropdown: fieldObj.format === "SELECT",
742
+ hasDropdown: fieldObj.format === "SELECT" || Boolean(fieldObj.choices),
658
743
  isMultiSelect: Boolean(
659
744
  valueType === "array" || fieldObj.items && fieldObj.items.type !== void 0
660
- )
745
+ ),
746
+ inlineChoices: fieldObj.choices
661
747
  };
662
748
  }
663
749
  /**
@@ -665,11 +751,10 @@ Optional fields${pathContext}:`));
665
751
  */
666
752
  async fetchChoices(fieldMeta, inputs, context, cursor) {
667
753
  try {
668
- console.log(
669
- chalk7__default.default.gray(
670
- cursor ? ` Fetching more choices...` : ` Fetching choices for ${fieldMeta.title}...`
671
- )
754
+ this.debugLog(
755
+ cursor ? `Fetching more choices for ${fieldMeta.title}` : `Fetching choices for ${fieldMeta.title}`
672
756
  );
757
+ this.startSpinner();
673
758
  const page = await context.sdk.listInputFieldChoices({
674
759
  appKey: context.resolvedParams.appKey,
675
760
  actionKey: context.resolvedParams.actionKey,
@@ -679,13 +764,14 @@ Optional fields${pathContext}:`));
679
764
  inputs,
680
765
  ...cursor && { cursor }
681
766
  });
767
+ this.stopSpinner();
682
768
  const choices = page.data.map((choice) => ({
683
769
  label: choice.label || choice.key || String(choice.value),
684
770
  value: choice.value ?? choice.key
685
771
  }));
686
772
  if (choices.length === 0 && !cursor) {
687
773
  console.log(
688
- chalk7__default.default.yellow(` No choices available for ${fieldMeta.title}`)
774
+ chalk7__default.default.yellow(`No choices available for ${fieldMeta.title}`)
689
775
  );
690
776
  }
691
777
  return {
@@ -693,8 +779,9 @@ Optional fields${pathContext}:`));
693
779
  nextCursor: page.nextCursor
694
780
  };
695
781
  } catch (error) {
782
+ this.stopSpinner();
696
783
  console.warn(
697
- chalk7__default.default.yellow(` \u26A0\uFE0F Failed to fetch choices for ${fieldMeta.title}:`),
784
+ chalk7__default.default.yellow(`Failed to fetch choices for ${fieldMeta.title}:`),
698
785
  error
699
786
  );
700
787
  return { choices: [] };
@@ -710,6 +797,7 @@ Optional fields${pathContext}:`));
710
797
  inputs,
711
798
  context
712
799
  }) {
800
+ this.stopSpinner();
713
801
  const choices = [...initialChoices];
714
802
  let nextCursor = initialCursor;
715
803
  const LOAD_MORE_SENTINEL = Symbol("LOAD_MORE");
@@ -772,6 +860,27 @@ Optional fields${pathContext}:`));
772
860
  if (fieldMeta.valueType === "boolean") {
773
861
  promptConfig.type = "confirm";
774
862
  promptConfig.default = fieldMeta.defaultValue !== void 0 ? Boolean(fieldMeta.defaultValue) : void 0;
863
+ } else if (fieldMeta.valueType === "array") {
864
+ promptConfig.type = "input";
865
+ promptConfig.default = fieldMeta.defaultValue;
866
+ promptConfig.message = `${fieldMeta.title}${fieldMeta.isRequired ? " (required)" : " (optional)"} (JSON array or comma-separated):`;
867
+ promptConfig.validate = (input) => {
868
+ if (fieldMeta.isRequired && !input) {
869
+ return "This field is required";
870
+ }
871
+ return true;
872
+ };
873
+ promptConfig.filter = (input) => {
874
+ if (!input) return input;
875
+ const trimmed = input.trim();
876
+ if (trimmed.startsWith("[")) {
877
+ try {
878
+ return JSON.parse(trimmed);
879
+ } catch {
880
+ }
881
+ }
882
+ return trimmed.split(",").map((s) => s.trim());
883
+ };
775
884
  } else {
776
885
  promptConfig.type = "input";
777
886
  promptConfig.default = fieldMeta.defaultValue;
@@ -819,7 +928,9 @@ Optional fields${pathContext}:`));
819
928
  const fieldMeta = this.extractFieldMetadata(field);
820
929
  let choices = [];
821
930
  let nextCursor;
822
- if (fieldMeta.hasDropdown && context) {
931
+ if (fieldMeta.inlineChoices) {
932
+ choices = fieldMeta.inlineChoices;
933
+ } else if (fieldMeta.hasDropdown && context) {
823
934
  const result = await this.fetchChoices(fieldMeta, inputs, context);
824
935
  choices = result.choices;
825
936
  nextCursor = result.nextCursor;
@@ -913,7 +1024,7 @@ var SHARED_COMMAND_CLI_OPTIONS = [
913
1024
 
914
1025
  // package.json
915
1026
  var package_default = {
916
- version: "0.35.1"};
1027
+ version: "0.36.1"};
917
1028
 
918
1029
  // src/telemetry/builders.ts
919
1030
  function createCliBaseEvent(context = {}) {
@@ -981,7 +1092,7 @@ function formatJsonOutput(data) {
981
1092
  util__default.default.inspect(data, { colors: true, depth: null, breakLength: 80 })
982
1093
  );
983
1094
  }
984
- function formatItemsFromSchema(functionInfo, items, startingNumber = 0) {
1095
+ async function formatItemsFromSchema(functionInfo, items, startingNumber = 0, options) {
985
1096
  const outputSchema = functionInfo.outputSchema || getOutputSchema(functionInfo.inputSchema);
986
1097
  if (!outputSchema) {
987
1098
  formatItemsGeneric(items, startingNumber);
@@ -1022,11 +1133,39 @@ function formatSingleItem(formatted, itemNumber) {
1022
1133
  return;
1023
1134
  }
1024
1135
  for (const detail of formatted.details) {
1025
- const styledText = applyStyle(detail.text, detail.style);
1026
- console.log(` ${styledText}`);
1136
+ if (detail.label) {
1137
+ const isMultiline = detail.text.includes("\n");
1138
+ if (isMultiline) {
1139
+ console.log(` ${chalk7__default.default.gray(detail.label + ":")}`);
1140
+ const displayText = formatDetailText(
1141
+ detail.text,
1142
+ DETAIL_INDENT + " "
1143
+ );
1144
+ const styledText = applyStyle(displayText, detail.style);
1145
+ console.log(`${DETAIL_INDENT} ${styledText}`);
1146
+ } else {
1147
+ const styledValue = applyStyle(detail.text, detail.style);
1148
+ console.log(` ${chalk7__default.default.gray(detail.label + ":")} ${styledValue}`);
1149
+ }
1150
+ } else {
1151
+ const displayText = formatDetailText(detail.text, DETAIL_INDENT);
1152
+ const styledText = applyStyle(displayText, detail.style);
1153
+ console.log(` ${styledText}`);
1154
+ }
1027
1155
  }
1028
1156
  console.log();
1029
1157
  }
1158
+ var DETAIL_INDENT = " ";
1159
+ var DETAIL_MAX_LINES = 5;
1160
+ function formatDetailText(text, indent = DETAIL_INDENT) {
1161
+ const columns = Math.max((process.stdout.columns || 80) - indent.length, 40);
1162
+ const wrapped = wrapAnsi__default.default(text, columns, { hard: true, trim: false });
1163
+ const lines = wrapped.split("\n");
1164
+ if (lines.length <= DETAIL_MAX_LINES) {
1165
+ return lines.join("\n" + indent);
1166
+ }
1167
+ return lines.slice(0, DETAIL_MAX_LINES).join("\n" + indent) + "\n" + indent + "\u2026";
1168
+ }
1030
1169
  function applyStyle(value, style) {
1031
1170
  switch (style) {
1032
1171
  case "dim":
@@ -1373,15 +1512,16 @@ var CONFIRM_MESSAGES = {
1373
1512
  messageBefore: "You are about to create a sensitive secret that will be displayed as plain text.\nOnce created, you cannot retrieve it again.",
1374
1513
  messageAfter: "Please treat this secret like a password and store it securely!"
1375
1514
  },
1376
- delete: {
1377
- messageBefore: "You are about to delete this record."
1378
- }
1515
+ delete: (itemType) => ({
1516
+ messageBefore: `You are about to delete the ${itemType || "item"}.`
1517
+ })
1379
1518
  };
1380
- async function promptConfirm(confirmType) {
1519
+ async function promptConfirm(confirmType, itemType) {
1381
1520
  if (!confirmType || !CONFIRM_MESSAGES[confirmType]) {
1382
1521
  return { confirmed: true };
1383
1522
  }
1384
- const { messageBefore, messageAfter } = CONFIRM_MESSAGES[confirmType];
1523
+ const configOrFn = CONFIRM_MESSAGES[confirmType];
1524
+ const { messageBefore, messageAfter } = typeof configOrFn === "function" ? configOrFn(itemType) : configOrFn;
1385
1525
  console.log(chalk7__default.default.yellow(`
1386
1526
  ${messageBefore}
1387
1527
  `));
@@ -1465,6 +1605,7 @@ function analyzeZodField(name, schema, functionInfo) {
1465
1605
  }
1466
1606
  }
1467
1607
  let paramType = "string";
1608
+ let elementType;
1468
1609
  let choices;
1469
1610
  if (baseSchema instanceof zod.z.ZodString) {
1470
1611
  paramType = "string";
@@ -1474,6 +1615,14 @@ function analyzeZodField(name, schema, functionInfo) {
1474
1615
  paramType = "boolean";
1475
1616
  } else if (baseSchema instanceof zod.z.ZodArray) {
1476
1617
  paramType = "array";
1618
+ const elementSchema = baseSchema._zod.def.element;
1619
+ if (elementSchema instanceof zod.z.ZodObject || elementSchema instanceof zod.z.ZodRecord) {
1620
+ elementType = "object";
1621
+ } else if (elementSchema instanceof zod.z.ZodNumber) {
1622
+ elementType = "number";
1623
+ } else if (elementSchema instanceof zod.z.ZodBoolean) {
1624
+ elementType = "boolean";
1625
+ }
1477
1626
  } else if (baseSchema instanceof zod.z.ZodEnum) {
1478
1627
  paramType = "string";
1479
1628
  choices = baseSchema.options;
@@ -1492,7 +1641,8 @@ function analyzeZodField(name, schema, functionInfo) {
1492
1641
  default: defaultValue,
1493
1642
  choices,
1494
1643
  hasResolver: paramHasResolver,
1495
- isPositional: zapierSdk.isPositional(schema)
1644
+ isPositional: zapierSdk.isPositional(schema),
1645
+ elementType
1496
1646
  };
1497
1647
  }
1498
1648
  function analyzeInputParameters(inputParameters, functionInfo) {
@@ -1679,7 +1829,10 @@ function createCommandConfig(cliCommandName, functionInfo, sdk2) {
1679
1829
  rawParams,
1680
1830
  sdk2,
1681
1831
  functionInfo.name,
1682
- { interactiveMode }
1832
+ {
1833
+ interactiveMode,
1834
+ debug: !!options2.debug || process.env.DEBUG === "true" || process.argv.includes("--debug")
1835
+ }
1683
1836
  );
1684
1837
  } else {
1685
1838
  resolvedParams = rawParams;
@@ -1687,7 +1840,10 @@ function createCommandConfig(cliCommandName, functionInfo, sdk2) {
1687
1840
  const confirm = functionInfo.confirm;
1688
1841
  let confirmMessageAfter;
1689
1842
  if (confirm && interactiveMode) {
1690
- const confirmResult = await promptConfirm(confirm);
1843
+ const confirmResult = await promptConfirm(
1844
+ confirm,
1845
+ functionInfo.itemType
1846
+ );
1691
1847
  if (!confirmResult.confirmed) {
1692
1848
  console.log(chalk7__default.default.yellow("Operation cancelled."));
1693
1849
  return;
@@ -1876,7 +2032,8 @@ function convertCliArgsToSdkParams(parameters, positionalArgs, options) {
1876
2032
  if ((param.required || param.isPositional) && argIndex < positionalArgs.length) {
1877
2033
  sdkParams[param.name] = convertValue(
1878
2034
  positionalArgs[argIndex],
1879
- param.type
2035
+ param.type,
2036
+ param.elementType
1880
2037
  );
1881
2038
  argIndex++;
1882
2039
  }
@@ -1888,12 +2045,12 @@ function convertCliArgsToSdkParams(parameters, positionalArgs, options) {
1888
2045
  if (param.type === "array" && Array.isArray(value) && value.length === 0) {
1889
2046
  return;
1890
2047
  }
1891
- sdkParams[camelKey] = convertValue(value, param.type);
2048
+ sdkParams[camelKey] = convertValue(value, param.type, param.elementType);
1892
2049
  }
1893
2050
  });
1894
2051
  return sdkParams;
1895
2052
  }
1896
- function convertValue(value, type) {
2053
+ function convertValue(value, type, elementType) {
1897
2054
  if (value === void 0) {
1898
2055
  return void 0;
1899
2056
  }
@@ -1902,8 +2059,20 @@ function convertValue(value, type) {
1902
2059
  return Number(value);
1903
2060
  case "boolean":
1904
2061
  return Boolean(value);
1905
- case "array":
1906
- return Array.isArray(value) ? value : [value];
2062
+ case "array": {
2063
+ const arr = Array.isArray(value) ? value : [value];
2064
+ if (elementType !== "object") return arr;
2065
+ return arr.flatMap((item) => {
2066
+ if (typeof item === "string" && (item.startsWith("{") || item.startsWith("["))) {
2067
+ try {
2068
+ return JSON.parse(item);
2069
+ } catch {
2070
+ return item;
2071
+ }
2072
+ }
2073
+ return item;
2074
+ });
2075
+ }
1907
2076
  case "string":
1908
2077
  return value;
1909
2078
  case "object":
@@ -4389,7 +4558,7 @@ function createZapierCliSdk(options = {}) {
4389
4558
  // package.json with { type: 'json' }
4390
4559
  var package_default2 = {
4391
4560
  name: "@zapier/zapier-sdk-cli",
4392
- version: "0.35.1"};
4561
+ version: "0.36.1"};
4393
4562
  var ONE_DAY_MS = 24 * 60 * 60 * 1e3;
4394
4563
  var CACHE_RESET_INTERVAL_MS = (() => {
4395
4564
  const { ZAPIER_SDK_UPDATE_CHECK_INTERVAL_MS = `${ONE_DAY_MS}` } = process.env;