@zapier/zapier-sdk-cli 0.3.1 → 0.4.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.
Files changed (47) hide show
  1. package/dist/cli.js +1099 -16
  2. package/dist/index.js +0 -3
  3. package/package.json +5 -3
  4. package/src/cli.ts +2 -2
  5. package/src/commands/configPath.ts +1 -1
  6. package/src/commands/index.ts +4 -4
  7. package/src/commands/login.ts +2 -2
  8. package/src/commands/logout.ts +1 -1
  9. package/src/commands/whoami.ts +2 -2
  10. package/src/utils/auth/login.ts +6 -6
  11. package/src/utils/cli-generator.ts +3 -3
  12. package/tsconfig.json +3 -3
  13. package/tsup.config.ts +17 -0
  14. package/dist/cli.d.ts +0 -2
  15. package/dist/commands/configPath.d.ts +0 -2
  16. package/dist/commands/configPath.js +0 -9
  17. package/dist/commands/index.d.ts +0 -4
  18. package/dist/commands/index.js +0 -4
  19. package/dist/commands/login.d.ts +0 -2
  20. package/dist/commands/login.js +0 -25
  21. package/dist/commands/logout.d.ts +0 -2
  22. package/dist/commands/logout.js +0 -16
  23. package/dist/commands/whoami.d.ts +0 -2
  24. package/dist/commands/whoami.js +0 -17
  25. package/dist/index.d.ts +0 -1
  26. package/dist/utils/api/client.d.ts +0 -15
  27. package/dist/utils/api/client.js +0 -27
  28. package/dist/utils/auth/login.d.ts +0 -2
  29. package/dist/utils/auth/login.js +0 -134
  30. package/dist/utils/cli-generator.d.ts +0 -3
  31. package/dist/utils/cli-generator.js +0 -388
  32. package/dist/utils/constants.d.ts +0 -5
  33. package/dist/utils/constants.js +0 -6
  34. package/dist/utils/getCallablePromise.d.ts +0 -6
  35. package/dist/utils/getCallablePromise.js +0 -14
  36. package/dist/utils/log.d.ts +0 -7
  37. package/dist/utils/log.js +0 -16
  38. package/dist/utils/pager.d.ts +0 -48
  39. package/dist/utils/pager.js +0 -137
  40. package/dist/utils/parameter-resolver.d.ts +0 -13
  41. package/dist/utils/parameter-resolver.js +0 -300
  42. package/dist/utils/schema-formatter.d.ts +0 -2
  43. package/dist/utils/schema-formatter.js +0 -71
  44. package/dist/utils/serializeAsync.d.ts +0 -2
  45. package/dist/utils/serializeAsync.js +0 -16
  46. package/dist/utils/spinner.d.ts +0 -1
  47. package/dist/utils/spinner.js +0 -13
