@zapier/zapier-sdk-cli 0.34.11 ā 0.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/README.md +33 -33
- package/dist/cli.cjs +632 -446
- package/dist/cli.mjs +632 -446
- package/dist/index.cjs +11 -7
- package/dist/index.mjs +11 -7
- package/dist/package.json +1 -1
- package/dist/src/plugins/init/index.js +1 -0
- package/dist/src/plugins/login/index.js +2 -3
- package/dist/src/plugins/logout/index.js +1 -0
- package/dist/src/utils/cli-generator.js +150 -255
- package/dist/src/utils/cli-renderer.d.ts +30 -0
- package/dist/src/utils/cli-renderer.js +226 -0
- package/dist/src/utils/errors.d.ts +17 -0
- package/dist/src/utils/errors.js +17 -0
- package/dist/src/utils/parameter-resolver.d.ts +15 -1
- package/dist/src/utils/parameter-resolver.js +89 -33
- package/dist/src/utils/string-utils.d.ts +1 -0
- package/dist/src/utils/string-utils.js +6 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
package/dist/index.cjs
CHANGED
|
@@ -371,9 +371,10 @@ var loginPlugin = ({
|
|
|
371
371
|
const user = await cliLogin.getLoggedInUser();
|
|
372
372
|
context.eventEmission.emit(
|
|
373
373
|
"platform.sdk.ApplicationLifecycleEvent",
|
|
374
|
-
zapierSdk.buildApplicationLifecycleEvent(
|
|
375
|
-
lifecycle_event_type: "login_success"
|
|
376
|
-
|
|
374
|
+
zapierSdk.buildApplicationLifecycleEvent(
|
|
375
|
+
{ lifecycle_event_type: "login_success" },
|
|
376
|
+
{ customuser_id: user.customUserId, account_id: user.accountId }
|
|
377
|
+
)
|
|
377
378
|
);
|
|
378
379
|
console.log(`\u2705 Successfully logged in as ${user.email}`);
|
|
379
380
|
};
|
|
@@ -383,7 +384,8 @@ var loginPlugin = ({
|
|
|
383
384
|
meta: {
|
|
384
385
|
login: {
|
|
385
386
|
categories: ["account"],
|
|
386
|
-
inputSchema: LoginSchema
|
|
387
|
+
inputSchema: LoginSchema,
|
|
388
|
+
supportsJsonOutput: false
|
|
387
389
|
}
|
|
388
390
|
}
|
|
389
391
|
}
|
|
@@ -402,7 +404,8 @@ var logoutPlugin = () => ({
|
|
|
402
404
|
meta: {
|
|
403
405
|
logout: {
|
|
404
406
|
categories: ["account"],
|
|
405
|
-
inputSchema: LogoutSchema
|
|
407
|
+
inputSchema: LogoutSchema,
|
|
408
|
+
supportsJsonOutput: false
|
|
406
409
|
}
|
|
407
410
|
}
|
|
408
411
|
}
|
|
@@ -2489,7 +2492,8 @@ var initPlugin = () => {
|
|
|
2489
2492
|
meta: {
|
|
2490
2493
|
init: {
|
|
2491
2494
|
categories: ["utility"],
|
|
2492
|
-
inputSchema: InitSchema
|
|
2495
|
+
inputSchema: InitSchema,
|
|
2496
|
+
supportsJsonOutput: false
|
|
2493
2497
|
}
|
|
2494
2498
|
}
|
|
2495
2499
|
}
|
|
@@ -2507,7 +2511,7 @@ function createZapierCliSdk(options = {}) {
|
|
|
2507
2511
|
|
|
2508
2512
|
// package.json
|
|
2509
2513
|
var package_default = {
|
|
2510
|
-
version: "0.
|
|
2514
|
+
version: "0.35.0"};
|
|
2511
2515
|
|
|
2512
2516
|
// src/telemetry/builders.ts
|
|
2513
2517
|
function createCliBaseEvent(context = {}) {
|
package/dist/index.mjs
CHANGED
|
@@ -338,9 +338,10 @@ var loginPlugin = ({
|
|
|
338
338
|
const user = await getLoggedInUser();
|
|
339
339
|
context.eventEmission.emit(
|
|
340
340
|
"platform.sdk.ApplicationLifecycleEvent",
|
|
341
|
-
buildApplicationLifecycleEvent(
|
|
342
|
-
lifecycle_event_type: "login_success"
|
|
343
|
-
|
|
341
|
+
buildApplicationLifecycleEvent(
|
|
342
|
+
{ lifecycle_event_type: "login_success" },
|
|
343
|
+
{ customuser_id: user.customUserId, account_id: user.accountId }
|
|
344
|
+
)
|
|
344
345
|
);
|
|
345
346
|
console.log(`\u2705 Successfully logged in as ${user.email}`);
|
|
346
347
|
};
|
|
@@ -350,7 +351,8 @@ var loginPlugin = ({
|
|
|
350
351
|
meta: {
|
|
351
352
|
login: {
|
|
352
353
|
categories: ["account"],
|
|
353
|
-
inputSchema: LoginSchema
|
|
354
|
+
inputSchema: LoginSchema,
|
|
355
|
+
supportsJsonOutput: false
|
|
354
356
|
}
|
|
355
357
|
}
|
|
356
358
|
}
|
|
@@ -369,7 +371,8 @@ var logoutPlugin = () => ({
|
|
|
369
371
|
meta: {
|
|
370
372
|
logout: {
|
|
371
373
|
categories: ["account"],
|
|
372
|
-
inputSchema: LogoutSchema
|
|
374
|
+
inputSchema: LogoutSchema,
|
|
375
|
+
supportsJsonOutput: false
|
|
373
376
|
}
|
|
374
377
|
}
|
|
375
378
|
}
|
|
@@ -2456,7 +2459,8 @@ var initPlugin = () => {
|
|
|
2456
2459
|
meta: {
|
|
2457
2460
|
init: {
|
|
2458
2461
|
categories: ["utility"],
|
|
2459
|
-
inputSchema: InitSchema
|
|
2462
|
+
inputSchema: InitSchema,
|
|
2463
|
+
supportsJsonOutput: false
|
|
2460
2464
|
}
|
|
2461
2465
|
}
|
|
2462
2466
|
}
|
|
@@ -2474,7 +2478,7 @@ function createZapierCliSdk(options = {}) {
|
|
|
2474
2478
|
|
|
2475
2479
|
// package.json
|
|
2476
2480
|
var package_default = {
|
|
2477
|
-
version: "0.
|
|
2481
|
+
version: "0.35.0"};
|
|
2478
2482
|
|
|
2479
2483
|
// src/telemetry/builders.ts
|
|
2480
2484
|
function createCliBaseEvent(context = {}) {
|
package/dist/package.json
CHANGED
|
@@ -30,9 +30,7 @@ export const loginPlugin = ({ context, }) => {
|
|
|
30
30
|
credentials: pkceCredentials,
|
|
31
31
|
});
|
|
32
32
|
const user = await getLoggedInUser();
|
|
33
|
-
context.eventEmission.emit("platform.sdk.ApplicationLifecycleEvent", buildApplicationLifecycleEvent({
|
|
34
|
-
lifecycle_event_type: "login_success",
|
|
35
|
-
}));
|
|
33
|
+
context.eventEmission.emit("platform.sdk.ApplicationLifecycleEvent", buildApplicationLifecycleEvent({ lifecycle_event_type: "login_success" }, { customuser_id: user.customUserId, account_id: user.accountId }));
|
|
36
34
|
console.log(`ā
Successfully logged in as ${user.email}`);
|
|
37
35
|
};
|
|
38
36
|
return {
|
|
@@ -42,6 +40,7 @@ export const loginPlugin = ({ context, }) => {
|
|
|
42
40
|
login: {
|
|
43
41
|
categories: ["account"],
|
|
44
42
|
inputSchema: LoginSchema,
|
|
43
|
+
supportsJsonOutput: false,
|
|
45
44
|
},
|
|
46
45
|
},
|
|
47
46
|
},
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { isPositional
|
|
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) =>
|
|
424
|
+
const hasPaginationParams = parameters.some((p) => PAGINATION_PARAM_NAMES.has(p.name));
|
|
362
425
|
const hasUserSpecifiedMaxItems = "maxItems" in options && options.maxItems !== undefined;
|
|
363
|
-
const
|
|
364
|
-
|
|
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 &&
|
|
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
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
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
|
-
|
|
414
|
-
const
|
|
415
|
-
|
|
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
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
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
|
-
|
|
429
|
-
|
|
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
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
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
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 (
|
|
594
|
-
|
|
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
|
-
}
|