@zapier/zapier-sdk-cli 0.34.10 → 0.34.11
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 +9 -0
- package/dist/cli.cjs +138 -134
- package/dist/cli.mjs +139 -135
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +1 -1
- package/dist/package.json +1 -1
- package/dist/src/utils/parameter-resolver.d.ts +1 -1
- package/dist/src/utils/parameter-resolver.js +144 -140
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
package/dist/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import type
|
|
2
|
+
import { type ZapierSdk } from "@zapier/zapier-sdk";
|
|
3
3
|
export declare class SchemaParameterResolver {
|
|
4
4
|
resolveParameters(schema: z.ZodSchema, providedParams: unknown, sdk: ZapierSdk, functionName?: string): Promise<unknown>;
|
|
5
5
|
private extractParametersFromSchema;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import inquirer from "inquirer";
|
|
2
2
|
import chalk from "chalk";
|
|
3
3
|
import { z } from "zod";
|
|
4
|
+
import { runWithTelemetryContext, } from "@zapier/zapier-sdk";
|
|
4
5
|
import { ZapierCliUserCancellationError } from "./errors";
|
|
5
6
|
// ============================================================================
|
|
6
7
|
// Local Resolution Helper Functions
|
|
@@ -50,146 +51,114 @@ function getLocalResolutionOrderForParams(paramNames, resolvers) {
|
|
|
50
51
|
// ============================================================================
|
|
51
52
|
export class SchemaParameterResolver {
|
|
52
53
|
async resolveParameters(schema, providedParams, sdk, functionName) {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
return false;
|
|
76
|
-
});
|
|
77
|
-
// Parameters that should always be prompted for directly, but can be skipped
|
|
78
|
-
const alwaysPrompt = missingResolvable.filter((param) => {
|
|
79
|
-
if (functionallyRequired.includes(param))
|
|
80
|
-
return false;
|
|
81
|
-
// connectionId should always be prompted for (since it's usually needed)
|
|
82
|
-
// but can be skipped with "Continue without connection"
|
|
83
|
-
if (param.name === "connectionId") {
|
|
84
|
-
return true;
|
|
85
|
-
}
|
|
86
|
-
return false;
|
|
87
|
-
});
|
|
88
|
-
const trulyOptional = missingResolvable.filter((param) => !functionallyRequired.includes(param) && !alwaysPrompt.includes(param));
|
|
89
|
-
if (parseResult.success &&
|
|
90
|
-
functionallyRequired.length === 0 &&
|
|
91
|
-
alwaysPrompt.length === 0) {
|
|
92
|
-
return parseResult.data;
|
|
93
|
-
}
|
|
94
|
-
if (functionallyRequired.length === 0 && alwaysPrompt.length === 0) {
|
|
95
|
-
// No functionally required parameters missing, but check if we can parse
|
|
96
|
-
if (!parseResult.success) {
|
|
97
|
-
throw parseResult.error;
|
|
98
|
-
}
|
|
99
|
-
return parseResult.data;
|
|
100
|
-
}
|
|
101
|
-
// 2. Resolve functionally required parameters first
|
|
102
|
-
const resolvedParams = { ...providedParams };
|
|
103
|
-
const context = {
|
|
104
|
-
sdk,
|
|
105
|
-
currentParams: providedParams,
|
|
106
|
-
resolvedParams,
|
|
107
|
-
functionName,
|
|
108
|
-
};
|
|
109
|
-
// Get local resolvers for this function
|
|
110
|
-
const localResolvers = this.getLocalResolvers(sdk, functionName);
|
|
111
|
-
if (functionallyRequired.length > 0) {
|
|
112
|
-
const requiredParamNames = functionallyRequired.map((p) => p.name);
|
|
113
|
-
const requiredResolutionOrder = getLocalResolutionOrderForParams(requiredParamNames, localResolvers);
|
|
114
|
-
// Find all parameters that need to be resolved (including dependencies)
|
|
115
|
-
// from the available resolvable parameters
|
|
116
|
-
const orderedRequiredParams = requiredResolutionOrder
|
|
117
|
-
.map((paramName) => {
|
|
118
|
-
// First try to find in functionally required
|
|
119
|
-
let param = functionallyRequired.find((p) => p.name === paramName);
|
|
120
|
-
// If not found, try always prompt (for dependencies like connectionId)
|
|
121
|
-
if (!param) {
|
|
122
|
-
param = alwaysPrompt.find((p) => p.name === paramName);
|
|
123
|
-
}
|
|
124
|
-
// If not found, try truly optional (for other dependencies)
|
|
125
|
-
if (!param) {
|
|
126
|
-
param = trulyOptional.find((p) => p.name === paramName);
|
|
127
|
-
}
|
|
128
|
-
return param;
|
|
129
|
-
})
|
|
130
|
-
.filter((param) => param !== undefined);
|
|
131
|
-
for (const param of orderedRequiredParams) {
|
|
132
|
-
try {
|
|
133
|
-
const value = await this.resolveParameter(param, context, functionName);
|
|
134
|
-
this.setNestedValue(resolvedParams, param.path, value);
|
|
135
|
-
// Update context with newly resolved value
|
|
136
|
-
context.resolvedParams = resolvedParams;
|
|
54
|
+
return runWithTelemetryContext(async () => {
|
|
55
|
+
// 1. Try to parse with current parameters
|
|
56
|
+
const parseResult = schema.safeParse(providedParams);
|
|
57
|
+
// Get all schema parameters to check which ones have resolvers
|
|
58
|
+
const allParams = this.extractParametersFromSchema(schema);
|
|
59
|
+
const resolvableParams = allParams.filter((param) => this.hasResolver(param.name, sdk, functionName));
|
|
60
|
+
// Get all missing parameters that have resolvers
|
|
61
|
+
const missingResolvable = resolvableParams.filter((param) => {
|
|
62
|
+
const hasValue = this.getNestedValue(providedParams, param.path) !== undefined;
|
|
63
|
+
return !hasValue;
|
|
64
|
+
});
|
|
65
|
+
// Determine parameter resolution categories:
|
|
66
|
+
// - functionally required: must be provided (inputs)
|
|
67
|
+
// - always prompt: should be prompted for but can be skipped (connectionId)
|
|
68
|
+
// - truly optional: only ask if user wants to be prompted
|
|
69
|
+
const functionallyRequired = missingResolvable.filter((param) => {
|
|
70
|
+
// Schema-required parameters are always functionally required
|
|
71
|
+
if (param.isRequired)
|
|
72
|
+
return true;
|
|
73
|
+
// Only inputs is functionally required for run-action
|
|
74
|
+
if (param.name === "inputs") {
|
|
75
|
+
return true;
|
|
137
76
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
77
|
+
return false;
|
|
78
|
+
});
|
|
79
|
+
// Parameters that should always be prompted for directly, but can be skipped
|
|
80
|
+
const alwaysPrompt = missingResolvable.filter((param) => {
|
|
81
|
+
if (functionallyRequired.includes(param))
|
|
82
|
+
return false;
|
|
83
|
+
// connectionId should always be prompted for (since it's usually needed)
|
|
84
|
+
// but can be skipped with "Continue without connection"
|
|
85
|
+
if (param.name === "connectionId") {
|
|
86
|
+
return true;
|
|
144
87
|
}
|
|
88
|
+
return false;
|
|
89
|
+
});
|
|
90
|
+
const trulyOptional = missingResolvable.filter((param) => !functionallyRequired.includes(param) &&
|
|
91
|
+
!alwaysPrompt.includes(param));
|
|
92
|
+
if (parseResult.success &&
|
|
93
|
+
functionallyRequired.length === 0 &&
|
|
94
|
+
alwaysPrompt.length === 0) {
|
|
95
|
+
return parseResult.data;
|
|
145
96
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
}
|
|
151
|
-
// 3. Resolve parameters that should always be prompted for (but can be skipped)
|
|
152
|
-
if (alwaysPrompt.length > 0) {
|
|
153
|
-
const alwaysPromptNames = alwaysPrompt.map((p) => p.name);
|
|
154
|
-
const alwaysPromptResolutionOrder = getLocalResolutionOrderForParams(alwaysPromptNames, localResolvers);
|
|
155
|
-
const orderedAlwaysPromptParams = alwaysPromptResolutionOrder
|
|
156
|
-
.map((paramName) => alwaysPrompt.find((p) => p.name === paramName))
|
|
157
|
-
.filter((param) => param !== undefined);
|
|
158
|
-
for (const param of orderedAlwaysPromptParams) {
|
|
159
|
-
try {
|
|
160
|
-
const value = await this.resolveParameter(param, context, functionName);
|
|
161
|
-
this.setNestedValue(resolvedParams, param.path, value);
|
|
162
|
-
// Update context with newly resolved value
|
|
163
|
-
context.resolvedParams = resolvedParams;
|
|
97
|
+
if (functionallyRequired.length === 0 && alwaysPrompt.length === 0) {
|
|
98
|
+
// No functionally required parameters missing, but check if we can parse
|
|
99
|
+
if (!parseResult.success) {
|
|
100
|
+
throw parseResult.error;
|
|
164
101
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
102
|
+
return parseResult.data;
|
|
103
|
+
}
|
|
104
|
+
// 2. Resolve functionally required parameters first
|
|
105
|
+
const resolvedParams = { ...providedParams };
|
|
106
|
+
const context = {
|
|
107
|
+
sdk,
|
|
108
|
+
currentParams: providedParams,
|
|
109
|
+
resolvedParams,
|
|
110
|
+
functionName,
|
|
111
|
+
};
|
|
112
|
+
// Get local resolvers for this function
|
|
113
|
+
const localResolvers = this.getLocalResolvers(sdk, functionName);
|
|
114
|
+
if (functionallyRequired.length > 0) {
|
|
115
|
+
const requiredParamNames = functionallyRequired.map((p) => p.name);
|
|
116
|
+
const requiredResolutionOrder = getLocalResolutionOrderForParams(requiredParamNames, localResolvers);
|
|
117
|
+
// Find all parameters that need to be resolved (including dependencies)
|
|
118
|
+
// from the available resolvable parameters
|
|
119
|
+
const orderedRequiredParams = requiredResolutionOrder
|
|
120
|
+
.map((paramName) => {
|
|
121
|
+
// First try to find in functionally required
|
|
122
|
+
let param = functionallyRequired.find((p) => p.name === paramName);
|
|
123
|
+
// If not found, try always prompt (for dependencies like connectionId)
|
|
124
|
+
if (!param) {
|
|
125
|
+
param = alwaysPrompt.find((p) => p.name === paramName);
|
|
126
|
+
}
|
|
127
|
+
// If not found, try truly optional (for other dependencies)
|
|
128
|
+
if (!param) {
|
|
129
|
+
param = trulyOptional.find((p) => p.name === paramName);
|
|
130
|
+
}
|
|
131
|
+
return param;
|
|
132
|
+
})
|
|
133
|
+
.filter((param) => param !== undefined);
|
|
134
|
+
for (const param of orderedRequiredParams) {
|
|
135
|
+
try {
|
|
136
|
+
const value = await this.resolveParameter(param, context, functionName);
|
|
137
|
+
this.setNestedValue(resolvedParams, param.path, value);
|
|
138
|
+
// Update context with newly resolved value
|
|
139
|
+
context.resolvedParams = resolvedParams;
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
if (this.isUserCancellation(error)) {
|
|
143
|
+
console.log(chalk.yellow("\n\nOperation cancelled by user"));
|
|
144
|
+
throw new ZapierCliUserCancellationError();
|
|
145
|
+
}
|
|
146
|
+
throw error;
|
|
169
147
|
}
|
|
170
|
-
throw error;
|
|
171
148
|
}
|
|
149
|
+
// Remove resolved dependencies from other categories to avoid double-prompting
|
|
150
|
+
const resolvedParamNames = new Set(orderedRequiredParams.map((p) => p.name));
|
|
151
|
+
alwaysPrompt.splice(0, alwaysPrompt.length, ...alwaysPrompt.filter((p) => !resolvedParamNames.has(p.name)));
|
|
152
|
+
trulyOptional.splice(0, trulyOptional.length, ...trulyOptional.filter((p) => !resolvedParamNames.has(p.name)));
|
|
172
153
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
type: "confirm",
|
|
180
|
-
name: "resolveOptional",
|
|
181
|
-
message: `Would you like to be prompted for optional parameters (${optionalNames})?`,
|
|
182
|
-
default: false,
|
|
183
|
-
},
|
|
184
|
-
]);
|
|
185
|
-
if (shouldResolveOptional.resolveOptional) {
|
|
186
|
-
// Resolve optional parameters using their resolvers
|
|
187
|
-
const optionalParamNames = trulyOptional.map((p) => p.name);
|
|
188
|
-
const optionalResolutionOrder = getLocalResolutionOrderForParams(optionalParamNames, localResolvers);
|
|
189
|
-
const orderedOptionalParams = optionalResolutionOrder
|
|
190
|
-
.map((paramName) => trulyOptional.find((p) => p.name === paramName))
|
|
154
|
+
// 3. Resolve parameters that should always be prompted for (but can be skipped)
|
|
155
|
+
if (alwaysPrompt.length > 0) {
|
|
156
|
+
const alwaysPromptNames = alwaysPrompt.map((p) => p.name);
|
|
157
|
+
const alwaysPromptResolutionOrder = getLocalResolutionOrderForParams(alwaysPromptNames, localResolvers);
|
|
158
|
+
const orderedAlwaysPromptParams = alwaysPromptResolutionOrder
|
|
159
|
+
.map((paramName) => alwaysPrompt.find((p) => p.name === paramName))
|
|
191
160
|
.filter((param) => param !== undefined);
|
|
192
|
-
for (const param of
|
|
161
|
+
for (const param of orderedAlwaysPromptParams) {
|
|
193
162
|
try {
|
|
194
163
|
const value = await this.resolveParameter(param, context, functionName);
|
|
195
164
|
this.setNestedValue(resolvedParams, param.path, value);
|
|
@@ -205,14 +174,49 @@ export class SchemaParameterResolver {
|
|
|
205
174
|
}
|
|
206
175
|
}
|
|
207
176
|
}
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
177
|
+
// 4. Ask user if they want to resolve truly optional parameters
|
|
178
|
+
if (trulyOptional.length > 0) {
|
|
179
|
+
const optionalNames = trulyOptional.map((p) => p.name).join(", ");
|
|
180
|
+
const shouldResolveOptional = await inquirer.prompt([
|
|
181
|
+
{
|
|
182
|
+
type: "confirm",
|
|
183
|
+
name: "resolveOptional",
|
|
184
|
+
message: `Would you like to be prompted for optional parameters (${optionalNames})?`,
|
|
185
|
+
default: false,
|
|
186
|
+
},
|
|
187
|
+
]);
|
|
188
|
+
if (shouldResolveOptional.resolveOptional) {
|
|
189
|
+
// Resolve optional parameters using their resolvers
|
|
190
|
+
const optionalParamNames = trulyOptional.map((p) => p.name);
|
|
191
|
+
const optionalResolutionOrder = getLocalResolutionOrderForParams(optionalParamNames, localResolvers);
|
|
192
|
+
const orderedOptionalParams = optionalResolutionOrder
|
|
193
|
+
.map((paramName) => trulyOptional.find((p) => p.name === paramName))
|
|
194
|
+
.filter((param) => param !== undefined);
|
|
195
|
+
for (const param of orderedOptionalParams) {
|
|
196
|
+
try {
|
|
197
|
+
const value = await this.resolveParameter(param, context, functionName);
|
|
198
|
+
this.setNestedValue(resolvedParams, param.path, value);
|
|
199
|
+
// Update context with newly resolved value
|
|
200
|
+
context.resolvedParams = resolvedParams;
|
|
201
|
+
}
|
|
202
|
+
catch (error) {
|
|
203
|
+
if (this.isUserCancellation(error)) {
|
|
204
|
+
console.log(chalk.yellow("\n\nOperation cancelled by user"));
|
|
205
|
+
throw new ZapierCliUserCancellationError();
|
|
206
|
+
}
|
|
207
|
+
throw error;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
// 5. Validate final parameters
|
|
213
|
+
const finalResult = schema.safeParse(resolvedParams);
|
|
214
|
+
if (!finalResult.success) {
|
|
215
|
+
console.error(chalk.red("❌ Parameter validation failed after resolution:"));
|
|
216
|
+
throw finalResult.error;
|
|
217
|
+
}
|
|
218
|
+
return finalResult.data;
|
|
219
|
+
});
|
|
216
220
|
}
|
|
217
221
|
extractParametersFromSchema(schema) {
|
|
218
222
|
const parameters = [];
|