@@ -1,300 +0,0 @@
1
- import inquirer from "inquirer";
2
- import chalk from "chalk";
3
- import { z } from "zod";
4
- import { getResolver, hasResolver, getResolutionOrderForParams, } from "@zapier/zapier-sdk";
5
- // ============================================================================
6
- // Schema Parameter Resolver
7
- // ============================================================================
8
- export class SchemaParameterResolver {
9
- async resolveParameters(schema, providedParams, sdk) {
10
- // 1. Try to parse with current parameters
11
- const parseResult = schema.safeParse(providedParams);
12
- // Get all schema parameters to check which ones have resolvers
13
- const allParams = this.extractParametersFromSchema(schema);
14
- const resolvableParams = allParams.filter((param) => hasResolver(param.name));
15
- // Get all missing parameters that have resolvers
16
- const missingResolvable = resolvableParams.filter((param) => {
17
- const hasValue = this.getNestedValue(providedParams, param.path) !== undefined;
18
- return !hasValue;
19
- });
20
- // Determine which parameters are "functionally required" vs truly optional
21
- // For run-action: appKey, actionType, actionKey are schema-required
22
- // authenticationId and inputs are schema-optional but functionally needed
23
- const functionallyRequired = missingResolvable.filter((param) => {
24
- // Schema-required parameters are always functionally required
25
- if (param.isRequired)
26
- return true;
27
- // For run-action, inputs and authenticationId are functionally required
28
- // even though schema-optional
29
- if (param.name === "inputs" || param.name === "authenticationId") {
30
- return true;
31
- }
32
- return false;
33
- });
34
- const trulyOptional = missingResolvable.filter((param) => !functionallyRequired.includes(param));
35
- if (parseResult.success && functionallyRequired.length === 0) {
36
- return parseResult.data;
37
- }
38
- if (functionallyRequired.length === 0) {
39
- // No functionally required parameters missing, but check if we can parse
40
- if (!parseResult.success) {
41
- throw parseResult.error;
42
- }
43
- return parseResult.data;
44
- }
45
- // 2. Resolve functionally required parameters first
46
- const resolvedParams = { ...providedParams };
47
- const context = {
48
- sdk,
49
- currentParams: providedParams,
50
- resolvedParams,
51
- };
52
- if (functionallyRequired.length > 0) {
53
- const requiredParamNames = functionallyRequired.map((p) => p.name);
54
- const requiredResolutionOrder = getResolutionOrderForParams(requiredParamNames);
55
- const orderedRequiredParams = requiredResolutionOrder
56
- .map((paramName) => functionallyRequired.find((p) => p.name === paramName))
57
- .filter((param) => param !== undefined);
58
- for (const param of orderedRequiredParams) {
59
- try {
60
- const value = await this.resolveParameter(param, context);
61
- this.setNestedValue(resolvedParams, param.path, value);
62
- // Update context with newly resolved value
63
- context.resolvedParams = resolvedParams;
64
- }
65
- catch (error) {
66
- if (this.isUserCancellation(error)) {
67
- console.log(chalk.yellow("\n\nOperation cancelled by user"));
68
- process.exit(0);
69
- }
70
- console.error(chalk.red(`Failed to resolve ${param.name}:`), error);
71
- throw error;
72
- }
73
- }
74
- }
75
- // 3. Ask user if they want to resolve truly optional parameters
76
- if (trulyOptional.length > 0) {
77
- const optionalNames = trulyOptional.map((p) => p.name).join(", ");
78
- const shouldResolveOptional = await inquirer.prompt([
79
- {
80
- type: "confirm",
81
- name: "resolveOptional",
82
- message: `Would you like to be prompted for optional parameters (${optionalNames})?`,
83
- default: false,
84
- },
85
- ]);
86
- if (shouldResolveOptional.resolveOptional) {
87
- // Resolve optional parameters using their resolvers
88
- const optionalParamNames = trulyOptional.map((p) => p.name);
89
- const optionalResolutionOrder = getResolutionOrderForParams(optionalParamNames);
90
- const orderedOptionalParams = optionalResolutionOrder
91
- .map((paramName) => trulyOptional.find((p) => p.name === paramName))
92
- .filter((param) => param !== undefined);
93
- for (const param of orderedOptionalParams) {
94
- try {
95
- const value = await this.resolveParameter(param, context);
96
- this.setNestedValue(resolvedParams, param.path, value);
97
- // Update context with newly resolved value
98
- context.resolvedParams = resolvedParams;
99
- }
100
- catch (error) {
101
- if (this.isUserCancellation(error)) {
102
- console.log(chalk.yellow("\n\nOperation cancelled by user"));
103
- process.exit(0);
104
- }
105
- console.error(chalk.red(`Failed to resolve ${param.name}:`), error);
106
- throw error;
107
- }
108
- }
109
- }
110
- }
111
- // 3. Validate final parameters
112
- const finalResult = schema.safeParse(resolvedParams);
113
- if (!finalResult.success) {
114
- console.error(chalk.red("❌ Parameter validation failed after resolution:"));
115
- throw finalResult.error;
116
- }
117
- return finalResult.data;
118
- }
119
- extractParametersFromSchema(schema) {
120
- const parameters = [];
121
- // Only handle ZodObject at the top level
122
- if (schema instanceof z.ZodObject) {
123
- const shape = schema.shape;
124
- for (const [key, fieldSchema] of Object.entries(shape)) {
125
- const param = this.analyzeFieldSchema(key, fieldSchema);
126
- if (param) {
127
- parameters.push(param);
128
- }
129
- }
130
- }
131
- return parameters;
132
- }
133
- analyzeFieldSchema(fieldName, fieldSchema) {
134
- let baseSchema = fieldSchema;
135
- let isRequired = true;
136
- // Check if field is optional or has default
137
- if (baseSchema instanceof z.ZodOptional) {
138
- isRequired = false;
139
- baseSchema = baseSchema._def.innerType;
140
- }
141
- if (baseSchema instanceof z.ZodDefault) {
142
- isRequired = false;
143
- baseSchema = baseSchema._def.innerType;
144
- }
145
- return this.createResolvableParameter([fieldName], baseSchema, isRequired);
146
- }
147
- createResolvableParameter(path, schema, isRequired) {
148
- if (path.length === 0)
149
- return null;
150
- const name = path[path.length - 1];
151
- return {
152
- name,
153
- path,
154
- schema,
155
- description: schema.description,
156
- isRequired,
157
- };
158
- }
159
- async resolveParameter(param, context) {
160
- const resolver = getResolver(param.name);
161
- if (!resolver) {
162
- throw new Error(`No resolver found for parameter: ${param.name}`);
163
- }
164
- console.log(chalk.blue(`\n🔍 Resolving ${param.name}...`));
165
- if (resolver.type === "static") {
166
- // Static resolver - just prompt for input
167
- const promptConfig = {
168
- type: resolver.inputType === "password" ? "password" : "input",
169
- name: param.name,
170
- message: `Enter ${param.name}:`,
171
- ...(resolver.placeholder && { default: resolver.placeholder }),
172
- };
173
- const answers = await inquirer.prompt([promptConfig]);
174
- return answers[param.name];
175
- }
176
- else if (resolver.type === "dynamic") {
177
- // Dynamic resolver - fetch options and prompt for selection
178
- try {
179
- console.log(chalk.gray(`Fetching options for ${param.name}...`));
180
- const items = await resolver.fetch(context.sdk, context.resolvedParams);
181
- if (!items || items.length === 0) {
182
- throw new Error(`No options available for ${param.name}`);
183
- }
184
- const promptConfig = resolver.prompt(items, context.resolvedParams);
185
- const answers = await inquirer.prompt([promptConfig]);
186
- return answers[param.name];
187
- }
188
- catch (error) {
189
- console.error(chalk.red(`Failed to fetch options for ${param.name}:`), error instanceof Error ? error.message : error);
190
- throw error;
191
- }
192
- }
193
- else if (resolver.type === "fields") {
194
- // Fields resolver - fetch field definitions and prompt for each input
195
- try {
196
- console.log(chalk.gray(`Fetching input fields for ${param.name}...`));
197
- const fields = await resolver.fetch(context.sdk, context.resolvedParams);
198
- if (!fields || fields.length === 0) {
199
- console.log(chalk.yellow(`No input fields required for this action.`));
200
- return {};
201
- }
202
- const inputs = {};
203
- // Separate required and optional fields
204
- const requiredFields = fields.filter((field) => field.required);
205
- const optionalFields = fields.filter((field) => !field.required);
206
- // First, prompt for all required fields
207
- if (requiredFields.length > 0) {
208
- console.log(chalk.blue(`\n📝 Please provide values for the following input fields:`));
209
- for (const field of requiredFields) {
210
- await this.promptForField(field, inputs);
211
- }
212
- }
213
- // Then ask if user wants to configure optional fields
214
- if (optionalFields.length > 0) {
215
- console.log(chalk.gray(`\nThere are ${optionalFields.length} optional field(s) available.`));
216
- let shouldConfigureOptional;
217
- try {
218
- shouldConfigureOptional = await inquirer.prompt([
219
- {
220
- type: "confirm",
221
- name: "configure",
222
- message: "Would you like to configure optional fields?",
223
- default: false,
224
- },
225
- ]);
226
- }
227
- catch (error) {
228
- if (this.isUserCancellation(error)) {
229
- console.log(chalk.yellow("\n\nOperation cancelled by user"));
230
- process.exit(0);
231
- }
232
- throw error;
233
- }
234
- if (shouldConfigureOptional.configure) {
235
- console.log(chalk.cyan(`\nOptional fields:`));
236
- for (const field of optionalFields) {
237
- await this.promptForField(field, inputs);
238
- }
239
- }
240
- }
241
- return inputs;
242
- }
243
- catch (error) {
244
- console.error(chalk.red(`Failed to fetch fields for ${param.name}:`), error instanceof Error ? error.message : error);
245
- throw error;
246
- }
247
- }
248
- throw new Error(`Unknown resolver type for ${param.name}`);
249
- }
250
- getNestedValue(obj, path) {
251
- return path.reduce((current, key) => current?.[key], obj);
252
- }
253
- setNestedValue(obj, path, value) {
254
- const lastKey = path[path.length - 1];
255
- const parent = path.slice(0, -1).reduce((current, key) => {
256
- if (!(key in current)) {
257
- current[key] = {};
258
- }
259
- return current[key];
260
- }, obj);
261
- parent[lastKey] = value;
262
- }
263
- async promptForField(field, inputs) {
264
- const fieldPrompt = {
265
- type: field.type === "boolean" ? "confirm" : "input",
266
- name: field.key,
267
- message: `${field.label || field.key}${field.required ? " (required)" : " (optional)"}:`,
268
- ...(field.helpText && { prefix: chalk.gray(`ℹ ${field.helpText}\n`) }),
269
- ...(field.default && { default: field.default }),
270
- };
271
- if (field.choices && field.choices.length > 0) {
272
- fieldPrompt.type = "list";
273
- fieldPrompt.choices = field.choices.map((choice) => ({
274
- name: choice.label || choice.value,
275
- value: choice.value,
276
- }));
277
- }
278
- try {
279
- const answer = await inquirer.prompt([fieldPrompt]);
280
- if (answer[field.key] !== undefined && answer[field.key] !== "") {
281
- inputs[field.key] = answer[field.key];
282
- }
283
- else if (field.required) {
284
- throw new Error(`Required field ${field.key} cannot be empty`);
285
- }
286
- }
287
- catch (error) {
288
- if (this.isUserCancellation(error)) {
289
- console.log(chalk.yellow("\n\nOperation cancelled by user"));
290
- process.exit(0);
291
- }
292
- throw error;
293
- }
294
- }
295
- isUserCancellation(error) {
296
- return (error?.name === "ExitPromptError" ||
297
- error?.message?.includes("User force closed") ||
298
- error?.isTTYError);
299
- }
300
- }
@@ -1,2 +0,0 @@
1
- import { z } from "zod";
2
- export declare function formatItemsFromSchema(inputSchema: z.ZodType, items: any[]): void;
@@ -1,71 +0,0 @@
1
- import chalk from "chalk";
2
- function getFormatMetadata(schema) {
3
- return schema?._def?.formatMeta;
4
- }
5
- function getOutputSchema(schema) {
6
- return schema?._def?.outputSchema;
7
- }
8
- // ============================================================================
9
- // Generic Schema-Driven Formatter
10
- // ============================================================================
11
- export function formatItemsFromSchema(inputSchema, items) {
12
- // Get the output schema and its format metadata
13
- const outputSchema = getOutputSchema(inputSchema);
14
- if (!outputSchema) {
15
- // Fallback to generic formatting if no output schema
16
- formatItemsGeneric(items);
17
- return;
18
- }
19
- const formatMeta = getFormatMetadata(outputSchema);
20
- if (!formatMeta) {
21
- // Fallback to generic formatting if no format metadata
22
- formatItemsGeneric(items);
23
- return;
24
- }
25
- // Format each item using the schema metadata
26
- items.forEach((item, index) => {
27
- formatSingleItem(item, index, formatMeta);
28
- });
29
- }
30
- function formatSingleItem(item, index, formatMeta) {
31
- // Get the formatted item from the format function
32
- const formatted = formatMeta.format(item);
33
- // Build the main title line
34
- let titleLine = `${chalk.gray(`${index + 1}.`)} ${chalk.cyan(formatted.title)}`;
35
- if (formatted.subtitle) {
36
- titleLine += ` ${chalk.gray(formatted.subtitle)}`;
37
- }
38
- console.log(titleLine);
39
- // Format detail lines
40
- for (const detail of formatted.details) {
41
- const styledText = applyStyle(detail.text, detail.style);
42
- console.log(` ${styledText}`);
43
- }
44
- console.log(); // Empty line between items
45
- }
46
- function applyStyle(value, style) {
47
- switch (style) {
48
- case "dim":
49
- return chalk.dim(value);
50
- case "accent":
51
- return chalk.magenta(value);
52
- case "warning":
53
- return chalk.red(value);
54
- case "success":
55
- return chalk.green(value);
56
- case "normal":
57
- default:
58
- return chalk.blue(value);
59
- }
60
- }
61
- function formatItemsGeneric(items) {
62
- // Fallback formatting for items without schema metadata
63
- items.forEach((item, index) => {
64
- const name = item.name || item.key || item.id || "Item";
65
- console.log(`${chalk.gray(`${index + 1}.`)} ${chalk.cyan(name)}`);
66
- if (item.description) {
67
- console.log(` ${chalk.dim(item.description)}`);
68
- }
69
- console.log();
70
- });
71
- }
@@ -1,2 +0,0 @@
1
- declare const serializeAsync: <R, A extends []>(fn: (...args: A) => Promise<R>) => ((...args: A) => Promise<R>);
2
- export default serializeAsync;
@@ -1,16 +0,0 @@
1
- import { createHash } from "node:crypto";
2
- const promises = {};
3
- const serializeAsync = (fn) => async (...args) => {
4
- const hash = createHash("sha256")
5
- .update(fn.toString(), "utf8")
6
- .digest()
7
- .toString("hex");
8
- const promise = promises[hash];
9
- if (!promise) {
10
- promises[hash] = fn(...args).finally(() => {
11
- delete promises[hash];
12
- });
13
- }
14
- return promises[hash];
15
- };
16
- export default serializeAsync;
@@ -1 +0,0 @@
1
- export declare const spinPromise: <T>(promise: Promise<T>, text: string) => Promise<T>;
@@ -1,13 +0,0 @@
1
- import ora from "ora";
2
- export const spinPromise = async (promise, text) => {
3
- const spinner = ora(text).start();
4
- try {
5
- const result = await promise;
6
- spinner.succeed();
7
- return result;
8
- }
9
- catch (error) {
10
- spinner.fail();
11
- throw error;
12
- }
13
- };