@zapier/zapier-sdk-cli 0.34.12 → 0.35.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/index.cjs CHANGED
@@ -384,7 +384,8 @@ var loginPlugin = ({
384
384
  meta: {
385
385
  login: {
386
386
  categories: ["account"],
387
- inputSchema: LoginSchema
387
+ inputSchema: LoginSchema,
388
+ supportsJsonOutput: false
388
389
  }
389
390
  }
390
391
  }
@@ -403,7 +404,8 @@ var logoutPlugin = () => ({
403
404
  meta: {
404
405
  logout: {
405
406
  categories: ["account"],
406
- inputSchema: LogoutSchema
407
+ inputSchema: LogoutSchema,
408
+ supportsJsonOutput: false
407
409
  }
408
410
  }
409
411
  }
@@ -2490,7 +2492,8 @@ var initPlugin = () => {
2490
2492
  meta: {
2491
2493
  init: {
2492
2494
  categories: ["utility"],
2493
- inputSchema: InitSchema
2495
+ inputSchema: InitSchema,
2496
+ supportsJsonOutput: false
2494
2497
  }
2495
2498
  }
2496
2499
  }
@@ -2508,7 +2511,7 @@ function createZapierCliSdk(options = {}) {
2508
2511
 
2509
2512
  // package.json
2510
2513
  var package_default = {
2511
- version: "0.34.12"};
2514
+ version: "0.35.1"};
2512
2515
 
2513
2516
  // src/telemetry/builders.ts
2514
2517
  function createCliBaseEvent(context = {}) {
package/dist/index.mjs CHANGED
@@ -351,7 +351,8 @@ var loginPlugin = ({
351
351
  meta: {
352
352
  login: {
353
353
  categories: ["account"],
354
- inputSchema: LoginSchema
354
+ inputSchema: LoginSchema,
355
+ supportsJsonOutput: false
355
356
  }
356
357
  }
357
358
  }
@@ -370,7 +371,8 @@ var logoutPlugin = () => ({
370
371
  meta: {
371
372
  logout: {
372
373
  categories: ["account"],
373
- inputSchema: LogoutSchema
374
+ inputSchema: LogoutSchema,
375
+ supportsJsonOutput: false
374
376
  }
375
377
  }
376
378
  }
@@ -2457,7 +2459,8 @@ var initPlugin = () => {
2457
2459
  meta: {
2458
2460
  init: {
2459
2461
  categories: ["utility"],
2460
- inputSchema: InitSchema
2462
+ inputSchema: InitSchema,
2463
+ supportsJsonOutput: false
2461
2464
  }
2462
2465
  }
2463
2466
  }
@@ -2475,7 +2478,7 @@ function createZapierCliSdk(options = {}) {
2475
2478
 
2476
2479
  // package.json
2477
2480
  var package_default = {
2478
- version: "0.34.12"};
2481
+ version: "0.35.1"};
2479
2482
 
2480
2483
  // src/telemetry/builders.ts
2481
2484
  function createCliBaseEvent(context = {}) {
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zapier/zapier-sdk-cli",
3
- "version": "0.34.12",
3
+ "version": "0.35.1",
4
4
  "description": "Command line interface for Zapier SDK",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.mjs",
@@ -54,6 +54,7 @@ export const initPlugin = () => {
54
54
  init: {
55
55
  categories: ["utility"],
56
56
  inputSchema: InitSchema,
57
+ supportsJsonOutput: false,
57
58
  },
58
59
  },
59
60
  },
@@ -40,6 +40,7 @@ export const loginPlugin = ({ context, }) => {
40
40
  login: {
41
41
  categories: ["account"],
42
42
  inputSchema: LoginSchema,
43
+ supportsJsonOutput: false,
43
44
  },
44
45
  },
45
46
  },
@@ -12,6 +12,7 @@ export const logoutPlugin = () => ({
12
12
  logout: {
13
13
  categories: ["account"],
14
14
  inputSchema: LogoutSchema,
15
+ supportsJsonOutput: false,
15
16
  },
16
17
  },
17
18
  },
@@ -1,13 +1,15 @@
1
1
  import { z } from "zod";
2
- import { isPositional, formatErrorMessage, ZapierError, } from "@zapier/zapier-sdk";
2
+ import { isPositional } from "@zapier/zapier-sdk";
3
3
  import { SchemaParameterResolver } from "./parameter-resolver";
4
- import { formatItemsFromSchema, formatJsonOutput } from "./schema-formatter";
5
4
  import chalk from "chalk";
6
5
  import inquirer from "inquirer";
7
- import { ZapierCliError, ZapierCliExitError } from "./errors";
6
+ import { ZapierCliError, ZapierCliExitError, ZapierCliMissingParametersError, ZapierCliValidationError, } from "./errors";
8
7
  import { SHARED_COMMAND_CLI_OPTIONS } from "./cli-options";
9
8
  import { buildCliCommandExecutedEvent } from "../telemetry/builders";
9
+ import { createJsonRenderer, createInteractiveRenderer } from "./cli-renderer";
10
+ import { toKebabCase } from "./string-utils";
10
11
  const CLI_COMMAND_EXECUTED_EVENT_SUBJECT = "platform.sdk.CliCommandExecutedEvent";
12
+ const PAGINATION_PARAM_NAMES = new Set(["maxItems", "pageSize", "cursor"]);
11
13
  // Flags whose values may contain secrets and must not appear in telemetry
12
14
  const SENSITIVE_FLAGS = [
13
15
  "--credentials",
@@ -41,6 +43,60 @@ export function sanitizeCliArguments(args) {
41
43
  }
42
44
  return sanitized;
43
45
  }
46
+ function getNormalizedResult(result, { isListCommand }) {
47
+ if (result instanceof Response) {
48
+ return { kind: "response", value: result };
49
+ }
50
+ if (isListCommand) {
51
+ const sdkResult = result;
52
+ if (!Array.isArray(sdkResult?.data)) {
53
+ throw new Error(`List command returned unexpected shape (expected { data: [] }): ${JSON.stringify(result).slice(0, 200)}`);
54
+ }
55
+ return {
56
+ kind: "list",
57
+ data: sdkResult.data,
58
+ nextCursor: sdkResult.nextCursor,
59
+ };
60
+ }
61
+ const sdkResult = result;
62
+ return {
63
+ kind: "item",
64
+ value: result !== null && typeof result === "object" && "data" in result
65
+ ? sdkResult.data
66
+ : result,
67
+ };
68
+ }
69
+ function hasItems(sdkResult) {
70
+ return (sdkResult != null &&
71
+ typeof sdkResult.items === "function");
72
+ }
73
+ function hasPages(sdkResult) {
74
+ return (sdkResult != null &&
75
+ typeof sdkResult[Symbol.asyncIterator] === "function");
76
+ }
77
+ async function* toItemsStream(sdkResult) {
78
+ if (hasItems(sdkResult)) {
79
+ yield* sdkResult.items();
80
+ return;
81
+ }
82
+ if (hasPages(sdkResult)) {
83
+ for await (const page of sdkResult) {
84
+ yield* page.data ?? [];
85
+ }
86
+ return;
87
+ }
88
+ throw new ZapierCliExitError(`SDK method returned a value that is not async-iterable. Got: ${typeof sdkResult}. ` +
89
+ `List methods must return an AsyncIterable or an object with an items() method.`, 1);
90
+ }
91
+ async function collectItemsFromResult({ sdkResult, maxItems, }) {
92
+ const items = [];
93
+ for await (const item of toItemsStream(sdkResult)) {
94
+ items.push(item);
95
+ if (maxItems !== undefined && items.length >= maxItems)
96
+ break;
97
+ }
98
+ return maxItems !== undefined ? items.slice(0, maxItems) : items;
99
+ }
44
100
  const CONFIRM_MESSAGES = {
45
101
  "create-secret": {
46
102
  messageBefore: "You are about to create a sensitive secret that will be displayed as plain text.\n" +
@@ -77,6 +133,13 @@ function emitDeprecationWarning({ cliCommandName, deprecation, }) {
77
133
  console.warn(chalk.yellow(` ${deprecation.message}`));
78
134
  console.warn();
79
135
  }
136
+ function resolveOutputMode({ isListCommand, hasPaginationParams, hasUserSpecifiedMaxItems, }) {
137
+ if (!isListCommand || !hasPaginationParams)
138
+ return "single";
139
+ if (hasUserSpecifiedMaxItems)
140
+ return "collect";
141
+ return "paginate";
142
+ }
80
143
  // ============================================================================
81
144
  // Schema Analysis
82
145
  // ============================================================================
@@ -247,13 +310,6 @@ function reconstructPositionalArgs(inputParameters, flatParams) {
247
310
  // ============================================================================
248
311
  // CLI Structure Derivation - Purely Generic
249
312
  // ============================================================================
250
- /**
251
- * Convert camelCase to kebab-case
252
- * e.g., listApps -> list-apps, generateTypes -> generate-types
253
- */
254
- function toKebabCase(str) {
255
- return str.replace(/([A-Z])/g, "-$1").toLowerCase();
256
- }
257
313
  /**
258
314
  * Convert SDK method name directly to CLI command
259
315
  * e.g., listApps -> list-apps, getApp -> get-app, generateTypes -> generate-types
@@ -348,6 +404,13 @@ function createCommandConfig(cliCommandName, functionInfo, sdk) {
348
404
  let success = true;
349
405
  let errorMessage = null;
350
406
  let resolvedParams = {};
407
+ // interactiveMode is true by default; --json disables it
408
+ const commandObj = args[args.length - 1];
409
+ const options = commandObj.opts();
410
+ const interactiveMode = !options.json;
411
+ const renderer = interactiveMode
412
+ ? createInteractiveRenderer()
413
+ : createJsonRenderer();
351
414
  try {
352
415
  // The last argument is always the command object with parsed options
353
416
  const commandObj = args[args.length - 1];
@@ -358,24 +421,24 @@ function createCommandConfig(cliCommandName, functionInfo, sdk) {
358
421
  });
359
422
  // Check if this is a list command for pagination
360
423
  const isListCommand = functionInfo.type === "list";
361
- const hasPaginationParams = parameters.some((p) => p.name === "maxItems" || p.name === "pageSize");
424
+ const hasPaginationParams = parameters.some((p) => PAGINATION_PARAM_NAMES.has(p.name));
362
425
  const hasUserSpecifiedMaxItems = "maxItems" in options && options.maxItems !== undefined;
363
- const shouldUseJson = options.json;
364
- // Convert CLI args to SDK method parameters
426
+ const outputMode = resolveOutputMode({
427
+ isListCommand,
428
+ hasPaginationParams,
429
+ hasUserSpecifiedMaxItems,
430
+ });
365
431
  const rawParams = convertCliArgsToSdkParams(parameters, args.slice(0, -1), options);
366
- // Resolve missing parameters interactively using schema metadata
367
- // (only available for inputSchema-based functions)
368
432
  if (schema && !usesInputParameters) {
369
433
  const resolver = new SchemaParameterResolver();
370
- resolvedParams = (await resolver.resolveParameters(schema, rawParams, sdk, functionInfo.name));
434
+ resolvedParams = (await resolver.resolveParameters(schema, rawParams, sdk, functionInfo.name, { interactiveMode }));
371
435
  }
372
436
  else {
373
437
  resolvedParams = rawParams;
374
438
  }
375
- // Check for confirmation before executing (skip for --json mode)
376
439
  const confirm = functionInfo.confirm;
377
440
  let confirmMessageAfter;
378
- if (confirm && !shouldUseJson) {
441
+ if (confirm && interactiveMode) {
379
442
  const confirmResult = await promptConfirm(confirm);
380
443
  if (!confirmResult.confirmed) {
381
444
  console.log(chalk.yellow("Operation cancelled."));
@@ -383,111 +446,82 @@ function createCommandConfig(cliCommandName, functionInfo, sdk) {
383
446
  }
384
447
  confirmMessageAfter = confirmResult.messageAfter;
385
448
  }
386
- // Handle paginated list commands with async iteration
387
- if (isListCommand &&
388
- hasPaginationParams &&
389
- !shouldUseJson &&
390
- !hasUserSpecifiedMaxItems) {
391
- // Get the async iterable directly from the SDK method call (don't await it! that breaks the next page behavior)
392
- const sdkObj = sdk;
393
- const sdkIterable = sdkObj[functionInfo.name](resolvedParams);
394
- await handlePaginatedListWithAsyncIteration(functionInfo.name, sdkIterable, functionInfo);
395
- }
396
- else {
397
- // Special handling for commands that write to files
398
- const hasOutputFile = resolvedParams.output;
399
- if (hasOutputFile) {
400
- const sdkObj = sdk;
401
- await sdkObj[functionInfo.name](resolvedParams);
402
- console.log(chalk.green(`āœ… ${cliCommandName} completed successfully!`));
403
- console.log(chalk.gray(`Output written to: ${hasOutputFile}`));
404
- return;
405
- }
406
- // Invoke SDK method — reconstruct positional args for inputParameters functions
407
- let result;
408
- if (usesInputParameters) {
409
- const positionalArgs = reconstructPositionalArgs(functionInfo.inputParameters, resolvedParams);
410
- const sdkObj = sdk;
411
- result = await sdkObj[functionInfo.name](...positionalArgs);
449
+ const sdkMethod = sdk[functionInfo.name];
450
+ switch (outputMode) {
451
+ case "paginate": {
452
+ const source = sdkMethod(resolvedParams);
453
+ await renderer.renderPaginatedList(source, functionInfo);
454
+ break;
412
455
  }
413
- else {
414
- const sdkObj = sdk;
415
- result = await sdkObj[functionInfo.name](resolvedParams);
456
+ case "collect": {
457
+ const maxItems = resolvedParams.maxItems;
458
+ const sdkResult = sdkMethod({ ...resolvedParams, maxItems });
459
+ const allItems = await collectItemsFromResult({
460
+ sdkResult,
461
+ maxItems,
462
+ });
463
+ renderer.renderCollectedList(allItems, {
464
+ maxItems,
465
+ userSpecifiedMaxItems: hasUserSpecifiedMaxItems,
466
+ functionInfo,
467
+ });
468
+ break;
416
469
  }
417
- // Handle Response objects by wrapping in a structured envelope
418
- if (result instanceof Response) {
419
- const response = result;
420
- let body;
421
- // Read as text first to preserve body for error messages
422
- const text = await response
423
- .text()
424
- .catch(() => "[unable to read body]");
425
- try {
426
- body = JSON.parse(text);
470
+ case "single": {
471
+ const callSdkMethod = () => {
472
+ if (usesInputParameters) {
473
+ const positionalArgs = reconstructPositionalArgs(functionInfo.inputParameters, resolvedParams);
474
+ return sdkMethod(...positionalArgs);
475
+ }
476
+ return sdkMethod(resolvedParams);
477
+ };
478
+ const outputFile = resolvedParams.output;
479
+ if (outputFile) {
480
+ await callSdkMethod();
481
+ renderer.renderItem(null, {
482
+ outputFile,
483
+ commandName: cliCommandName,
484
+ });
485
+ break;
427
486
  }
428
- catch {
429
- throw new Error(`Failed to parse response as JSON (status: ${response.status}). Body: ${text.slice(0, 500)}`);
487
+ const result = await callSdkMethod();
488
+ const normalizedResult = getNormalizedResult(result, {
489
+ isListCommand,
490
+ });
491
+ if (normalizedResult.kind === "response") {
492
+ await renderer.renderResponse(normalizedResult.value);
430
493
  }
431
- result = {
432
- statusCode: response.status,
433
- headers: Object.fromEntries(response.headers.entries()),
434
- body,
435
- };
436
- }
437
- const items = result?.data
438
- ? result.data
439
- : result;
440
- if (shouldUseJson) {
441
- console.log(JSON.stringify(items, null, 2));
442
- }
443
- else if (isListCommand) {
444
- formatNonPaginatedResults(items, resolvedParams.maxItems, hasUserSpecifiedMaxItems, shouldUseJson, functionInfo);
445
- }
446
- else {
447
- formatJsonOutput(items);
448
- }
449
- // Show message after operation completes
450
- if (confirmMessageAfter) {
451
- console.log(chalk.yellow(`\n${confirmMessageAfter}`));
494
+ else if (normalizedResult.kind === "list") {
495
+ renderer.renderCollectedList(normalizedResult.data, {
496
+ maxItems: resolvedParams.maxItems,
497
+ userSpecifiedMaxItems: hasUserSpecifiedMaxItems,
498
+ functionInfo,
499
+ });
500
+ }
501
+ else {
502
+ renderer.renderItem(normalizedResult.value);
503
+ }
504
+ if (confirmMessageAfter) {
505
+ console.log(chalk.yellow(`\n${confirmMessageAfter}`));
506
+ }
507
+ break;
452
508
  }
453
509
  }
454
510
  }
455
511
  catch (error) {
456
512
  success = false;
457
513
  errorMessage = error instanceof Error ? error.message : String(error);
458
- // Handle Zod validation errors more gracefully
459
- if (error instanceof Error && error.message.includes('"code"')) {
460
- try {
461
- const validationErrors = JSON.parse(error.message);
462
- console.error(chalk.red("āŒ Validation Error:"));
463
- validationErrors.forEach((err) => {
464
- const errorObj = err;
465
- const field = errorObj?.path?.join(".") || "unknown";
466
- console.error(chalk.yellow(` • ${field}: ${errorObj?.message || "Unknown error"}`));
467
- });
468
- console.error("\n" + chalk.dim(`Use --help to see available options`));
469
- throw new ZapierCliExitError("Validation failed", 1);
470
- }
471
- catch {
472
- console.error(chalk.red("Error:"), error instanceof Error ? error.message : String(error));
473
- throw new ZapierCliExitError(error instanceof Error ? error.message : String(error), 1);
474
- }
514
+ if (error instanceof ZapierCliMissingParametersError) {
515
+ renderer.renderError(error);
516
+ }
517
+ else if (error instanceof ZapierCliValidationError) {
518
+ renderer.renderError(error);
475
519
  }
476
520
  else if (error instanceof ZapierCliError) {
477
- // Re-throw all CLI errors as-is
478
521
  throw error;
479
522
  }
480
- else if (error instanceof ZapierError) {
481
- // Handle SDK errors with clean, user-friendly messages using our formatter
482
- const formattedMessage = formatErrorMessage(error);
483
- console.error(chalk.red("āŒ Error:"), formattedMessage);
484
- throw new ZapierCliExitError(formattedMessage, 1);
485
- }
486
523
  else {
487
- // Handle other errors
488
- const msg = error instanceof Error ? error.message : "Unknown error";
489
- console.error(chalk.red("āŒ Error:"), msg);
490
- throw new ZapierCliExitError(msg, 1);
524
+ renderer.renderError(error);
491
525
  }
492
526
  }
493
527
  finally {
@@ -522,6 +556,7 @@ function createCommandConfig(cliCommandName, functionInfo, sdk) {
522
556
  handler,
523
557
  hidden: functionInfo.categories?.includes("deprecated") ?? false,
524
558
  aliases: functionInfo.aliases,
559
+ supportsJsonOutput: functionInfo.supportsJsonOutput,
525
560
  };
526
561
  }
527
562
  // Collect function for repeatable options (e.g., -d foo -d bar → ['foo', 'bar'])
@@ -537,8 +572,7 @@ function addCommand(program, commandName, config) {
537
572
  let hasPositionalArray = false;
538
573
  // Add parameters to command
539
574
  config.parameters.forEach((param) => {
540
- // Convert camelCase to kebab-case for CLI display
541
- const kebabName = param.name.replace(/([A-Z])/g, "-$1").toLowerCase();
575
+ const kebabName = toKebabCase(param.name);
542
576
  if (param.hasResolver && param.required) {
543
577
  // Required parameters with resolvers become optional positional arguments (resolver handles prompting)
544
578
  command.argument(`[${kebabName}]`, param.description || `${kebabName} parameter`);
@@ -587,12 +621,14 @@ function addCommand(program, commandName, config) {
587
621
  }
588
622
  }
589
623
  });
590
- // Add shared command options (if not already included)
624
+ // Add shared command options (if not already included or excluded by interactive mode)
591
625
  const paramNames = new Set(config.parameters.map((p) => p.name));
592
626
  SHARED_COMMAND_CLI_OPTIONS.forEach((opt) => {
593
- if (!paramNames.has(opt.name)) {
594
- command.option(opt.flag, opt.description);
595
- }
627
+ if (paramNames.has(opt.name))
628
+ return;
629
+ if (config.supportsJsonOutput === false && opt.name === "json")
630
+ return;
631
+ command.option(opt.flag, opt.description);
596
632
  });
597
633
  command.action(config.handler);
598
634
  }
@@ -669,144 +705,3 @@ function convertValue(value, type) {
669
705
  return value;
670
706
  }
671
707
  }
672
- // ============================================================================
673
- // Pagination Handlers
674
- // ============================================================================
675
- async function handlePaginatedListWithAsyncIteration(sdkMethodName, sdkResult, functionInfo) {
676
- const itemName = getItemNameFromMethod(functionInfo);
677
- let totalShown = 0;
678
- let pageCount = 0;
679
- console.log(chalk.blue(`šŸ“‹ ${getListTitleFromMethod(sdkMethodName, functionInfo)}\n`));
680
- try {
681
- // Use async iteration to go through pages
682
- for await (const page of sdkResult) {
683
- const items = page.data || page;
684
- pageCount++;
685
- if (!Array.isArray(items)) {
686
- console.log(chalk.yellow(`No ${itemName} found.`));
687
- return;
688
- }
689
- if (items.length === 0 && pageCount === 1) {
690
- console.log(chalk.yellow(`No ${itemName} found.`));
691
- return;
692
- }
693
- if (items.length === 0) {
694
- break; // No more items
695
- }
696
- // Clear screen for subsequent pages (not the first)
697
- if (pageCount > 1) {
698
- console.clear();
699
- console.log(chalk.blue(`šŸ“‹ ${getListTitleFromMethod(sdkMethodName, functionInfo)}\n`));
700
- }
701
- // Format and display items using function info
702
- if (functionInfo && functionInfo.inputSchema) {
703
- formatItemsFromSchema(functionInfo, items, totalShown);
704
- }
705
- else {
706
- formatItemsGeneric(items, totalShown);
707
- }
708
- totalShown += items.length;
709
- console.log(chalk.green(`\nāœ… Showing ${totalShown} ${itemName} (page ${pageCount})`));
710
- // Only prompt if there's a nextCursor (more pages available)
711
- if (page.nextCursor) {
712
- const { continueReading } = await inquirer.prompt([
713
- {
714
- type: "confirm",
715
- name: "continueReading",
716
- message: `Load next page?`,
717
- default: true,
718
- },
719
- ]);
720
- if (!continueReading) {
721
- break;
722
- }
723
- }
724
- else {
725
- // No more pages available, exit gracefully
726
- break;
727
- }
728
- }
729
- console.log(chalk.gray(`\nšŸ“„ Finished browsing ${itemName}`));
730
- }
731
- catch (error) {
732
- // If the result is not async iterable, fall back to showing the first page
733
- const items = sdkResult?.data || sdkResult;
734
- if (Array.isArray(items)) {
735
- if (items.length === 0) {
736
- console.log(chalk.yellow(`No ${itemName} found.`));
737
- return;
738
- }
739
- if (functionInfo && functionInfo.inputSchema) {
740
- formatItemsFromSchema(functionInfo, items, 0);
741
- }
742
- else {
743
- formatItemsGeneric(items, 0);
744
- }
745
- console.log(chalk.green(`\nāœ… Showing ${items.length} ${itemName}`));
746
- }
747
- else {
748
- throw error;
749
- }
750
- }
751
- }
752
- function formatNonPaginatedResults(result, requestedMaxItems, userSpecifiedMaxItems, useRawJson, functionInfo) {
753
- if (!Array.isArray(result)) {
754
- if (useRawJson) {
755
- console.log(JSON.stringify(result, null, 2));
756
- }
757
- else {
758
- formatJsonOutput(result);
759
- }
760
- return;
761
- }
762
- if (useRawJson) {
763
- console.log(JSON.stringify(result, null, 2));
764
- return;
765
- }
766
- const itemName = functionInfo ? getItemNameFromMethod(functionInfo) : "items";
767
- if (result.length === 0) {
768
- console.log(chalk.yellow(`No ${itemName} found.`));
769
- return;
770
- }
771
- console.log(chalk.green(`\nāœ… Found ${result.length} ${itemName}:\n`));
772
- // Use function info for formatting
773
- if (functionInfo && functionInfo.inputSchema) {
774
- formatItemsFromSchema(functionInfo, result);
775
- }
776
- else {
777
- // Fallback to generic formatting
778
- formatItemsGeneric(result);
779
- }
780
- // Show appropriate status message
781
- if (userSpecifiedMaxItems && requestedMaxItems) {
782
- console.log(chalk.gray(`\nšŸ“„ Showing up to ${requestedMaxItems} ${itemName} (--max-items ${requestedMaxItems})`));
783
- }
784
- else {
785
- console.log(chalk.gray(`\nšŸ“„ All available ${itemName} shown`));
786
- }
787
- }
788
- function formatItemsGeneric(items, startingNumber = 0) {
789
- // Fallback formatting for items without schema metadata
790
- items.forEach((item, index) => {
791
- const itemObj = item;
792
- const name = itemObj?.name || itemObj?.key || itemObj?.id || "Item";
793
- console.log(`${chalk.gray(`${startingNumber + index + 1}.`)} ${chalk.cyan(String(name))}`);
794
- if (itemObj?.description) {
795
- console.log(` ${chalk.dim(String(itemObj.description))}`);
796
- }
797
- console.log();
798
- });
799
- }
800
- // Generic helper functions that infer from schema description or method name
801
- function getItemNameFromMethod(functionInfo) {
802
- if (functionInfo.itemType) {
803
- return `${functionInfo.itemType} items`;
804
- }
805
- return "items";
806
- }
807
- function getListTitleFromMethod(methodName, functionInfo) {
808
- if (functionInfo.itemType) {
809
- return `Available ${functionInfo.itemType} items`;
810
- }
811
- return `${methodName} items`;
812
- }
@@ -0,0 +1,30 @@
1
+ import type { FunctionRegistryEntry, SdkPage } from "@zapier/zapier-sdk";
2
+ export interface JsonErrorEntry {
3
+ code: string;
4
+ message: string;
5
+ }
6
+ export interface JsonEnvelope {
7
+ data: unknown;
8
+ nextCursor?: string;
9
+ errors: JsonErrorEntry[];
10
+ }
11
+ type PagedSource = AsyncIterable<SdkPage> | PromiseLike<SdkPage>;
12
+ export interface CliRenderer {
13
+ renderPaginatedList(source: PagedSource, functionInfo: FunctionRegistryEntry): Promise<void>;
14
+ renderCollectedList(items: unknown[], options: {
15
+ maxItems?: number;
16
+ userSpecifiedMaxItems?: boolean;
17
+ functionInfo?: FunctionRegistryEntry;
18
+ }): void;
19
+ renderItem(value: unknown, options?: {
20
+ outputFile?: unknown;
21
+ commandName?: string;
22
+ functionInfo?: FunctionRegistryEntry;
23
+ }): void;
24
+ renderResponse(response: Response): Promise<void>;
25
+ renderError(error: unknown): never;
26
+ }
27
+ export declare function buildJsonErrors(error: unknown): JsonErrorEntry[];
28
+ export declare function createJsonRenderer(): CliRenderer;
29
+ export declare function createInteractiveRenderer(): CliRenderer;
30
+ export {};