@zapier/zapier-sdk-cli 0.66.2 → 0.66.3
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 +300 -1759
- package/dist/cli.mjs +264 -1722
- package/dist/experimental.cjs +1 -1
- package/dist/experimental.mjs +1 -1
- package/dist/index.cjs +2 -2
- package/dist/index.mjs +2 -2
- package/package.json +3 -3
package/dist/cli.mjs
CHANGED
|
@@ -1,1515 +1,44 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command, CommanderError, Option } from 'commander';
|
|
3
|
-
import { getConnectionPlugin, defineMethod, apiPluginRef, resolveCredentialsPluginRef, eventEmissionPluginRef, sdkOptionsPluginRef, declareOptionalProperty, OutputPropertySchema, ZapierBundleError, DEFAULT_CONFIG_PATH, declareMethod, ZapierValidationError, ZapierUnknownError, manifestPluginRef, defineResolver, defineMethodOverride, zapierCoreOptions, injectCliLogin, definePlugin, omitExports, zapierSdkPlugin, BaseSdkOptionsSchema, disposeSdk, isPermanentHttpError, invalidateCachedToken, batch, toSnakeCase, ZapierError, ZapierReleaseTriggerMessageSignal, createSdk as createSdk$1, CORE_OPTIONS_ID as CORE_OPTIONS_ID$1, SDK_OPTIONS_ID as SDK_OPTIONS_ID$1, addPlugin as addPlugin$1, getOrCreateApiClient, isCredentialsObject, ZapierAuthenticationError, ZapierAbortDrainSignal, buildApplicationLifecycleEvent, AuthMechanism, DEPRECATION_NOTICE_EVENT, runWithCallerContext, isPositional, createController, CoreCancelledSignal, resolvePlugin,
|
|
3
|
+
import { getConnectionPlugin, defineMethod, apiPluginRef, resolveCredentialsPluginRef, eventEmissionPluginRef, sdkOptionsPluginRef, declareOptionalProperty, OutputPropertySchema, ZapierBundleError, DEFAULT_CONFIG_PATH, declareMethod, ZapierValidationError, ZapierUnknownError, manifestPluginRef, defineResolver, defineMethodOverride, zapierCoreOptions, injectCliLogin, definePlugin, omitExports, zapierSdkPlugin, BaseSdkOptionsSchema, disposeSdk, isPermanentHttpError, invalidateCachedToken, batch, toSnakeCase, ZapierError, ZapierReleaseTriggerMessageSignal, createSdk as createSdk$1, CORE_OPTIONS_ID as CORE_OPTIONS_ID$1, SDK_OPTIONS_ID as SDK_OPTIONS_ID$1, addPlugin as addPlugin$1, getOrCreateApiClient, isCredentialsObject, ZapierAuthenticationError, ZapierAbortDrainSignal, buildApplicationLifecycleEvent, AuthMechanism, DEPRECATION_NOTICE_EVENT, runWithCallerContext, isPositional, createController, CoreCancelledSignal, resolvePlugin, formatErrorMessage, getOsInfo, getPlatformVersions, getAgent, getTtyContext, getCiPlatform, isCi, getReleaseId, getCurrentTimestamp, generateEventId, ZapierApprovalError } from '@zapier/zapier-sdk';
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
import inquirer from 'inquirer';
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import ora from 'ora';
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
import
|
|
12
|
-
import
|
|
13
|
-
import
|
|
14
|
-
import
|
|
15
|
-
import
|
|
16
|
-
import
|
|
17
|
-
import
|
|
18
|
-
import
|
|
19
|
-
import
|
|
20
|
-
import
|
|
21
|
-
import
|
|
22
|
-
import
|
|
23
|
-
import
|
|
24
|
-
import
|
|
25
|
-
import
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
28
|
-
import
|
|
29
|
-
import
|
|
30
|
-
import
|
|
31
|
-
import
|
|
32
|
-
import
|
|
33
|
-
import {
|
|
34
|
-
import
|
|
35
|
-
import
|
|
36
|
-
import
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
var
|
|
40
|
-
var
|
|
41
|
-
|
|
42
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
43
|
-
};
|
|
44
|
-
var ZapierCliError = class extends ZapierError {
|
|
45
|
-
};
|
|
46
|
-
var ZapierCliUserCancellationError = class extends ZapierCliError {
|
|
47
|
-
constructor(message = "Operation cancelled by user") {
|
|
48
|
-
super(message);
|
|
49
|
-
this.name = "ZapierCliUserCancellationError";
|
|
50
|
-
this.code = "ZAPIER_CLI_USER_CANCELLATION";
|
|
51
|
-
this.exitCode = 0;
|
|
52
|
-
}
|
|
53
|
-
};
|
|
54
|
-
var ZapierCliExitError = class extends ZapierCliError {
|
|
55
|
-
constructor(message, exitCode = 1) {
|
|
56
|
-
super(message);
|
|
57
|
-
this.name = "ZapierCliExitError";
|
|
58
|
-
this.code = "ZAPIER_CLI_EXIT";
|
|
59
|
-
this.exitCode = exitCode;
|
|
60
|
-
}
|
|
61
|
-
};
|
|
62
|
-
var ZapierCliValidationError = class _ZapierCliValidationError extends ZapierCliError {
|
|
63
|
-
constructor(message, options = {}) {
|
|
64
|
-
super(message);
|
|
65
|
-
this.exitCode = 1;
|
|
66
|
-
this.name = options.name ?? "ZapierCliValidationError";
|
|
67
|
-
this.code = options.code ?? "ZAPIER_CLI_VALIDATION_ERROR";
|
|
68
|
-
}
|
|
69
|
-
withMessage(message) {
|
|
70
|
-
return new _ZapierCliValidationError(message, {
|
|
71
|
-
name: this.name,
|
|
72
|
-
code: this.code
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
};
|
|
76
|
-
var ZapierCliMissingParametersError = class extends ZapierCliError {
|
|
77
|
-
constructor(params) {
|
|
78
|
-
super(
|
|
79
|
-
`Missing required parameters: ${params.map((p) => p.name).join(", ")}`
|
|
80
|
-
);
|
|
81
|
-
this.name = "ZapierCliMissingParametersError";
|
|
82
|
-
this.code = "ZAPIER_CLI_MISSING_PARAMETERS";
|
|
83
|
-
this.exitCode = 1;
|
|
84
|
-
this.params = params;
|
|
85
|
-
}
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
// src/utils/parameter-resolver.ts
|
|
89
|
-
function formatZodError(error) {
|
|
90
|
-
return error.issues.map((issue) => {
|
|
91
|
-
const field = issue.path.length > 0 ? issue.path.join(".") : "input";
|
|
92
|
-
return `${field}: ${issue.message}`;
|
|
93
|
-
}).join(", ");
|
|
94
|
-
}
|
|
95
|
-
function getLocalResolutionOrder(paramName, resolvers, resolved = /* @__PURE__ */ new Set()) {
|
|
96
|
-
const resolver = resolvers[paramName];
|
|
97
|
-
if (!resolver || resolver.type === "static" || resolver.type === "constant") {
|
|
98
|
-
return [paramName];
|
|
99
|
-
}
|
|
100
|
-
const order = [];
|
|
101
|
-
if ("depends" in resolver && resolver.depends) {
|
|
102
|
-
for (const dependency of resolver.depends) {
|
|
103
|
-
if (!resolved.has(dependency)) {
|
|
104
|
-
order.push(...getLocalResolutionOrder(dependency, resolvers, resolved));
|
|
105
|
-
resolved.add(dependency);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
if (!resolved.has(paramName)) {
|
|
110
|
-
order.push(paramName);
|
|
111
|
-
resolved.add(paramName);
|
|
112
|
-
}
|
|
113
|
-
return order;
|
|
114
|
-
}
|
|
115
|
-
function getLocalResolutionOrderForParams(paramNames, resolvers) {
|
|
116
|
-
const resolved = /* @__PURE__ */ new Set();
|
|
117
|
-
const order = [];
|
|
118
|
-
for (const paramName of paramNames) {
|
|
119
|
-
const paramOrder = getLocalResolutionOrder(paramName, resolvers, resolved);
|
|
120
|
-
for (const param of paramOrder) {
|
|
121
|
-
if (!order.includes(param)) {
|
|
122
|
-
order.push(param);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
return order;
|
|
127
|
-
}
|
|
128
|
-
function unwrapSchema(schema) {
|
|
129
|
-
let current = schema;
|
|
130
|
-
while (current instanceof z.ZodOptional || current instanceof z.ZodDefault || current instanceof z.ZodNullable) {
|
|
131
|
-
current = current._zod.def.innerType;
|
|
132
|
-
}
|
|
133
|
-
return current;
|
|
134
|
-
}
|
|
135
|
-
function coerceToSchemaType(value, schema) {
|
|
136
|
-
if (typeof value !== "string") return value;
|
|
137
|
-
const base = unwrapSchema(schema);
|
|
138
|
-
if (base instanceof z.ZodNumber) {
|
|
139
|
-
const n = Number(value);
|
|
140
|
-
return Number.isNaN(n) ? value : n;
|
|
141
|
-
}
|
|
142
|
-
if (base instanceof z.ZodBoolean) {
|
|
143
|
-
if (value === "true") return true;
|
|
144
|
-
if (value === "false") return false;
|
|
145
|
-
}
|
|
146
|
-
return value;
|
|
147
|
-
}
|
|
148
|
-
function renderChoiceLabel(choice) {
|
|
149
|
-
const baseName = choice.label ?? choice.name ?? "";
|
|
150
|
-
const alreadyNamed = choice.name === baseName;
|
|
151
|
-
let effectiveHint = choice.hint;
|
|
152
|
-
if (effectiveHint === void 0 && (typeof choice.value === "string" || typeof choice.value === "number")) {
|
|
153
|
-
effectiveHint = String(choice.value);
|
|
154
|
-
}
|
|
155
|
-
if (!effectiveHint || Array.isArray(effectiveHint) && effectiveHint.length === 0) {
|
|
156
|
-
return alreadyNamed ? choice : { ...choice, name: baseName };
|
|
157
|
-
}
|
|
158
|
-
const hintText = Array.isArray(effectiveHint) ? effectiveHint.join(", ") : effectiveHint;
|
|
159
|
-
if (hintText === baseName) {
|
|
160
|
-
return alreadyNamed ? choice : { ...choice, name: baseName };
|
|
161
|
-
}
|
|
162
|
-
return { ...choice, name: `${baseName} ${chalk.dim(`(${hintText})`)}` };
|
|
163
|
-
}
|
|
164
|
-
var SchemaParameterResolver = class {
|
|
165
|
-
constructor() {
|
|
166
|
-
this.debug = false;
|
|
167
|
-
this.spinner = null;
|
|
168
|
-
}
|
|
169
|
-
debugLog(message) {
|
|
170
|
-
if (this.debug) {
|
|
171
|
-
this.stopSpinner();
|
|
172
|
-
console.error(chalk.gray(`[Zapier CLI] ${message}`));
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
startSpinner() {
|
|
176
|
-
if (!this.debug && !this.spinner) {
|
|
177
|
-
this.spinner = ora({ text: "", spinner: "dots" }).start();
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
stopSpinner() {
|
|
181
|
-
if (this.spinner) {
|
|
182
|
-
this.spinner.stop();
|
|
183
|
-
this.spinner = null;
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
async resolveParameters(schema, providedParams, sdk, functionName, options) {
|
|
187
|
-
return runWithTelemetryContext(async () => {
|
|
188
|
-
this.debug = options?.debug ?? false;
|
|
189
|
-
const interactiveMode = (options?.interactiveMode ?? true) && !!process.stdin.isTTY;
|
|
190
|
-
const parseResult = schema.safeParse(providedParams);
|
|
191
|
-
const allParams = this.extractParametersFromSchema(schema);
|
|
192
|
-
const resolvableParams = allParams.filter(
|
|
193
|
-
(param) => this.hasResolver(param.name, sdk, functionName)
|
|
194
|
-
);
|
|
195
|
-
const missingResolvable = resolvableParams.filter((param) => {
|
|
196
|
-
const hasValue = this.getNestedValue(providedParams, param.path) !== void 0;
|
|
197
|
-
return !hasValue;
|
|
198
|
-
});
|
|
199
|
-
const required = missingResolvable.filter((param) => param.isRequired);
|
|
200
|
-
const optional = missingResolvable.filter((param) => !param.isRequired);
|
|
201
|
-
if (parseResult.success && required.length === 0 && optional.length === 0) {
|
|
202
|
-
return parseResult.data;
|
|
203
|
-
}
|
|
204
|
-
if (required.length === 0 && optional.length === 0) {
|
|
205
|
-
if (!parseResult.success) {
|
|
206
|
-
throw new ZapierCliValidationError(formatZodError(parseResult.error));
|
|
207
|
-
}
|
|
208
|
-
return parseResult.data;
|
|
209
|
-
}
|
|
210
|
-
const resolverConstants = this.getResolverConstants(sdk, functionName);
|
|
211
|
-
const resolvedParams = {
|
|
212
|
-
...resolverConstants,
|
|
213
|
-
...providedParams
|
|
214
|
-
};
|
|
215
|
-
const context = {
|
|
216
|
-
sdk,
|
|
217
|
-
currentParams: providedParams,
|
|
218
|
-
resolvedParams,
|
|
219
|
-
functionName
|
|
220
|
-
};
|
|
221
|
-
const localResolvers = this.getLocalResolvers(sdk, functionName);
|
|
222
|
-
if (required.length > 0) {
|
|
223
|
-
const requiredParamNames = required.map((p) => p.name);
|
|
224
|
-
const requiredResolutionOrder = getLocalResolutionOrderForParams(
|
|
225
|
-
requiredParamNames,
|
|
226
|
-
localResolvers
|
|
227
|
-
);
|
|
228
|
-
const orderedRequiredParams = requiredResolutionOrder.map((paramName) => {
|
|
229
|
-
let param = required.find((p) => p.name === paramName);
|
|
230
|
-
if (!param) {
|
|
231
|
-
param = optional.find((p) => p.name === paramName);
|
|
232
|
-
}
|
|
233
|
-
return param;
|
|
234
|
-
}).filter((param) => param !== void 0);
|
|
235
|
-
if (!interactiveMode) {
|
|
236
|
-
await this.resolveRequiredParamsNonInteractive(
|
|
237
|
-
orderedRequiredParams,
|
|
238
|
-
context,
|
|
239
|
-
resolvedParams,
|
|
240
|
-
functionName
|
|
241
|
-
);
|
|
242
|
-
} else {
|
|
243
|
-
for (const param of orderedRequiredParams) {
|
|
244
|
-
try {
|
|
245
|
-
const value = await this.resolveParameter(
|
|
246
|
-
param,
|
|
247
|
-
context,
|
|
248
|
-
functionName,
|
|
249
|
-
{ isOptional: !param.isRequired }
|
|
250
|
-
);
|
|
251
|
-
if (param.isRequired || value !== void 0) {
|
|
252
|
-
this.setNestedValue(resolvedParams, param.path, value);
|
|
253
|
-
context.resolvedParams = resolvedParams;
|
|
254
|
-
}
|
|
255
|
-
} catch (error) {
|
|
256
|
-
if (this.isUserCancellation(error)) {
|
|
257
|
-
console.log(chalk.yellow("\n\nOperation cancelled by user"));
|
|
258
|
-
throw new ZapierCliUserCancellationError();
|
|
259
|
-
}
|
|
260
|
-
throw error;
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
const resolvedParamNames = new Set(
|
|
265
|
-
orderedRequiredParams.map((p) => p.name)
|
|
266
|
-
);
|
|
267
|
-
optional.splice(
|
|
268
|
-
0,
|
|
269
|
-
optional.length,
|
|
270
|
-
...optional.filter((p) => !resolvedParamNames.has(p.name))
|
|
271
|
-
);
|
|
272
|
-
}
|
|
273
|
-
if (interactiveMode && optional.length > 0) {
|
|
274
|
-
const optionalParamNames = optional.map((p) => p.name);
|
|
275
|
-
const optionalResolutionOrder = getLocalResolutionOrderForParams(
|
|
276
|
-
optionalParamNames,
|
|
277
|
-
localResolvers
|
|
278
|
-
);
|
|
279
|
-
const orderedOptionalParams = optionalResolutionOrder.map((paramName) => optional.find((p) => p.name === paramName)).filter((param) => param !== void 0);
|
|
280
|
-
for (const param of orderedOptionalParams) {
|
|
281
|
-
try {
|
|
282
|
-
const value = await this.resolveParameter(
|
|
283
|
-
param,
|
|
284
|
-
context,
|
|
285
|
-
functionName,
|
|
286
|
-
{ isOptional: true }
|
|
287
|
-
);
|
|
288
|
-
if (value !== void 0) {
|
|
289
|
-
this.setNestedValue(resolvedParams, param.path, value);
|
|
290
|
-
context.resolvedParams = resolvedParams;
|
|
291
|
-
}
|
|
292
|
-
} catch (error) {
|
|
293
|
-
if (this.isUserCancellation(error)) {
|
|
294
|
-
console.log(chalk.yellow("\n\nOperation cancelled by user"));
|
|
295
|
-
throw new ZapierCliUserCancellationError();
|
|
296
|
-
}
|
|
297
|
-
throw error;
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
const finalResult = schema.safeParse(resolvedParams);
|
|
302
|
-
if (!finalResult.success) {
|
|
303
|
-
throw new ZapierCliValidationError(
|
|
304
|
-
`Parameter validation failed: ${formatZodError(finalResult.error)}`
|
|
305
|
-
);
|
|
306
|
-
}
|
|
307
|
-
return finalResult.data;
|
|
308
|
-
});
|
|
309
|
-
}
|
|
310
|
-
extractParametersFromSchema(schema) {
|
|
311
|
-
const parameters = [];
|
|
312
|
-
if (schema instanceof z.ZodObject) {
|
|
313
|
-
const shape = schema.shape;
|
|
314
|
-
for (const [key, fieldSchema] of Object.entries(shape)) {
|
|
315
|
-
const param = this.analyzeFieldSchema(key, fieldSchema);
|
|
316
|
-
if (param) {
|
|
317
|
-
parameters.push(param);
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
return parameters;
|
|
322
|
-
}
|
|
323
|
-
analyzeFieldSchema(fieldName, fieldSchema) {
|
|
324
|
-
let baseSchema = fieldSchema;
|
|
325
|
-
let isRequired = true;
|
|
326
|
-
if (baseSchema instanceof z.ZodOptional) {
|
|
327
|
-
isRequired = false;
|
|
328
|
-
baseSchema = baseSchema._zod.def.innerType;
|
|
329
|
-
}
|
|
330
|
-
if (baseSchema instanceof z.ZodDefault) {
|
|
331
|
-
isRequired = false;
|
|
332
|
-
baseSchema = baseSchema._zod.def.innerType;
|
|
333
|
-
}
|
|
334
|
-
return this.createResolvableParameter([fieldName], baseSchema, isRequired);
|
|
335
|
-
}
|
|
336
|
-
createResolvableParameter(path2, schema, isRequired) {
|
|
337
|
-
if (path2.length === 0) return null;
|
|
338
|
-
const name = path2[path2.length - 1];
|
|
339
|
-
return {
|
|
340
|
-
name,
|
|
341
|
-
path: path2,
|
|
342
|
-
schema,
|
|
343
|
-
description: schema.description,
|
|
344
|
-
isRequired
|
|
345
|
-
};
|
|
346
|
-
}
|
|
347
|
-
/**
|
|
348
|
-
* Calls `tryResolveWithoutPrompt` on a dynamic resolver.
|
|
349
|
-
* Returns the resolution result object, or null if unresolvable / throws.
|
|
350
|
-
* Note: { resolvedValue: undefined } is a valid result (e.g. connection when app has no auth);
|
|
351
|
-
* only a null return from the resolver itself means "could not auto-resolve".
|
|
352
|
-
*/
|
|
353
|
-
async tryAutoResolve(dynamicResolver, context) {
|
|
354
|
-
if (!dynamicResolver.tryResolveWithoutPrompt) return null;
|
|
355
|
-
try {
|
|
356
|
-
return await dynamicResolver.tryResolveWithoutPrompt(
|
|
357
|
-
context.sdk,
|
|
358
|
-
context.resolvedParams
|
|
359
|
-
);
|
|
360
|
-
} catch (err) {
|
|
361
|
-
console.warn(
|
|
362
|
-
`Auto-resolver threw unexpectedly; treating as unresolved. Error: ${err instanceof Error ? err.message : String(err)}`
|
|
363
|
-
);
|
|
364
|
-
return null;
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
/**
|
|
368
|
-
* Non-interactive resolution: auto-resolves what it can via tryAutoResolve,
|
|
369
|
-
* throws ZapierCliMissingParametersError for anything that requires user input.
|
|
370
|
-
*/
|
|
371
|
-
async resolveRequiredParamsNonInteractive(params, context, resolvedParams, functionName) {
|
|
372
|
-
const missingParams = [];
|
|
373
|
-
for (const param of params) {
|
|
374
|
-
const resolver = this.getResolver(param.name, context.sdk, functionName);
|
|
375
|
-
let autoResolved = null;
|
|
376
|
-
if (resolver?.type === "constant") {
|
|
377
|
-
autoResolved = {
|
|
378
|
-
resolvedValue: resolver.value
|
|
379
|
-
};
|
|
380
|
-
} else if (resolver?.type === "dynamic") {
|
|
381
|
-
autoResolved = await this.tryAutoResolve(
|
|
382
|
-
resolver,
|
|
383
|
-
context
|
|
384
|
-
);
|
|
385
|
-
}
|
|
386
|
-
if (autoResolved != null) {
|
|
387
|
-
this.setNestedValue(
|
|
388
|
-
resolvedParams,
|
|
389
|
-
param.path,
|
|
390
|
-
autoResolved.resolvedValue
|
|
391
|
-
);
|
|
392
|
-
context.resolvedParams = resolvedParams;
|
|
393
|
-
} else {
|
|
394
|
-
missingParams.push({
|
|
395
|
-
name: param.name,
|
|
396
|
-
// Required params render as positional CLI args (<name>); so do explicitly positional optional params.
|
|
397
|
-
isPositional: param.isRequired || isPositional(param.schema)
|
|
398
|
-
});
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
if (missingParams.length > 0) {
|
|
402
|
-
throw new ZapierCliMissingParametersError(missingParams);
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
/**
|
|
406
|
-
* Wrap a PromptConfig.validate so internal sentinels (Symbols) bypass
|
|
407
|
-
* it. The resolver's validator is intended for actual user values; our
|
|
408
|
-
* Skip / Custom / Load-more sentinels are internal control-flow and
|
|
409
|
-
* should pass through. Returns `undefined` when the resolver didn't
|
|
410
|
-
* supply a validator (so `await search({ ...rest })` doesn't get a
|
|
411
|
-
* pass-through identity function).
|
|
412
|
-
*/
|
|
413
|
-
wrapPromptValidate(validate) {
|
|
414
|
-
if (!validate) return void 0;
|
|
415
|
-
return (value) => typeof value === "symbol" ? true : validate(value);
|
|
416
|
-
}
|
|
417
|
-
/**
|
|
418
|
-
* Apply a PromptConfig.filter to a selected value, but only when the
|
|
419
|
-
* value is a real data choice (not an internal sentinel). @inquirer/search
|
|
420
|
-
* has no built-in filter hook, so the search-backed paths call this
|
|
421
|
-
* explicitly before returning.
|
|
422
|
-
*/
|
|
423
|
-
applyPromptFilter(filter, value) {
|
|
424
|
-
if (!filter || typeof value === "symbol") return value;
|
|
425
|
-
return filter(value);
|
|
426
|
-
}
|
|
427
|
-
/**
|
|
428
|
-
* If the resolver's PromptConfig sets a `default` value, move the
|
|
429
|
-
* matching choice to the front so it's the first selectable item in
|
|
430
|
-
* the rendered source. @inquirer/search has no built-in `default`
|
|
431
|
-
* option; first-selectable is what Enter picks, so reordering achieves
|
|
432
|
-
* the same semantics inquirer.prompt's list had natively.
|
|
433
|
-
*
|
|
434
|
-
* Returns the original array if no default is set or the default
|
|
435
|
-
* doesn't match any current choice.
|
|
436
|
-
*/
|
|
437
|
-
reorderForDefault(matches, defaultValue) {
|
|
438
|
-
if (defaultValue === void 0) return matches;
|
|
439
|
-
const idx = matches.findIndex((c) => c.value === defaultValue);
|
|
440
|
-
if (idx <= 0) return matches;
|
|
441
|
-
return [matches[idx], ...matches.slice(0, idx), ...matches.slice(idx + 1)];
|
|
442
|
-
}
|
|
443
|
-
/**
|
|
444
|
-
* Build the disabled "if you had X capability, more results would show"
|
|
445
|
-
* hints for any unmet capabilities the resolver declared. Returns the
|
|
446
|
-
* raw hint strings — callers wrap them into choice objects with whatever
|
|
447
|
-
* sentinel value they prefer (disabled choices' values are inert).
|
|
448
|
-
*/
|
|
449
|
-
async computeCapabilityHints(resolver, context) {
|
|
450
|
-
if (!resolver.requireCapabilities) return [];
|
|
451
|
-
const capContext = context.sdk.context;
|
|
452
|
-
if (!capContext.hasCapability) return [];
|
|
453
|
-
const messages = [];
|
|
454
|
-
for (const cap of resolver.requireCapabilities) {
|
|
455
|
-
const enabled = await capContext.hasCapability(cap);
|
|
456
|
-
if (!enabled) messages.push(buildCapabilityMessage(cap));
|
|
457
|
-
}
|
|
458
|
-
return messages;
|
|
459
|
-
}
|
|
460
|
-
/**
|
|
461
|
-
* Unpack a DynamicResolver.fetch result into the three shapes the caller
|
|
462
|
-
* cares about: a flat items array, an optional AsyncIterator for further
|
|
463
|
-
* pagination, and a hasMore flag. Centralizing keeps the AsyncIterable /
|
|
464
|
-
* `{data, nextCursor}` / `TItem[]` discrimination in one place — both
|
|
465
|
-
* the main dropdown loop and the search-mode flow consume it.
|
|
466
|
-
*
|
|
467
|
-
* The function is `async` for the AsyncIterable branch only (we eagerly
|
|
468
|
-
* consume the first page so callers don't have to discriminate). The
|
|
469
|
-
* other two branches return synchronously; an explicit Promise.resolve
|
|
470
|
-
* is unnecessary because async automatically wraps.
|
|
471
|
-
*
|
|
472
|
-
* Note: callers in search mode intentionally drop `pageIterator` /
|
|
473
|
-
* `hasMore` because each search() invocation re-prompts from scratch;
|
|
474
|
-
* pagination only matters when the prompt is the dropdown itself.
|
|
475
|
-
*/
|
|
476
|
-
async unpackFetchResult(fetchResult, promptLabel) {
|
|
477
|
-
if (fetchResult != null && typeof fetchResult === "object" && Symbol.asyncIterator in fetchResult) {
|
|
478
|
-
const pageIterator = fetchResult[Symbol.asyncIterator]();
|
|
479
|
-
const first = await pageIterator.next();
|
|
480
|
-
if (!first.done && first.value) {
|
|
481
|
-
return {
|
|
482
|
-
items: Array.isArray(first.value.data) ? first.value.data : [],
|
|
483
|
-
pageIterator,
|
|
484
|
-
hasMore: first.value.nextCursor != null
|
|
485
|
-
};
|
|
486
|
-
}
|
|
487
|
-
return { items: [], pageIterator, hasMore: false };
|
|
488
|
-
}
|
|
489
|
-
if (fetchResult != null && typeof fetchResult === "object" && "data" in fetchResult) {
|
|
490
|
-
const page = fetchResult;
|
|
491
|
-
const hasMore = page.nextCursor != null;
|
|
492
|
-
if (hasMore) {
|
|
493
|
-
this.debugLog(
|
|
494
|
-
`Resolver for ${promptLabel} has more pages but no iterator. Return the paginated result's .pages() instead of an awaited page to enable "Load more..." support.`
|
|
495
|
-
);
|
|
496
|
-
}
|
|
497
|
-
return {
|
|
498
|
-
items: Array.isArray(page.data) ? page.data : [],
|
|
499
|
-
pageIterator: null,
|
|
500
|
-
hasMore
|
|
501
|
-
};
|
|
502
|
-
}
|
|
503
|
-
return {
|
|
504
|
-
items: Array.isArray(fetchResult) ? fetchResult : [],
|
|
505
|
-
pageIterator: null,
|
|
506
|
-
hasMore: false
|
|
507
|
-
};
|
|
508
|
-
}
|
|
509
|
-
/**
|
|
510
|
-
* Search-mode dynamic resolver: prompts the user for free-form text, passes
|
|
511
|
-
* it to fetch via `search`, and either short-circuits on a primitive return
|
|
512
|
-
* (exact match) or renders the results as a search-filterable dropdown.
|
|
513
|
-
* Empty results still render the dropdown so the user can fall through to
|
|
514
|
-
* "(Use 'foo' as-is)" or "(Try a different search)" rather than being
|
|
515
|
-
* stuck.
|
|
516
|
-
*
|
|
517
|
-
* Known limitation: pagination beyond the first page is dropped. Each
|
|
518
|
-
* search() invocation re-prompts from scratch and the user is expected
|
|
519
|
-
* to refine their query if too many results came back. If a future
|
|
520
|
-
* high-cardinality search resolver needs Load-more here, the
|
|
521
|
-
* `pageIterator` / `hasMore` from `unpackFetchResult` is what to wire in.
|
|
522
|
-
*/
|
|
523
|
-
async resolveDynamicWithSearchInput({
|
|
524
|
-
resolver,
|
|
525
|
-
context,
|
|
526
|
-
promptLabel,
|
|
527
|
-
isOptional
|
|
528
|
-
}) {
|
|
529
|
-
const parenParts = [];
|
|
530
|
-
if (isOptional) parenParts.push("optional");
|
|
531
|
-
if (resolver.placeholder) parenParts.push(resolver.placeholder);
|
|
532
|
-
const parens = parenParts.length > 0 ? ` (${parenParts.join(", ")})` : "";
|
|
533
|
-
const message = `Enter or search ${promptLabel}${parens}:`;
|
|
534
|
-
const SKIP_SENTINEL = Symbol("SKIP");
|
|
535
|
-
const USE_AS_IS_SENTINEL = Symbol("USE_AS_IS");
|
|
536
|
-
const TRY_AGAIN_SENTINEL = Symbol("TRY_AGAIN");
|
|
537
|
-
let lastNote;
|
|
538
|
-
while (true) {
|
|
539
|
-
this.stopSpinner();
|
|
540
|
-
if (lastNote) {
|
|
541
|
-
console.log(chalk.yellow(lastNote));
|
|
542
|
-
lastNote = void 0;
|
|
543
|
-
}
|
|
544
|
-
const answers = await inquirer.prompt([
|
|
545
|
-
{ type: "input", name: "search", message }
|
|
546
|
-
]);
|
|
547
|
-
const rawInput = answers.search;
|
|
548
|
-
const searchInput = typeof rawInput === "string" ? rawInput.trim() : "";
|
|
549
|
-
if (!searchInput) {
|
|
550
|
-
if (isOptional) return void 0;
|
|
551
|
-
lastNote = `${promptLabel} is required.`;
|
|
552
|
-
continue;
|
|
553
|
-
}
|
|
554
|
-
const searchParams = {
|
|
555
|
-
...context.resolvedParams,
|
|
556
|
-
search: searchInput
|
|
557
|
-
};
|
|
558
|
-
this.startSpinner();
|
|
559
|
-
this.debugLog(`Searching ${promptLabel} for "${searchInput}"`);
|
|
560
|
-
let fetchResult;
|
|
561
|
-
try {
|
|
562
|
-
fetchResult = await resolver.fetch(context.sdk, searchParams);
|
|
563
|
-
} finally {
|
|
564
|
-
this.stopSpinner();
|
|
565
|
-
}
|
|
566
|
-
if (typeof fetchResult === "string" || typeof fetchResult === "number") {
|
|
567
|
-
return fetchResult;
|
|
568
|
-
}
|
|
569
|
-
const { items } = await this.unpackFetchResult(fetchResult, promptLabel);
|
|
570
|
-
const choicesConfig = resolver.prompt(items, searchParams);
|
|
571
|
-
const dataChoices = (choicesConfig.choices ?? []).map(renderChoiceLabel);
|
|
572
|
-
const capabilityHintMessages = await this.computeCapabilityHints(
|
|
573
|
-
resolver,
|
|
574
|
-
context
|
|
575
|
-
);
|
|
576
|
-
const selected = await search({
|
|
577
|
-
message: choicesConfig.message,
|
|
578
|
-
validate: this.wrapPromptValidate(choicesConfig.validate),
|
|
579
|
-
// @inquirer/search passes an AbortSignal as the second arg for
|
|
580
|
-
// cancelling async sources. All three of our source callbacks are
|
|
581
|
-
// pure-local (filter an already-fetched array), so we intentionally
|
|
582
|
-
// ignore the signal. A future server-side filter implementation
|
|
583
|
-
// would need to honor it.
|
|
584
|
-
source: (term) => {
|
|
585
|
-
const trimmed = (term ?? "").trim();
|
|
586
|
-
const lower = trimmed.toLowerCase();
|
|
587
|
-
const matches = trimmed ? dataChoices.filter((c) => c.name.toLowerCase().includes(lower)) : dataChoices;
|
|
588
|
-
const orderedMatches = trimmed ? matches : this.reorderForDefault(matches, choicesConfig.default);
|
|
589
|
-
const skipChoice = isOptional ? [{ name: chalk.dim("(Skip)"), value: SKIP_SENTINEL }] : [];
|
|
590
|
-
const useAsIsChoice = {
|
|
591
|
-
name: chalk.dim(`(Use ${JSON.stringify(searchInput)} as-is)`),
|
|
592
|
-
value: USE_AS_IS_SENTINEL
|
|
593
|
-
};
|
|
594
|
-
const tryAgainChoice = {
|
|
595
|
-
name: chalk.dim("(Try a different search)"),
|
|
596
|
-
value: TRY_AGAIN_SENTINEL
|
|
597
|
-
};
|
|
598
|
-
const out2 = [];
|
|
599
|
-
if (orderedMatches.length === 0) {
|
|
600
|
-
out2.push(useAsIsChoice);
|
|
601
|
-
out2.push(tryAgainChoice);
|
|
602
|
-
out2.push(...skipChoice);
|
|
603
|
-
} else {
|
|
604
|
-
out2.push(...orderedMatches);
|
|
605
|
-
out2.push(...skipChoice);
|
|
606
|
-
out2.push(useAsIsChoice);
|
|
607
|
-
out2.push(tryAgainChoice);
|
|
608
|
-
}
|
|
609
|
-
for (const message2 of capabilityHintMessages) {
|
|
610
|
-
out2.push({
|
|
611
|
-
name: chalk.dim(message2),
|
|
612
|
-
value: SKIP_SENTINEL,
|
|
613
|
-
disabled: true
|
|
614
|
-
});
|
|
615
|
-
}
|
|
616
|
-
return out2;
|
|
617
|
-
}
|
|
618
|
-
});
|
|
619
|
-
if (selected === SKIP_SENTINEL) return void 0;
|
|
620
|
-
if (selected === USE_AS_IS_SENTINEL) {
|
|
621
|
-
const validationResult = choicesConfig.validate?.(searchInput);
|
|
622
|
-
if (validationResult === false) {
|
|
623
|
-
lastNote = `${promptLabel}: invalid value.`;
|
|
624
|
-
continue;
|
|
625
|
-
}
|
|
626
|
-
if (typeof validationResult === "string") {
|
|
627
|
-
lastNote = validationResult;
|
|
628
|
-
continue;
|
|
629
|
-
}
|
|
630
|
-
return this.applyPromptFilter(choicesConfig.filter, searchInput);
|
|
631
|
-
}
|
|
632
|
-
if (selected === TRY_AGAIN_SENTINEL) continue;
|
|
633
|
-
return this.applyPromptFilter(choicesConfig.filter, selected);
|
|
634
|
-
}
|
|
635
|
-
}
|
|
636
|
-
async resolveParameter(param, context, functionName, options) {
|
|
637
|
-
const resolver = this.getResolver(
|
|
638
|
-
param.name,
|
|
639
|
-
context.sdk,
|
|
640
|
-
functionName
|
|
641
|
-
);
|
|
642
|
-
if (!resolver) {
|
|
643
|
-
throw new Error(`No resolver found for parameter: ${param.name}`);
|
|
644
|
-
}
|
|
645
|
-
return this.resolveWithResolver(resolver, param, context, {
|
|
646
|
-
isOptional: options?.isOptional
|
|
647
|
-
});
|
|
648
|
-
}
|
|
649
|
-
/**
|
|
650
|
-
* Run a resolver to obtain a value for one parameter, prompting the
|
|
651
|
-
* user when necessary. Routes to one of several prompt backends and
|
|
652
|
-
* has to keep the `PromptConfig` contract honest across each one.
|
|
653
|
-
*
|
|
654
|
-
* `PromptConfig` field × prompt-backend handling:
|
|
655
|
-
*
|
|
656
|
-
* | field | list (search()) | checkbox/confirm (inquirer.prompt) | search-mode dropdown (search()) |
|
|
657
|
-
* | -------- | --------------- | ---------------------------------- | ------------------------------- |
|
|
658
|
-
* | type | required | required | required |
|
|
659
|
-
* | name | (set internally)| forwarded | (set internally) |
|
|
660
|
-
* | message | forwarded | forwarded | forwarded |
|
|
661
|
-
* | choices | filtered in src | passed to inquirer | filtered in src |
|
|
662
|
-
* | default | reorder matches | passed (also internal cursor jump) | reorder matches |
|
|
663
|
-
* | validate | wrapped | passed (inquirer native) | wrapped + manual for (Use as-is)|
|
|
664
|
-
* | filter | manual once | inquirer native (do NOT double) | manual once |
|
|
665
|
-
*
|
|
666
|
-
* Escape-hatch sentinels (Skip / Custom value / Use as-is / Load more
|
|
667
|
-
* / Try again) bypass the resolver's validate/filter because they
|
|
668
|
-
* aren't real user values — they're CLI control-flow.
|
|
669
|
-
*/
|
|
670
|
-
async resolveWithResolver(resolver, param, context, options = {}) {
|
|
671
|
-
const { arrayIndex, isOptional } = options;
|
|
672
|
-
const inArrayContext = arrayIndex != null;
|
|
673
|
-
const promptLabel = inArrayContext ? `${param.name}[${arrayIndex}]` : param.name;
|
|
674
|
-
const promptName = inArrayContext ? "value" : param.name;
|
|
675
|
-
this.debugLog(`Resolving ${promptLabel}${isOptional ? " (optional)" : ""}`);
|
|
676
|
-
if (resolver.type === "constant") {
|
|
677
|
-
const constantResolver = resolver;
|
|
678
|
-
this.stopSpinner();
|
|
679
|
-
return constantResolver.value;
|
|
680
|
-
} else if (resolver.type === "static") {
|
|
681
|
-
const staticResolver = resolver;
|
|
682
|
-
const promptConfig = {
|
|
683
|
-
type: staticResolver.inputType === "password" ? "password" : "input",
|
|
684
|
-
name: promptName,
|
|
685
|
-
message: `Enter ${promptLabel}${isOptional ? " (optional)" : ""}:`,
|
|
686
|
-
...staticResolver.placeholder && {
|
|
687
|
-
default: staticResolver.placeholder
|
|
688
|
-
}
|
|
689
|
-
};
|
|
690
|
-
this.stopSpinner();
|
|
691
|
-
const answers = await inquirer.prompt([promptConfig]);
|
|
692
|
-
const value = answers[promptName];
|
|
693
|
-
if (isOptional && (value === void 0 || value === "" || value === staticResolver.placeholder)) {
|
|
694
|
-
return void 0;
|
|
695
|
-
}
|
|
696
|
-
return coerceToSchemaType(value, param.schema);
|
|
697
|
-
} else if (resolver.type === "dynamic") {
|
|
698
|
-
const dynamicResolver = resolver;
|
|
699
|
-
this.startSpinner();
|
|
700
|
-
const autoResolution = await this.tryAutoResolve(
|
|
701
|
-
dynamicResolver,
|
|
702
|
-
context
|
|
703
|
-
);
|
|
704
|
-
if (autoResolution != null) {
|
|
705
|
-
this.stopSpinner();
|
|
706
|
-
return autoResolution.resolvedValue;
|
|
707
|
-
}
|
|
708
|
-
if (dynamicResolver.inputType === "search") {
|
|
709
|
-
this.stopSpinner();
|
|
710
|
-
return await this.resolveDynamicWithSearchInput({
|
|
711
|
-
resolver: dynamicResolver,
|
|
712
|
-
context,
|
|
713
|
-
promptLabel,
|
|
714
|
-
isOptional: isOptional ?? false
|
|
715
|
-
});
|
|
716
|
-
}
|
|
717
|
-
this.debugLog(`Fetching options for ${promptLabel}`);
|
|
718
|
-
let fetchResult;
|
|
719
|
-
try {
|
|
720
|
-
fetchResult = await dynamicResolver.fetch(
|
|
721
|
-
context.sdk,
|
|
722
|
-
context.resolvedParams
|
|
723
|
-
);
|
|
724
|
-
} finally {
|
|
725
|
-
this.stopSpinner();
|
|
726
|
-
}
|
|
727
|
-
if (typeof fetchResult === "string" || typeof fetchResult === "number") {
|
|
728
|
-
console.error(
|
|
729
|
-
chalk.yellow(
|
|
730
|
-
`Resolver for ${promptLabel} returned a primitive value but is not in search mode. Set inputType: "search" on the resolver if you want exact-match short-circuit. Falling back to manual entry.`
|
|
731
|
-
)
|
|
732
|
-
);
|
|
733
|
-
const fallbackAnswers = await inquirer.prompt([
|
|
734
|
-
{
|
|
735
|
-
type: "input",
|
|
736
|
-
name: promptName,
|
|
737
|
-
message: `Enter ${promptLabel}${isOptional ? " (optional)" : ""}:`
|
|
738
|
-
}
|
|
739
|
-
]);
|
|
740
|
-
const fallbackValue = fallbackAnswers[promptName];
|
|
741
|
-
if (isOptional && (fallbackValue === void 0 || fallbackValue === "")) {
|
|
742
|
-
return void 0;
|
|
743
|
-
}
|
|
744
|
-
return fallbackValue;
|
|
745
|
-
}
|
|
746
|
-
const unpacked = await this.unpackFetchResult(fetchResult, promptLabel);
|
|
747
|
-
let pageIterator = unpacked.pageIterator;
|
|
748
|
-
let items = unpacked.items;
|
|
749
|
-
let hasMore = unpacked.hasMore;
|
|
750
|
-
const LOAD_MORE_SENTINEL = Symbol("LOAD_MORE");
|
|
751
|
-
const SKIP_SENTINEL = Symbol("SKIP");
|
|
752
|
-
const CUSTOM_VALUE_SENTINEL = Symbol("CUSTOM_VALUE");
|
|
753
|
-
let newItemsStartIndex = -1;
|
|
754
|
-
while (true) {
|
|
755
|
-
const promptConfig = dynamicResolver.prompt(
|
|
756
|
-
items,
|
|
757
|
-
context.resolvedParams
|
|
758
|
-
);
|
|
759
|
-
promptConfig.name = promptName;
|
|
760
|
-
const renderedChoices = promptConfig.choices ? promptConfig.choices.map(renderChoiceLabel) : [];
|
|
761
|
-
if (promptConfig.choices) {
|
|
762
|
-
promptConfig.choices = renderedChoices;
|
|
763
|
-
}
|
|
764
|
-
const hasSelectableChoice = promptConfig.choices?.some(
|
|
765
|
-
(c) => !c.disabled
|
|
766
|
-
);
|
|
767
|
-
if (!hasSelectableChoice && !hasMore) {
|
|
768
|
-
throw new ZapierCliValidationError(
|
|
769
|
-
`No ${promptLabel} available to select.`
|
|
770
|
-
);
|
|
771
|
-
}
|
|
772
|
-
const capabilityHints = [];
|
|
773
|
-
if (!hasMore) {
|
|
774
|
-
const hintMessages = await this.computeCapabilityHints(
|
|
775
|
-
dynamicResolver,
|
|
776
|
-
context
|
|
777
|
-
);
|
|
778
|
-
for (const message of hintMessages) {
|
|
779
|
-
capabilityHints.push({
|
|
780
|
-
name: chalk.dim(message),
|
|
781
|
-
value: SKIP_SENTINEL,
|
|
782
|
-
disabled: true
|
|
783
|
-
});
|
|
784
|
-
}
|
|
785
|
-
}
|
|
786
|
-
let selected;
|
|
787
|
-
if (promptConfig.type === "list") {
|
|
788
|
-
const dataChoices = renderedChoices;
|
|
789
|
-
selected = await search({
|
|
790
|
-
message: promptConfig.message,
|
|
791
|
-
validate: this.wrapPromptValidate(promptConfig.validate),
|
|
792
|
-
source: (term) => {
|
|
793
|
-
const trimmed = (term ?? "").trim();
|
|
794
|
-
const lower = trimmed.toLowerCase();
|
|
795
|
-
const matches = trimmed ? dataChoices.filter(
|
|
796
|
-
(c) => c.name.toLowerCase().includes(lower)
|
|
797
|
-
) : dataChoices;
|
|
798
|
-
const out2 = [];
|
|
799
|
-
const skipChoice = isOptional ? [
|
|
800
|
-
{
|
|
801
|
-
name: chalk.dim("(Skip)"),
|
|
802
|
-
value: SKIP_SENTINEL
|
|
803
|
-
}
|
|
804
|
-
] : [];
|
|
805
|
-
const customValueChoice = {
|
|
806
|
-
name: chalk.dim("(Enter custom value)"),
|
|
807
|
-
value: CUSTOM_VALUE_SENTINEL
|
|
808
|
-
};
|
|
809
|
-
const orderedMatches = trimmed ? matches : this.reorderForDefault(matches, promptConfig.default);
|
|
810
|
-
const matchesFirst = trimmed || promptConfig.default !== void 0;
|
|
811
|
-
const loadMoreChoice = hasMore && pageIterator ? {
|
|
812
|
-
name: chalk.dim("(Load more...)"),
|
|
813
|
-
value: LOAD_MORE_SENTINEL
|
|
814
|
-
} : null;
|
|
815
|
-
if (matchesFirst && orderedMatches.length > 0) {
|
|
816
|
-
out2.push(...orderedMatches);
|
|
817
|
-
out2.push(...skipChoice);
|
|
818
|
-
out2.push(customValueChoice);
|
|
819
|
-
if (loadMoreChoice) out2.push(loadMoreChoice);
|
|
820
|
-
} else if (matchesFirst) {
|
|
821
|
-
out2.push(customValueChoice);
|
|
822
|
-
if (loadMoreChoice) out2.push(loadMoreChoice);
|
|
823
|
-
out2.push(...skipChoice);
|
|
824
|
-
} else {
|
|
825
|
-
out2.push(...skipChoice);
|
|
826
|
-
out2.push(customValueChoice);
|
|
827
|
-
out2.push(...orderedMatches);
|
|
828
|
-
if (loadMoreChoice) out2.push(loadMoreChoice);
|
|
829
|
-
}
|
|
830
|
-
if (capabilityHints.length > 0 && (!trimmed || matches.length > 0)) {
|
|
831
|
-
out2.push(...capabilityHints);
|
|
832
|
-
}
|
|
833
|
-
return out2;
|
|
834
|
-
}
|
|
835
|
-
});
|
|
836
|
-
} else {
|
|
837
|
-
if (isOptional && promptConfig.choices) {
|
|
838
|
-
promptConfig.choices.unshift({
|
|
839
|
-
name: chalk.dim("(Skip)"),
|
|
840
|
-
value: SKIP_SENTINEL
|
|
841
|
-
});
|
|
842
|
-
}
|
|
843
|
-
if (hasMore && pageIterator && promptConfig.choices) {
|
|
844
|
-
promptConfig.choices.push({
|
|
845
|
-
name: chalk.dim("(Load more...)"),
|
|
846
|
-
value: LOAD_MORE_SENTINEL
|
|
847
|
-
});
|
|
848
|
-
}
|
|
849
|
-
if (capabilityHints.length > 0 && promptConfig.choices) {
|
|
850
|
-
promptConfig.choices.push(...capabilityHints);
|
|
851
|
-
}
|
|
852
|
-
if (newItemsStartIndex >= 0 && promptConfig.choices) {
|
|
853
|
-
const injectedBefore = isOptional ? 1 : 0;
|
|
854
|
-
const adjustedIndex = newItemsStartIndex + injectedBefore;
|
|
855
|
-
if (promptConfig.choices[adjustedIndex]) {
|
|
856
|
-
promptConfig.default = promptConfig.choices[adjustedIndex].value;
|
|
857
|
-
}
|
|
858
|
-
newItemsStartIndex = -1;
|
|
859
|
-
}
|
|
860
|
-
const answers = await inquirer.prompt([promptConfig]);
|
|
861
|
-
selected = answers[promptName];
|
|
862
|
-
}
|
|
863
|
-
if (selected === SKIP_SENTINEL) {
|
|
864
|
-
return void 0;
|
|
865
|
-
}
|
|
866
|
-
if (selected === CUSTOM_VALUE_SENTINEL) {
|
|
867
|
-
const customAnswer = await inquirer.prompt([
|
|
868
|
-
{
|
|
869
|
-
type: "input",
|
|
870
|
-
name: promptName,
|
|
871
|
-
message: `Enter ${promptLabel}${isOptional ? " (optional)" : ""}:`
|
|
872
|
-
}
|
|
873
|
-
]);
|
|
874
|
-
const value = customAnswer[promptName];
|
|
875
|
-
if (isOptional && (value === void 0 || value === "")) {
|
|
876
|
-
return void 0;
|
|
877
|
-
}
|
|
878
|
-
return value;
|
|
879
|
-
}
|
|
880
|
-
const wantsMore = Array.isArray(selected) ? selected.includes(LOAD_MORE_SENTINEL) : selected === LOAD_MORE_SENTINEL;
|
|
881
|
-
if (wantsMore && pageIterator) {
|
|
882
|
-
if (Array.isArray(selected)) {
|
|
883
|
-
selected = selected.filter(
|
|
884
|
-
(v) => v !== LOAD_MORE_SENTINEL
|
|
885
|
-
);
|
|
886
|
-
}
|
|
887
|
-
const prevLength = items.length;
|
|
888
|
-
this.startSpinner();
|
|
889
|
-
this.debugLog("Fetching more options...");
|
|
890
|
-
const next = await pageIterator.next();
|
|
891
|
-
this.stopSpinner();
|
|
892
|
-
if (!next.done && next.value) {
|
|
893
|
-
items = [...items, ...next.value.data];
|
|
894
|
-
hasMore = next.value.nextCursor != null;
|
|
895
|
-
newItemsStartIndex = prevLength;
|
|
896
|
-
} else {
|
|
897
|
-
hasMore = false;
|
|
898
|
-
}
|
|
899
|
-
continue;
|
|
900
|
-
}
|
|
901
|
-
return promptConfig.type === "list" ? this.applyPromptFilter(promptConfig.filter, selected) : selected;
|
|
902
|
-
}
|
|
903
|
-
} else if (resolver.type === "fields") {
|
|
904
|
-
if (isOptional && !inArrayContext) {
|
|
905
|
-
this.stopSpinner();
|
|
906
|
-
const { confirm } = await inquirer.prompt([
|
|
907
|
-
{
|
|
908
|
-
type: "confirm",
|
|
909
|
-
name: "confirm",
|
|
910
|
-
message: `Add ${promptLabel}?`,
|
|
911
|
-
default: false
|
|
912
|
-
}
|
|
913
|
-
]);
|
|
914
|
-
if (!confirm) {
|
|
915
|
-
return void 0;
|
|
916
|
-
}
|
|
917
|
-
}
|
|
918
|
-
return await this.resolveFieldsRecursively(
|
|
919
|
-
resolver,
|
|
920
|
-
context,
|
|
921
|
-
param,
|
|
922
|
-
{ inArrayContext }
|
|
923
|
-
);
|
|
924
|
-
} else if (resolver.type === "array") {
|
|
925
|
-
return await this.resolveArrayRecursively(
|
|
926
|
-
resolver,
|
|
927
|
-
context,
|
|
928
|
-
param
|
|
929
|
-
);
|
|
930
|
-
}
|
|
931
|
-
throw new Error(`Unknown resolver type for ${promptLabel}`);
|
|
932
|
-
}
|
|
933
|
-
async resolveFieldsRecursively(resolver, context, param, options = {}) {
|
|
934
|
-
const inputs = {};
|
|
935
|
-
let processedFieldKeys = /* @__PURE__ */ new Set();
|
|
936
|
-
let iteration = 0;
|
|
937
|
-
const maxIterations = 10;
|
|
938
|
-
while (iteration < maxIterations) {
|
|
939
|
-
iteration++;
|
|
940
|
-
const updatedContext = {
|
|
941
|
-
...context,
|
|
942
|
-
resolvedParams: {
|
|
943
|
-
...context.resolvedParams,
|
|
944
|
-
inputs
|
|
945
|
-
}
|
|
946
|
-
};
|
|
947
|
-
this.debugLog(
|
|
948
|
-
`Fetching input fields for ${param.name}${iteration > 1 ? ` (iteration ${iteration})` : ""}`
|
|
949
|
-
);
|
|
950
|
-
this.startSpinner();
|
|
951
|
-
const rootFieldItems = await resolver.fetch(
|
|
952
|
-
updatedContext.sdk,
|
|
953
|
-
updatedContext.resolvedParams
|
|
954
|
-
);
|
|
955
|
-
this.stopSpinner();
|
|
956
|
-
if (!rootFieldItems || rootFieldItems.length === 0) {
|
|
957
|
-
if (iteration === 1) {
|
|
958
|
-
console.log(
|
|
959
|
-
chalk.yellow(`No input fields required for this action.`)
|
|
960
|
-
);
|
|
961
|
-
}
|
|
962
|
-
break;
|
|
963
|
-
}
|
|
964
|
-
const fieldStats = await this.processFieldItems(
|
|
965
|
-
rootFieldItems,
|
|
966
|
-
inputs,
|
|
967
|
-
processedFieldKeys,
|
|
968
|
-
[],
|
|
969
|
-
iteration,
|
|
970
|
-
updatedContext,
|
|
971
|
-
{ inArrayContext: options.inArrayContext }
|
|
972
|
-
);
|
|
973
|
-
if (fieldStats.newRequired === 0 && fieldStats.newOptional === 0) {
|
|
974
|
-
break;
|
|
975
|
-
}
|
|
976
|
-
if (fieldStats.newRequired === 0 && fieldStats.optionalSkipped) {
|
|
977
|
-
break;
|
|
978
|
-
}
|
|
979
|
-
}
|
|
980
|
-
if (iteration >= maxIterations) {
|
|
981
|
-
console.log(
|
|
982
|
-
chalk.yellow(
|
|
983
|
-
`
|
|
984
|
-
\u26A0\uFE0F Maximum field resolution iterations reached. Some dynamic fields may not have been discovered.`
|
|
985
|
-
)
|
|
986
|
-
);
|
|
987
|
-
}
|
|
988
|
-
if (resolver.transform) {
|
|
989
|
-
return resolver.transform(inputs);
|
|
990
|
-
}
|
|
991
|
-
return inputs;
|
|
992
|
-
}
|
|
993
|
-
/**
|
|
994
|
-
* Resolves an array parameter by repeatedly prompting for items until user says no
|
|
995
|
-
*/
|
|
996
|
-
async resolveArrayRecursively(resolver, context, param) {
|
|
997
|
-
const items = [];
|
|
998
|
-
const minItems = resolver.minItems ?? 0;
|
|
999
|
-
const maxItems = resolver.maxItems ?? Infinity;
|
|
1000
|
-
while (items.length < maxItems) {
|
|
1001
|
-
const currentIndex = items.length;
|
|
1002
|
-
if (currentIndex >= minItems) {
|
|
1003
|
-
this.stopSpinner();
|
|
1004
|
-
const confirmAnswer = await inquirer.prompt([
|
|
1005
|
-
{
|
|
1006
|
-
type: "confirm",
|
|
1007
|
-
name: "addItem",
|
|
1008
|
-
message: `Add ${param.name}[${currentIndex}]?`,
|
|
1009
|
-
default: false
|
|
1010
|
-
}
|
|
1011
|
-
]);
|
|
1012
|
-
if (!confirmAnswer.addItem) {
|
|
1013
|
-
break;
|
|
1014
|
-
}
|
|
1015
|
-
}
|
|
1016
|
-
const innerResolver = await resolver.fetch(
|
|
1017
|
-
context.sdk,
|
|
1018
|
-
context.resolvedParams
|
|
1019
|
-
);
|
|
1020
|
-
const itemValue = await this.resolveWithResolver(
|
|
1021
|
-
innerResolver,
|
|
1022
|
-
param,
|
|
1023
|
-
context,
|
|
1024
|
-
{ arrayIndex: currentIndex }
|
|
1025
|
-
);
|
|
1026
|
-
items.push(itemValue);
|
|
1027
|
-
context.resolvedParams = {
|
|
1028
|
-
...context.resolvedParams,
|
|
1029
|
-
[param.name]: items
|
|
1030
|
-
};
|
|
1031
|
-
}
|
|
1032
|
-
if (items.length >= maxItems) {
|
|
1033
|
-
console.log(chalk.gray(`Maximum of ${maxItems} items reached.`));
|
|
1034
|
-
}
|
|
1035
|
-
return items;
|
|
1036
|
-
}
|
|
1037
|
-
/**
|
|
1038
|
-
* Recursively processes fieldsets and their fields, maintaining natural structure
|
|
1039
|
-
* and creating nested inputs as needed (e.g., fieldset "foo" becomes inputs.foo = [{}])
|
|
1040
|
-
*/
|
|
1041
|
-
async processFieldItems(items, targetInputs, processedFieldKeys, fieldsetPath = [], iteration = 1, context, options = {}) {
|
|
1042
|
-
let newRequiredCount = 0;
|
|
1043
|
-
let newOptionalCount = 0;
|
|
1044
|
-
let optionalSkipped = false;
|
|
1045
|
-
for (const item of items) {
|
|
1046
|
-
const typedItem = item;
|
|
1047
|
-
if (typedItem.type === "fieldset" && typedItem.fields && typedItem.key) {
|
|
1048
|
-
const fieldsetTitle = typedItem.title || typedItem.key;
|
|
1049
|
-
const pathDisplay = fieldsetPath.length > 0 ? ` (in ${fieldsetPath.join(" > ")})` : "";
|
|
1050
|
-
console.log(
|
|
1051
|
-
chalk.cyan(
|
|
1052
|
-
`
|
|
1053
|
-
\u{1F4C1} Processing fieldset: ${fieldsetTitle}${pathDisplay}`
|
|
1054
|
-
)
|
|
1055
|
-
);
|
|
1056
|
-
if (!targetInputs[typedItem.key]) {
|
|
1057
|
-
targetInputs[typedItem.key] = [{}];
|
|
1058
|
-
}
|
|
1059
|
-
const fieldsetTarget = targetInputs[typedItem.key][0];
|
|
1060
|
-
const nestedPath = [...fieldsetPath, fieldsetTitle];
|
|
1061
|
-
const nestedStats = await this.processFieldItems(
|
|
1062
|
-
typedItem.fields,
|
|
1063
|
-
fieldsetTarget,
|
|
1064
|
-
processedFieldKeys,
|
|
1065
|
-
nestedPath,
|
|
1066
|
-
iteration,
|
|
1067
|
-
context,
|
|
1068
|
-
options
|
|
1069
|
-
);
|
|
1070
|
-
newRequiredCount += nestedStats.newRequired;
|
|
1071
|
-
newOptionalCount += nestedStats.newOptional;
|
|
1072
|
-
if (nestedStats.optionalSkipped) {
|
|
1073
|
-
optionalSkipped = true;
|
|
1074
|
-
}
|
|
1075
|
-
} else if (typedItem.type === "input_field" && typedItem.key) {
|
|
1076
|
-
if (processedFieldKeys.has(typedItem.key)) {
|
|
1077
|
-
continue;
|
|
1078
|
-
}
|
|
1079
|
-
const isRequired = typedItem.is_required || false;
|
|
1080
|
-
if (isRequired) {
|
|
1081
|
-
newRequiredCount++;
|
|
1082
|
-
if (typedItem.resolver && context) {
|
|
1083
|
-
const param = {
|
|
1084
|
-
name: typedItem.key,
|
|
1085
|
-
path: [typedItem.key],
|
|
1086
|
-
schema: z.unknown(),
|
|
1087
|
-
isRequired: true
|
|
1088
|
-
};
|
|
1089
|
-
targetInputs[typedItem.key] = await this.resolveWithResolver(
|
|
1090
|
-
typedItem.resolver,
|
|
1091
|
-
param,
|
|
1092
|
-
context,
|
|
1093
|
-
{ isOptional: false }
|
|
1094
|
-
);
|
|
1095
|
-
} else {
|
|
1096
|
-
await this.promptForField(typedItem, targetInputs, context);
|
|
1097
|
-
}
|
|
1098
|
-
processedFieldKeys.add(typedItem.key);
|
|
1099
|
-
} else {
|
|
1100
|
-
newOptionalCount++;
|
|
1101
|
-
}
|
|
1102
|
-
}
|
|
1103
|
-
}
|
|
1104
|
-
if (newOptionalCount > 0) {
|
|
1105
|
-
const optionalFields = items.filter((item) => {
|
|
1106
|
-
const typedItem = item;
|
|
1107
|
-
return typedItem.type === "input_field" && typedItem.key && !typedItem.is_required && !processedFieldKeys.has(typedItem.key);
|
|
1108
|
-
});
|
|
1109
|
-
if (optionalFields.length > 0) {
|
|
1110
|
-
const pathContext = fieldsetPath.length > 0 ? ` in ${fieldsetPath.join(" > ")}` : "";
|
|
1111
|
-
if (options.inArrayContext) {
|
|
1112
|
-
for (const field of optionalFields) {
|
|
1113
|
-
await this.promptForField(field, targetInputs, context);
|
|
1114
|
-
const typedField = field;
|
|
1115
|
-
processedFieldKeys.add(typedField.key);
|
|
1116
|
-
}
|
|
1117
|
-
} else {
|
|
1118
|
-
console.log(
|
|
1119
|
-
chalk.gray(
|
|
1120
|
-
`
|
|
1121
|
-
There are ${optionalFields.length} ${iteration === 1 ? "" : "additional "}optional field(s) available${pathContext}.`
|
|
1122
|
-
)
|
|
1123
|
-
);
|
|
1124
|
-
try {
|
|
1125
|
-
const shouldConfigureOptional = await inquirer.prompt([
|
|
1126
|
-
{
|
|
1127
|
-
type: "confirm",
|
|
1128
|
-
name: "configure",
|
|
1129
|
-
message: `Would you like to configure ${iteration === 1 ? "" : "these additional "}optional fields${pathContext}?`,
|
|
1130
|
-
default: false
|
|
1131
|
-
}
|
|
1132
|
-
]);
|
|
1133
|
-
if (shouldConfigureOptional.configure) {
|
|
1134
|
-
console.log(chalk.cyan(`
|
|
1135
|
-
Optional fields${pathContext}:`));
|
|
1136
|
-
for (const field of optionalFields) {
|
|
1137
|
-
await this.promptForField(field, targetInputs, context);
|
|
1138
|
-
const typedField = field;
|
|
1139
|
-
processedFieldKeys.add(typedField.key);
|
|
1140
|
-
}
|
|
1141
|
-
} else {
|
|
1142
|
-
optionalSkipped = true;
|
|
1143
|
-
optionalFields.forEach((field) => {
|
|
1144
|
-
const typedField = field;
|
|
1145
|
-
processedFieldKeys.add(typedField.key);
|
|
1146
|
-
});
|
|
1147
|
-
}
|
|
1148
|
-
} catch (error) {
|
|
1149
|
-
if (this.isUserCancellation(error)) {
|
|
1150
|
-
console.log(chalk.yellow("\n\nOperation cancelled by user"));
|
|
1151
|
-
throw new ZapierCliUserCancellationError();
|
|
1152
|
-
}
|
|
1153
|
-
throw error;
|
|
1154
|
-
}
|
|
1155
|
-
}
|
|
1156
|
-
}
|
|
1157
|
-
}
|
|
1158
|
-
return {
|
|
1159
|
-
newRequired: newRequiredCount,
|
|
1160
|
-
newOptional: newOptionalCount,
|
|
1161
|
-
optionalSkipped
|
|
1162
|
-
};
|
|
1163
|
-
}
|
|
1164
|
-
getNestedValue(obj, path2) {
|
|
1165
|
-
return path2.reduce(
|
|
1166
|
-
(current, key) => current?.[key],
|
|
1167
|
-
obj
|
|
1168
|
-
);
|
|
1169
|
-
}
|
|
1170
|
-
setNestedValue(obj, path2, value) {
|
|
1171
|
-
const lastKey = path2[path2.length - 1];
|
|
1172
|
-
const parent = path2.slice(0, -1).reduce((current, key) => {
|
|
1173
|
-
const currentObj = current;
|
|
1174
|
-
if (!(key in currentObj)) {
|
|
1175
|
-
currentObj[key] = {};
|
|
1176
|
-
}
|
|
1177
|
-
return currentObj[key];
|
|
1178
|
-
}, obj);
|
|
1179
|
-
parent[lastKey] = value;
|
|
1180
|
-
}
|
|
1181
|
-
/**
|
|
1182
|
-
* Extract and normalize field metadata from raw field object
|
|
1183
|
-
*/
|
|
1184
|
-
extractFieldMetadata(field) {
|
|
1185
|
-
const fieldObj = field;
|
|
1186
|
-
const valueType = fieldObj.value_type || "string";
|
|
1187
|
-
return {
|
|
1188
|
-
key: fieldObj.key,
|
|
1189
|
-
title: fieldObj.title || fieldObj.label || fieldObj.key,
|
|
1190
|
-
description: fieldObj.description || fieldObj.helpText,
|
|
1191
|
-
isRequired: fieldObj.is_required || false,
|
|
1192
|
-
defaultValue: fieldObj.default_value ?? fieldObj.default,
|
|
1193
|
-
valueType,
|
|
1194
|
-
hasDropdown: fieldObj.format === "SELECT" || Boolean(fieldObj.choices),
|
|
1195
|
-
isMultiSelect: Boolean(
|
|
1196
|
-
valueType === "array" || fieldObj.items && fieldObj.items.type !== void 0
|
|
1197
|
-
),
|
|
1198
|
-
inlineChoices: fieldObj.choices
|
|
1199
|
-
};
|
|
1200
|
-
}
|
|
1201
|
-
/**
|
|
1202
|
-
* Fetch a page of choices for a dropdown field
|
|
1203
|
-
*/
|
|
1204
|
-
async fetchChoices(fieldMeta, inputs, context, cursor) {
|
|
1205
|
-
try {
|
|
1206
|
-
this.debugLog(
|
|
1207
|
-
cursor ? `Fetching more choices for ${fieldMeta.title}` : `Fetching choices for ${fieldMeta.title}`
|
|
1208
|
-
);
|
|
1209
|
-
this.startSpinner();
|
|
1210
|
-
const page = await context.sdk.listActionInputFieldChoices({
|
|
1211
|
-
app: context.resolvedParams.app,
|
|
1212
|
-
action: context.resolvedParams.action,
|
|
1213
|
-
actionType: context.resolvedParams.actionType,
|
|
1214
|
-
connection: context.resolvedParams.connection,
|
|
1215
|
-
inputField: fieldMeta.key,
|
|
1216
|
-
inputs,
|
|
1217
|
-
...cursor && { cursor }
|
|
1218
|
-
});
|
|
1219
|
-
this.stopSpinner();
|
|
1220
|
-
const choices = page.data.map((choice) => ({
|
|
1221
|
-
label: choice.label || choice.key || String(choice.value),
|
|
1222
|
-
value: choice.value ?? choice.key
|
|
1223
|
-
}));
|
|
1224
|
-
if (choices.length === 0 && !cursor) {
|
|
1225
|
-
console.log(
|
|
1226
|
-
chalk.yellow(`No choices available for ${fieldMeta.title}`)
|
|
1227
|
-
);
|
|
1228
|
-
}
|
|
1229
|
-
return {
|
|
1230
|
-
choices,
|
|
1231
|
-
nextCursor: page.nextCursor
|
|
1232
|
-
};
|
|
1233
|
-
} catch (error) {
|
|
1234
|
-
this.stopSpinner();
|
|
1235
|
-
console.warn(
|
|
1236
|
-
chalk.yellow(`Failed to fetch choices for ${fieldMeta.title}:`),
|
|
1237
|
-
error
|
|
1238
|
-
);
|
|
1239
|
-
return { choices: [] };
|
|
1240
|
-
}
|
|
1241
|
-
}
|
|
1242
|
-
/**
|
|
1243
|
-
* Prompt user with choices (handles both single and multi-select with pagination).
|
|
1244
|
-
* Single-select goes through @inquirer/search so users can type-to-filter long
|
|
1245
|
-
* dropdowns (SELECT fields); multi-select stays on inquirer.prompt since search
|
|
1246
|
-
* is single-select only.
|
|
1247
|
-
*/
|
|
1248
|
-
async promptWithChoices({
|
|
1249
|
-
fieldMeta,
|
|
1250
|
-
choices: initialChoices,
|
|
1251
|
-
nextCursor: initialCursor,
|
|
1252
|
-
inputs,
|
|
1253
|
-
context
|
|
1254
|
-
}) {
|
|
1255
|
-
this.stopSpinner();
|
|
1256
|
-
const choices = [...initialChoices];
|
|
1257
|
-
let nextCursor = initialCursor;
|
|
1258
|
-
const LOAD_MORE_SENTINEL = Symbol("LOAD_MORE");
|
|
1259
|
-
const SKIP_SENTINEL = Symbol("SKIP");
|
|
1260
|
-
const CUSTOM_VALUE_SENTINEL = Symbol("CUSTOM_VALUE");
|
|
1261
|
-
const message = `${fieldMeta.title}${fieldMeta.isRequired ? " (required)" : " (optional)"}:`;
|
|
1262
|
-
while (true) {
|
|
1263
|
-
let selectedValue;
|
|
1264
|
-
if (!fieldMeta.isMultiSelect) {
|
|
1265
|
-
const dataChoices = choices.map((c) => ({
|
|
1266
|
-
name: c.label,
|
|
1267
|
-
value: c.value
|
|
1268
|
-
}));
|
|
1269
|
-
selectedValue = await search({
|
|
1270
|
-
message,
|
|
1271
|
-
source: (term) => {
|
|
1272
|
-
const trimmed = (term ?? "").trim();
|
|
1273
|
-
const lower = trimmed.toLowerCase();
|
|
1274
|
-
const matches = trimmed ? dataChoices.filter((c) => c.name.toLowerCase().includes(lower)) : dataChoices;
|
|
1275
|
-
const out2 = [];
|
|
1276
|
-
const skipChoice = !fieldMeta.isRequired ? [{ name: chalk.dim("(Skip)"), value: SKIP_SENTINEL }] : [];
|
|
1277
|
-
const customValueChoice = {
|
|
1278
|
-
name: chalk.dim("(Enter custom value)"),
|
|
1279
|
-
value: CUSTOM_VALUE_SENTINEL
|
|
1280
|
-
};
|
|
1281
|
-
const loadMoreChoice = nextCursor && context ? {
|
|
1282
|
-
name: chalk.dim("(Load more...)"),
|
|
1283
|
-
value: LOAD_MORE_SENTINEL
|
|
1284
|
-
} : null;
|
|
1285
|
-
if (trimmed && matches.length > 0) {
|
|
1286
|
-
out2.push(...matches);
|
|
1287
|
-
out2.push(...skipChoice);
|
|
1288
|
-
out2.push(customValueChoice);
|
|
1289
|
-
if (loadMoreChoice) out2.push(loadMoreChoice);
|
|
1290
|
-
} else if (trimmed) {
|
|
1291
|
-
out2.push(customValueChoice);
|
|
1292
|
-
if (loadMoreChoice) out2.push(loadMoreChoice);
|
|
1293
|
-
out2.push(...skipChoice);
|
|
1294
|
-
} else {
|
|
1295
|
-
out2.push(...skipChoice);
|
|
1296
|
-
out2.push(customValueChoice);
|
|
1297
|
-
out2.push(...matches);
|
|
1298
|
-
if (loadMoreChoice) out2.push(loadMoreChoice);
|
|
1299
|
-
}
|
|
1300
|
-
return out2;
|
|
1301
|
-
}
|
|
1302
|
-
});
|
|
1303
|
-
if (selectedValue === SKIP_SENTINEL) {
|
|
1304
|
-
return void 0;
|
|
1305
|
-
}
|
|
1306
|
-
if (selectedValue === CUSTOM_VALUE_SENTINEL) {
|
|
1307
|
-
return await this.promptFreeForm(fieldMeta);
|
|
1308
|
-
}
|
|
1309
|
-
} else {
|
|
1310
|
-
const promptChoices = choices.map((c) => ({
|
|
1311
|
-
name: c.label,
|
|
1312
|
-
value: c.value
|
|
1313
|
-
}));
|
|
1314
|
-
if (nextCursor) {
|
|
1315
|
-
promptChoices.push({
|
|
1316
|
-
name: chalk.dim("(Load more...)"),
|
|
1317
|
-
value: LOAD_MORE_SENTINEL
|
|
1318
|
-
});
|
|
1319
|
-
}
|
|
1320
|
-
const promptConfig = {
|
|
1321
|
-
type: "checkbox",
|
|
1322
|
-
name: fieldMeta.key,
|
|
1323
|
-
message,
|
|
1324
|
-
choices: promptChoices,
|
|
1325
|
-
validate: (input) => {
|
|
1326
|
-
if (fieldMeta.isRequired && (!input || input.length === 0)) {
|
|
1327
|
-
return "At least one selection is required";
|
|
1328
|
-
}
|
|
1329
|
-
return true;
|
|
1330
|
-
}
|
|
1331
|
-
};
|
|
1332
|
-
const answer = await inquirer.prompt([promptConfig]);
|
|
1333
|
-
selectedValue = answer[fieldMeta.key];
|
|
1334
|
-
}
|
|
1335
|
-
const wantsMore = fieldMeta.isMultiSelect ? Array.isArray(selectedValue) && selectedValue.includes(LOAD_MORE_SENTINEL) : selectedValue === LOAD_MORE_SENTINEL;
|
|
1336
|
-
if (wantsMore && nextCursor && context) {
|
|
1337
|
-
if (fieldMeta.isMultiSelect && Array.isArray(selectedValue)) {
|
|
1338
|
-
selectedValue = selectedValue.filter((v) => v !== LOAD_MORE_SENTINEL);
|
|
1339
|
-
}
|
|
1340
|
-
const result = await this.fetchChoices(
|
|
1341
|
-
fieldMeta,
|
|
1342
|
-
inputs,
|
|
1343
|
-
context,
|
|
1344
|
-
nextCursor
|
|
1345
|
-
);
|
|
1346
|
-
choices.push(...result.choices);
|
|
1347
|
-
nextCursor = result.nextCursor;
|
|
1348
|
-
continue;
|
|
1349
|
-
}
|
|
1350
|
-
return selectedValue;
|
|
1351
|
-
}
|
|
1352
|
-
}
|
|
1353
|
-
/**
|
|
1354
|
-
* Prompt user for free-form input (text or boolean)
|
|
1355
|
-
*/
|
|
1356
|
-
async promptFreeForm(fieldMeta) {
|
|
1357
|
-
const promptConfig = {
|
|
1358
|
-
name: fieldMeta.key,
|
|
1359
|
-
message: `${fieldMeta.title}${fieldMeta.isRequired ? " (required)" : " (optional)"}:`
|
|
1360
|
-
};
|
|
1361
|
-
if (fieldMeta.valueType === "boolean") {
|
|
1362
|
-
promptConfig.type = "confirm";
|
|
1363
|
-
promptConfig.default = fieldMeta.defaultValue !== void 0 ? Boolean(fieldMeta.defaultValue) : void 0;
|
|
1364
|
-
} else if (fieldMeta.valueType === "array") {
|
|
1365
|
-
promptConfig.type = "input";
|
|
1366
|
-
promptConfig.default = fieldMeta.defaultValue;
|
|
1367
|
-
promptConfig.message = `${fieldMeta.title}${fieldMeta.isRequired ? " (required)" : " (optional)"} (JSON array or comma-separated):`;
|
|
1368
|
-
promptConfig.validate = (input) => {
|
|
1369
|
-
if (fieldMeta.isRequired && !input) {
|
|
1370
|
-
return "This field is required";
|
|
1371
|
-
}
|
|
1372
|
-
return true;
|
|
1373
|
-
};
|
|
1374
|
-
promptConfig.filter = (input) => {
|
|
1375
|
-
if (!input) return input;
|
|
1376
|
-
const trimmed = input.trim();
|
|
1377
|
-
if (trimmed.startsWith("[")) {
|
|
1378
|
-
try {
|
|
1379
|
-
return JSON.parse(trimmed);
|
|
1380
|
-
} catch {
|
|
1381
|
-
}
|
|
1382
|
-
}
|
|
1383
|
-
return trimmed.split(",").map((s) => s.trim());
|
|
1384
|
-
};
|
|
1385
|
-
} else {
|
|
1386
|
-
promptConfig.type = "input";
|
|
1387
|
-
promptConfig.default = fieldMeta.defaultValue;
|
|
1388
|
-
promptConfig.validate = (input) => {
|
|
1389
|
-
if (fieldMeta.isRequired && !input) {
|
|
1390
|
-
return "This field is required";
|
|
1391
|
-
}
|
|
1392
|
-
return true;
|
|
1393
|
-
};
|
|
1394
|
-
}
|
|
1395
|
-
if (fieldMeta.description) {
|
|
1396
|
-
promptConfig.prefix = chalk.gray(`\u2139 ${fieldMeta.description}
|
|
1397
|
-
`);
|
|
1398
|
-
}
|
|
1399
|
-
try {
|
|
1400
|
-
const answer = await inquirer.prompt([promptConfig]);
|
|
1401
|
-
return answer[fieldMeta.key];
|
|
1402
|
-
} catch (error) {
|
|
1403
|
-
if (this.isUserCancellation(error)) {
|
|
1404
|
-
console.log(chalk.yellow("\n\nOperation cancelled by user"));
|
|
1405
|
-
throw new ZapierCliUserCancellationError();
|
|
1406
|
-
}
|
|
1407
|
-
throw error;
|
|
1408
|
-
}
|
|
1409
|
-
}
|
|
1410
|
-
/**
|
|
1411
|
-
* Store field value in inputs object with validation
|
|
1412
|
-
*/
|
|
1413
|
-
storeFieldValue(inputs, key, value, isRequired) {
|
|
1414
|
-
try {
|
|
1415
|
-
if (value !== void 0 && value !== "") {
|
|
1416
|
-
inputs[key] = value;
|
|
1417
|
-
} else if (isRequired) {
|
|
1418
|
-
throw new Error(`Required field ${key} cannot be empty`);
|
|
1419
|
-
}
|
|
1420
|
-
} catch (error) {
|
|
1421
|
-
if (this.isUserCancellation(error)) {
|
|
1422
|
-
console.log(chalk.yellow("\n\nOperation cancelled by user"));
|
|
1423
|
-
throw new ZapierCliUserCancellationError();
|
|
1424
|
-
}
|
|
1425
|
-
throw error;
|
|
1426
|
-
}
|
|
1427
|
-
}
|
|
1428
|
-
async promptForField(field, inputs, context) {
|
|
1429
|
-
const fieldMeta = this.extractFieldMetadata(field);
|
|
1430
|
-
let choices = [];
|
|
1431
|
-
let nextCursor;
|
|
1432
|
-
if (fieldMeta.inlineChoices) {
|
|
1433
|
-
choices = fieldMeta.inlineChoices;
|
|
1434
|
-
} else if (fieldMeta.hasDropdown && context) {
|
|
1435
|
-
const result = await this.fetchChoices(fieldMeta, inputs, context);
|
|
1436
|
-
choices = result.choices;
|
|
1437
|
-
nextCursor = result.nextCursor;
|
|
1438
|
-
}
|
|
1439
|
-
let selectedValue;
|
|
1440
|
-
if (choices.length > 0) {
|
|
1441
|
-
selectedValue = await this.promptWithChoices({
|
|
1442
|
-
fieldMeta,
|
|
1443
|
-
choices,
|
|
1444
|
-
nextCursor,
|
|
1445
|
-
inputs,
|
|
1446
|
-
context
|
|
1447
|
-
});
|
|
1448
|
-
} else {
|
|
1449
|
-
selectedValue = await this.promptFreeForm(fieldMeta);
|
|
1450
|
-
}
|
|
1451
|
-
this.storeFieldValue(
|
|
1452
|
-
inputs,
|
|
1453
|
-
fieldMeta.key,
|
|
1454
|
-
selectedValue,
|
|
1455
|
-
fieldMeta.isRequired
|
|
1456
|
-
);
|
|
1457
|
-
}
|
|
1458
|
-
isUserCancellation(error) {
|
|
1459
|
-
const errorObj = error;
|
|
1460
|
-
return errorObj?.name === "ExitPromptError" || errorObj?.message?.includes("User force closed") || errorObj?.isTTYError === true;
|
|
1461
|
-
}
|
|
1462
|
-
hasResolver(paramName, sdk, functionName) {
|
|
1463
|
-
if (functionName && typeof sdk.getRegistry === "function") {
|
|
1464
|
-
const registry = sdk.getRegistry({ package: "cli" });
|
|
1465
|
-
const functionInfo = registry.functions.find(
|
|
1466
|
-
(f) => f.name === functionName
|
|
1467
|
-
);
|
|
1468
|
-
if (functionInfo && functionInfo.resolvers?.[paramName]) {
|
|
1469
|
-
return true;
|
|
1470
|
-
}
|
|
1471
|
-
}
|
|
1472
|
-
return false;
|
|
1473
|
-
}
|
|
1474
|
-
getResolver(paramName, sdk, functionName) {
|
|
1475
|
-
if (functionName && typeof sdk.getRegistry === "function") {
|
|
1476
|
-
const registry = sdk.getRegistry({ package: "cli" });
|
|
1477
|
-
const functionInfo = registry.functions.find(
|
|
1478
|
-
(f) => f.name === functionName
|
|
1479
|
-
);
|
|
1480
|
-
if (functionInfo && functionInfo.resolvers?.[paramName]) {
|
|
1481
|
-
return functionInfo.resolvers[paramName];
|
|
1482
|
-
}
|
|
1483
|
-
}
|
|
1484
|
-
return null;
|
|
1485
|
-
}
|
|
1486
|
-
getLocalResolvers(sdk, functionName) {
|
|
1487
|
-
if (!functionName || typeof sdk.getRegistry !== "function") {
|
|
1488
|
-
return {};
|
|
1489
|
-
}
|
|
1490
|
-
const registry = sdk.getRegistry();
|
|
1491
|
-
const functionInfo = registry.functions.find(
|
|
1492
|
-
(f) => f.name === functionName
|
|
1493
|
-
);
|
|
1494
|
-
return functionInfo?.resolvers || {};
|
|
1495
|
-
}
|
|
1496
|
-
getResolverConstants(sdk, functionName) {
|
|
1497
|
-
if (!functionName || typeof sdk.getRegistry !== "function") {
|
|
1498
|
-
return {};
|
|
1499
|
-
}
|
|
1500
|
-
const registry = sdk.getRegistry();
|
|
1501
|
-
const functionInfo = registry.functions.find(
|
|
1502
|
-
(f) => f.name === functionName
|
|
1503
|
-
);
|
|
1504
|
-
const resolvers = functionInfo?.resolvers ?? {};
|
|
1505
|
-
const constants = {};
|
|
1506
|
-
for (const [key, resolver] of Object.entries(resolvers)) {
|
|
1507
|
-
if (resolver && typeof resolver === "object" && resolver.type === "constant") {
|
|
1508
|
-
constants[key] = resolver.value;
|
|
1509
|
-
}
|
|
1510
|
-
}
|
|
1511
|
-
return constants;
|
|
1512
|
-
}
|
|
6
|
+
import chalk8 from 'chalk';
|
|
7
|
+
import { makeTheme, createPrompt, useState, usePrefix, useMemo, useEffect, useKeypress, isEnterKey, isTabKey, isUpKey, isDownKey, usePagination, Separator } from '@inquirer/core';
|
|
8
|
+
import ora from 'ora';
|
|
9
|
+
import util, { stripVTControlCharacters } from 'util';
|
|
10
|
+
import wrapAnsi3 from 'wrap-ansi';
|
|
11
|
+
import * as jwt from 'jsonwebtoken';
|
|
12
|
+
import { deletePassword, getKeyring, setPassword, getPassword } from 'cross-keychain';
|
|
13
|
+
import Conf from 'conf';
|
|
14
|
+
import * as fs from 'fs';
|
|
15
|
+
import { promises, createWriteStream, existsSync, readdirSync, rmSync, mkdirSync, writeFileSync, copyFileSync, readFileSync } from 'fs';
|
|
16
|
+
import crypto, { createHash } from 'crypto';
|
|
17
|
+
import * as path from 'path';
|
|
18
|
+
import { resolve, join, dirname, basename, relative, extname } from 'path';
|
|
19
|
+
import * as lockfile from 'proper-lockfile';
|
|
20
|
+
import { hostname } from 'os';
|
|
21
|
+
import express from 'express';
|
|
22
|
+
import { createInterface } from 'readline/promises';
|
|
23
|
+
import open from 'open';
|
|
24
|
+
import pkceChallenge from 'pkce-challenge';
|
|
25
|
+
import { startMcpServer } from '@zapier/zapier-sdk-mcp';
|
|
26
|
+
import { buildSync } from 'esbuild';
|
|
27
|
+
import { mkdir, writeFile, access } from 'fs/promises';
|
|
28
|
+
import * as ts from 'typescript';
|
|
29
|
+
import isInstalledGlobally from 'is-installed-globally';
|
|
30
|
+
import { execSync, spawn } from 'child_process';
|
|
31
|
+
import Handlebars from 'handlebars';
|
|
32
|
+
import { fileURLToPath } from 'url';
|
|
33
|
+
import { triggerInboxResolver, DrainTriggerInboxSchema, WatchTriggerInboxSchema, injectCliLogin as injectCliLogin$1, definePlugin as definePlugin$1, omitExports as omitExports$1, zapierExperimentalSdkPlugin, createSdk, CORE_OPTIONS_ID, SDK_OPTIONS_ID, addPlugin } from '@zapier/zapier-sdk/experimental';
|
|
34
|
+
import packageJsonLib, { VersionNotFoundError } from 'package-json';
|
|
35
|
+
import semver from 'semver';
|
|
36
|
+
import * as readline from 'readline';
|
|
37
|
+
|
|
38
|
+
var __defProp = Object.defineProperty;
|
|
39
|
+
var __export = (target, all) => {
|
|
40
|
+
for (var name in all)
|
|
41
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
1513
42
|
};
|
|
1514
43
|
function isSelectable(item) {
|
|
1515
44
|
return !Separator.isSeparator(item) && !item.disabled;
|
|
@@ -1529,9 +58,9 @@ function normalizeChoices(choices) {
|
|
|
1529
58
|
var theme = makeTheme({
|
|
1530
59
|
icon: { cursor: "\u276F" },
|
|
1531
60
|
style: {
|
|
1532
|
-
disabled: (text) =>
|
|
1533
|
-
searchTerm: (text) =>
|
|
1534
|
-
keysHelpTip: (keys) => keys.map(([key, action]) => `${
|
|
61
|
+
disabled: (text) => chalk8.dim(`- ${text}`),
|
|
62
|
+
searchTerm: (text) => chalk8.cyan(text),
|
|
63
|
+
keysHelpTip: (keys) => keys.map(([key, action]) => `${chalk8.bold(key)} ${chalk8.dim(action)}`).join(chalk8.dim(" \u2022 "))
|
|
1535
64
|
}
|
|
1536
65
|
});
|
|
1537
66
|
var searchSelect = createPrompt(
|
|
@@ -1669,7 +198,7 @@ async function promptText({
|
|
|
1669
198
|
]);
|
|
1670
199
|
return value;
|
|
1671
200
|
}
|
|
1672
|
-
var display = (c) => c.hint ? `${c.label} ${
|
|
201
|
+
var display = (c) => c.hint ? `${c.label} ${chalk8.dim(`(${c.hint})`)}` : c.label;
|
|
1673
202
|
function buildSelectRows(question, term) {
|
|
1674
203
|
const row = (name, action) => ({
|
|
1675
204
|
name,
|
|
@@ -1683,8 +212,8 @@ function buildSelectRows(question, term) {
|
|
|
1683
212
|
name: display(c),
|
|
1684
213
|
value: c.value
|
|
1685
214
|
}));
|
|
1686
|
-
const skipRow = offers(question, "skip") ? [row(
|
|
1687
|
-
const customRow = offers(question, "custom") ? [row(
|
|
215
|
+
const skipRow = offers(question, "skip") ? [row(chalk8.dim("Skip (optional)"), "skip")] : [];
|
|
216
|
+
const customRow = offers(question, "custom") ? [row(chalk8.dim("Enter a value manually\u2026"), "custom")] : [];
|
|
1688
217
|
const committed = !!t || question.search !== void 0;
|
|
1689
218
|
let rows;
|
|
1690
219
|
if (!committed) {
|
|
@@ -1695,13 +224,13 @@ function buildSelectRows(question, term) {
|
|
|
1695
224
|
rows = [...customRow, ...skipRow];
|
|
1696
225
|
}
|
|
1697
226
|
if (offers(question, "search"))
|
|
1698
|
-
rows.push(row(
|
|
227
|
+
rows.push(row(chalk8.cyan("Search again\u2026"), "search"));
|
|
1699
228
|
if (offers(question, "next_page"))
|
|
1700
|
-
rows.push(row(
|
|
1701
|
-
if (offers(question, "retry")) rows.push(row(
|
|
1702
|
-
if (offers(question, "cancel")) rows.push(row(
|
|
229
|
+
rows.push(row(chalk8.dim("Load more\u2026"), "next_page"));
|
|
230
|
+
if (offers(question, "retry")) rows.push(row(chalk8.yellow("Retry"), "retry"));
|
|
231
|
+
if (offers(question, "cancel")) rows.push(row(chalk8.dim("Cancel"), "cancel"));
|
|
1703
232
|
for (const note of question.notes ?? [])
|
|
1704
|
-
rows.push({ name:
|
|
233
|
+
rows.push({ name: chalk8.dim(note), value: note, disabled: true });
|
|
1705
234
|
return rows;
|
|
1706
235
|
}
|
|
1707
236
|
function foldPage(acc, question, field) {
|
|
@@ -1751,12 +280,12 @@ async function answerSelect(question, field, box, failed = false) {
|
|
|
1751
280
|
})),
|
|
1752
281
|
...offers(question, "next_page") ? [
|
|
1753
282
|
{
|
|
1754
|
-
name:
|
|
283
|
+
name: chalk8.dim("Load more\u2026"),
|
|
1755
284
|
value: { action: "next_page" }
|
|
1756
285
|
}
|
|
1757
286
|
] : [],
|
|
1758
287
|
...(question.notes ?? []).map((note) => ({
|
|
1759
|
-
name:
|
|
288
|
+
name: chalk8.dim(note),
|
|
1760
289
|
value: note,
|
|
1761
290
|
disabled: true
|
|
1762
291
|
}))
|
|
@@ -1827,14 +356,14 @@ async function answerSelect(question, field, box, failed = false) {
|
|
|
1827
356
|
case "retry":
|
|
1828
357
|
return { type: "retry" };
|
|
1829
358
|
case "skip":
|
|
1830
|
-
printAnswered(view.message,
|
|
359
|
+
printAnswered(view.message, chalk8.dim("(skipped)"));
|
|
1831
360
|
return { type: "skip" };
|
|
1832
361
|
case "cancel":
|
|
1833
362
|
return { type: "cancel" };
|
|
1834
363
|
}
|
|
1835
364
|
}
|
|
1836
365
|
function printAnswered(message, label) {
|
|
1837
|
-
console.log(`${
|
|
366
|
+
console.log(`${chalk8.green("\u2714")} ${message} ${chalk8.cyan(label)}`);
|
|
1838
367
|
}
|
|
1839
368
|
async function answerInput(question) {
|
|
1840
369
|
const message = question.placeholder ? question.message.replace(/:?\s*$/, ` (${question.placeholder}):`) : question.message;
|
|
@@ -1877,7 +406,7 @@ function createCliAnswer() {
|
|
|
1877
406
|
return ({ result }) => {
|
|
1878
407
|
if (result.error !== void 0) {
|
|
1879
408
|
const message = typeof result.error === "string" ? result.error : result.error.message;
|
|
1880
|
-
console.log(
|
|
409
|
+
console.log(chalk8.yellow(`! ${message}`));
|
|
1881
410
|
}
|
|
1882
411
|
const question = result.question;
|
|
1883
412
|
const field = question.path.length ? question.path.join(".") : "value";
|
|
@@ -1891,6 +420,49 @@ function createCliAnswer() {
|
|
|
1891
420
|
}
|
|
1892
421
|
};
|
|
1893
422
|
}
|
|
423
|
+
var ZapierCliError = class extends ZapierError {
|
|
424
|
+
};
|
|
425
|
+
var ZapierCliUserCancellationError = class extends ZapierCliError {
|
|
426
|
+
constructor(message = "Operation cancelled by user") {
|
|
427
|
+
super(message);
|
|
428
|
+
this.name = "ZapierCliUserCancellationError";
|
|
429
|
+
this.code = "ZAPIER_CLI_USER_CANCELLATION";
|
|
430
|
+
this.exitCode = 0;
|
|
431
|
+
}
|
|
432
|
+
};
|
|
433
|
+
var ZapierCliExitError = class extends ZapierCliError {
|
|
434
|
+
constructor(message, exitCode = 1) {
|
|
435
|
+
super(message);
|
|
436
|
+
this.name = "ZapierCliExitError";
|
|
437
|
+
this.code = "ZAPIER_CLI_EXIT";
|
|
438
|
+
this.exitCode = exitCode;
|
|
439
|
+
}
|
|
440
|
+
};
|
|
441
|
+
var ZapierCliValidationError = class _ZapierCliValidationError extends ZapierCliError {
|
|
442
|
+
constructor(message, options = {}) {
|
|
443
|
+
super(message);
|
|
444
|
+
this.exitCode = 1;
|
|
445
|
+
this.name = options.name ?? "ZapierCliValidationError";
|
|
446
|
+
this.code = options.code ?? "ZAPIER_CLI_VALIDATION_ERROR";
|
|
447
|
+
}
|
|
448
|
+
withMessage(message) {
|
|
449
|
+
return new _ZapierCliValidationError(message, {
|
|
450
|
+
name: this.name,
|
|
451
|
+
code: this.code
|
|
452
|
+
});
|
|
453
|
+
}
|
|
454
|
+
};
|
|
455
|
+
var ZapierCliMissingParametersError = class extends ZapierCliError {
|
|
456
|
+
constructor(params) {
|
|
457
|
+
super(
|
|
458
|
+
`Missing required parameters: ${params.map((p) => p.name).join(", ")}`
|
|
459
|
+
);
|
|
460
|
+
this.name = "ZapierCliMissingParametersError";
|
|
461
|
+
this.code = "ZAPIER_CLI_MISSING_PARAMETERS";
|
|
462
|
+
this.exitCode = 1;
|
|
463
|
+
this.params = params;
|
|
464
|
+
}
|
|
465
|
+
};
|
|
1894
466
|
|
|
1895
467
|
// src/utils/cli-options.ts
|
|
1896
468
|
var RESERVED_CLI_OPTIONS = [
|
|
@@ -1922,7 +494,7 @@ var SHARED_COMMAND_CLI_OPTIONS = [
|
|
|
1922
494
|
|
|
1923
495
|
// package.json
|
|
1924
496
|
var package_default = {
|
|
1925
|
-
version: "0.66.
|
|
497
|
+
version: "0.66.3"};
|
|
1926
498
|
|
|
1927
499
|
// src/telemetry/builders.ts
|
|
1928
500
|
function createCliBaseEvent(context = {}) {
|
|
@@ -2009,7 +581,7 @@ async function formatItemsFromSchema(_functionInfo, items, startingNumber = 0, o
|
|
|
2009
581
|
formatItemsGeneric(items, startingNumber);
|
|
2010
582
|
}
|
|
2011
583
|
function formatSingleItem(formatted, itemNumber) {
|
|
2012
|
-
let titleLine = `${
|
|
584
|
+
let titleLine = `${chalk8.gray(`${itemNumber + 1}.`)} ${chalk8.cyan(formatted.title)}`;
|
|
2013
585
|
const subtitleParts = [];
|
|
2014
586
|
if (formatted.hint !== void 0) {
|
|
2015
587
|
subtitleParts.push(
|
|
@@ -2027,11 +599,11 @@ function formatSingleItem(formatted, itemNumber) {
|
|
|
2027
599
|
}
|
|
2028
600
|
const uniqueParts = [...new Set(subtitleParts)];
|
|
2029
601
|
if (uniqueParts.length > 0) {
|
|
2030
|
-
titleLine += ` ${
|
|
602
|
+
titleLine += ` ${chalk8.gray(`(${uniqueParts.join(", ")})`)}`;
|
|
2031
603
|
}
|
|
2032
604
|
console.log(titleLine);
|
|
2033
605
|
if (formatted.description) {
|
|
2034
|
-
console.log(` ${
|
|
606
|
+
console.log(` ${chalk8.dim(formatted.description)}`);
|
|
2035
607
|
}
|
|
2036
608
|
if (formatted.raw !== void 0) {
|
|
2037
609
|
formatJsonOutput(formatted.raw);
|
|
@@ -2042,7 +614,7 @@ function formatSingleItem(formatted, itemNumber) {
|
|
|
2042
614
|
if (detail.label) {
|
|
2043
615
|
const isMultiline = detail.text.includes("\n");
|
|
2044
616
|
if (isMultiline) {
|
|
2045
|
-
console.log(` ${
|
|
617
|
+
console.log(` ${chalk8.gray(detail.label + ":")}`);
|
|
2046
618
|
const displayText = formatDetailText(
|
|
2047
619
|
detail.text,
|
|
2048
620
|
DETAIL_INDENT + " "
|
|
@@ -2051,7 +623,7 @@ function formatSingleItem(formatted, itemNumber) {
|
|
|
2051
623
|
console.log(`${DETAIL_INDENT} ${styledText}`);
|
|
2052
624
|
} else {
|
|
2053
625
|
const styledValue = applyStyle(detail.text, detail.style);
|
|
2054
|
-
console.log(` ${
|
|
626
|
+
console.log(` ${chalk8.gray(detail.label + ":")} ${styledValue}`);
|
|
2055
627
|
}
|
|
2056
628
|
} else {
|
|
2057
629
|
const displayText = formatDetailText(detail.text, DETAIL_INDENT);
|
|
@@ -2075,16 +647,16 @@ function formatDetailText(text, indent = DETAIL_INDENT) {
|
|
|
2075
647
|
function applyStyle(value, style) {
|
|
2076
648
|
switch (style) {
|
|
2077
649
|
case "dim":
|
|
2078
|
-
return
|
|
650
|
+
return chalk8.dim(value);
|
|
2079
651
|
case "accent":
|
|
2080
|
-
return
|
|
652
|
+
return chalk8.magenta(value);
|
|
2081
653
|
case "warning":
|
|
2082
|
-
return
|
|
654
|
+
return chalk8.red(value);
|
|
2083
655
|
case "success":
|
|
2084
|
-
return
|
|
656
|
+
return chalk8.green(value);
|
|
2085
657
|
case "normal":
|
|
2086
658
|
default:
|
|
2087
|
-
return
|
|
659
|
+
return chalk8.blue(value);
|
|
2088
660
|
}
|
|
2089
661
|
}
|
|
2090
662
|
function convertGenericItemToFormattedItem(item) {
|
|
@@ -2112,15 +684,15 @@ function formatMissingParamsError(error) {
|
|
|
2112
684
|
return [
|
|
2113
685
|
"Missing required parameters:",
|
|
2114
686
|
...error.params.map(
|
|
2115
|
-
({ name, isPositional:
|
|
687
|
+
({ name, isPositional: isPositional2 }) => isPositional2 ? ` \u2022 <${toKebabCase(name)}>` : ` \u2022 --${toKebabCase(name)}`
|
|
2116
688
|
)
|
|
2117
689
|
].join("\n");
|
|
2118
690
|
}
|
|
2119
691
|
function buildJsonErrors(error) {
|
|
2120
692
|
if (error instanceof ZapierCliMissingParametersError) {
|
|
2121
|
-
return error.params.map(({ name, isPositional:
|
|
693
|
+
return error.params.map(({ name, isPositional: isPositional2 }) => ({
|
|
2122
694
|
code: error.code,
|
|
2123
|
-
message:
|
|
695
|
+
message: isPositional2 ? `<${toKebabCase(name)}> is required in non-interactive mode` : `--${toKebabCase(name)} is required in non-interactive mode`
|
|
2124
696
|
}));
|
|
2125
697
|
}
|
|
2126
698
|
const code = error instanceof ZapierError ? error.code : "UNKNOWN_ERROR";
|
|
@@ -2228,10 +800,10 @@ function createInteractiveRenderer(context = {}) {
|
|
|
2228
800
|
const obj = item;
|
|
2229
801
|
const name = obj?.name || obj?.key || obj?.id || "Item";
|
|
2230
802
|
console.log(
|
|
2231
|
-
`${
|
|
803
|
+
`${chalk8.gray(`${startingNumber + index + 1}.`)} ${chalk8.cyan(String(name))}`
|
|
2232
804
|
);
|
|
2233
805
|
if (obj?.description)
|
|
2234
|
-
console.log(` ${
|
|
806
|
+
console.log(` ${chalk8.dim(String(obj.description))}`);
|
|
2235
807
|
console.log();
|
|
2236
808
|
});
|
|
2237
809
|
}
|
|
@@ -2242,35 +814,35 @@ function createInteractiveRenderer(context = {}) {
|
|
|
2242
814
|
if (!(Symbol.asyncIterator in Object(source))) {
|
|
2243
815
|
const items = source?.data;
|
|
2244
816
|
if (!Array.isArray(items) || items.length === 0) {
|
|
2245
|
-
console.log(
|
|
817
|
+
console.log(chalk8.yellow(`No ${itemName} found.`));
|
|
2246
818
|
return;
|
|
2247
819
|
}
|
|
2248
820
|
await renderItemsForDisplay(items, functionInfo, 0);
|
|
2249
|
-
console.log(
|
|
821
|
+
console.log(chalk8.green(`
|
|
2250
822
|
\u2705 Showing ${items.length} ${itemName}`));
|
|
2251
823
|
return;
|
|
2252
824
|
}
|
|
2253
825
|
let totalShown = 0;
|
|
2254
826
|
let pageCount = 0;
|
|
2255
|
-
console.log(
|
|
827
|
+
console.log(chalk8.blue(`\u{1F4CB} ${getListTitle(functionInfo)}
|
|
2256
828
|
`));
|
|
2257
829
|
for await (const page of source) {
|
|
2258
830
|
const items = page.data ?? [];
|
|
2259
831
|
pageCount++;
|
|
2260
832
|
if (items.length === 0 && pageCount === 1) {
|
|
2261
|
-
console.log(
|
|
833
|
+
console.log(chalk8.yellow(`No ${itemName} found.`));
|
|
2262
834
|
return;
|
|
2263
835
|
}
|
|
2264
836
|
if (items.length === 0) break;
|
|
2265
837
|
if (pageCount > 1) {
|
|
2266
838
|
console.clear();
|
|
2267
|
-
console.log(
|
|
839
|
+
console.log(chalk8.blue(`\u{1F4CB} ${getListTitle(functionInfo)}
|
|
2268
840
|
`));
|
|
2269
841
|
}
|
|
2270
842
|
await renderItemsForDisplay(items, functionInfo, totalShown);
|
|
2271
843
|
totalShown += items.length;
|
|
2272
844
|
console.log(
|
|
2273
|
-
|
|
845
|
+
chalk8.green(
|
|
2274
846
|
`
|
|
2275
847
|
\u2705 Showing ${totalShown} ${itemName} (page ${pageCount})`
|
|
2276
848
|
)
|
|
@@ -2289,7 +861,7 @@ function createInteractiveRenderer(context = {}) {
|
|
|
2289
861
|
break;
|
|
2290
862
|
}
|
|
2291
863
|
}
|
|
2292
|
-
console.log(
|
|
864
|
+
console.log(chalk8.gray(`
|
|
2293
865
|
\u{1F4C4} Finished browsing ${itemName}`));
|
|
2294
866
|
},
|
|
2295
867
|
async renderCollectedList(items, { maxItems, userSpecifiedMaxItems, functionInfo } = {}) {
|
|
@@ -2299,30 +871,30 @@ function createInteractiveRenderer(context = {}) {
|
|
|
2299
871
|
}
|
|
2300
872
|
const itemName = getItemName(functionInfo);
|
|
2301
873
|
if (items.length === 0) {
|
|
2302
|
-
console.log(
|
|
874
|
+
console.log(chalk8.yellow(`No ${itemName} found.`));
|
|
2303
875
|
return;
|
|
2304
876
|
}
|
|
2305
|
-
console.log(
|
|
877
|
+
console.log(chalk8.green(`
|
|
2306
878
|
\u2705 Found ${items.length} ${itemName}:
|
|
2307
879
|
`));
|
|
2308
880
|
await renderItemsForDisplay(items, functionInfo);
|
|
2309
881
|
if (userSpecifiedMaxItems && maxItems) {
|
|
2310
882
|
console.log(
|
|
2311
|
-
|
|
883
|
+
chalk8.gray(
|
|
2312
884
|
`
|
|
2313
885
|
\u{1F4C4} Showing up to ${maxItems} ${itemName} (--max-items ${maxItems})`
|
|
2314
886
|
)
|
|
2315
887
|
);
|
|
2316
888
|
} else {
|
|
2317
|
-
console.log(
|
|
889
|
+
console.log(chalk8.gray(`
|
|
2318
890
|
\u{1F4C4} All available ${itemName} shown`));
|
|
2319
891
|
}
|
|
2320
892
|
},
|
|
2321
893
|
renderItem(value, options) {
|
|
2322
894
|
if (options?.outputFile) {
|
|
2323
895
|
const label = options.commandName ? `\u2705 ${options.commandName} completed successfully!` : "\u2705 Done!";
|
|
2324
|
-
console.log(
|
|
2325
|
-
console.log(
|
|
896
|
+
console.log(chalk8.green(label));
|
|
897
|
+
console.log(chalk8.gray(`Output written to: ${options.outputFile}`));
|
|
2326
898
|
} else {
|
|
2327
899
|
formatJsonOutput(value);
|
|
2328
900
|
}
|
|
@@ -2332,17 +904,17 @@ function createInteractiveRenderer(context = {}) {
|
|
|
2332
904
|
},
|
|
2333
905
|
renderError(error) {
|
|
2334
906
|
if (error instanceof ZapierCliMissingParametersError) {
|
|
2335
|
-
console.error(
|
|
2336
|
-
console.error("\n" +
|
|
907
|
+
console.error(chalk8.red("\u274C " + formatMissingParamsError(error)));
|
|
908
|
+
console.error("\n" + chalk8.dim("Use --help to see available options"));
|
|
2337
909
|
throw new ZapierCliExitError(error.message, 1);
|
|
2338
910
|
}
|
|
2339
911
|
if (error instanceof ZapierError) {
|
|
2340
912
|
const formattedMessage = formatErrorMessage(error);
|
|
2341
|
-
console.error(
|
|
913
|
+
console.error(chalk8.red("\u274C Error:"), formattedMessage);
|
|
2342
914
|
throw new ZapierCliExitError(formattedMessage, 1);
|
|
2343
915
|
}
|
|
2344
916
|
const msg = error instanceof Error ? error.message : "Unknown error";
|
|
2345
|
-
console.error(
|
|
917
|
+
console.error(chalk8.red("\u274C Error:"), msg);
|
|
2346
918
|
throw new ZapierCliExitError(msg, 1);
|
|
2347
919
|
}
|
|
2348
920
|
};
|
|
@@ -2458,7 +1030,7 @@ async function promptConfirm(confirmType, itemType) {
|
|
|
2458
1030
|
}
|
|
2459
1031
|
const configOrFn = CONFIRM_MESSAGES[confirmType];
|
|
2460
1032
|
const { messageBefore, messageAfter } = typeof configOrFn === "function" ? configOrFn(itemType) : configOrFn;
|
|
2461
|
-
console.log(
|
|
1033
|
+
console.log(chalk8.yellow(`
|
|
2462
1034
|
${messageBefore}
|
|
2463
1035
|
`));
|
|
2464
1036
|
const { confirmed } = await inquirer.prompt([
|
|
@@ -2482,12 +1054,12 @@ function emitParamDeprecationWarnings({
|
|
|
2482
1054
|
if (Array.isArray(value) && value.length === 0) continue;
|
|
2483
1055
|
console.warn();
|
|
2484
1056
|
console.warn(
|
|
2485
|
-
|
|
1057
|
+
chalk8.yellow.bold("\u26A0\uFE0F DEPRECATION WARNING") + chalk8.yellow(
|
|
2486
1058
|
` - \`${toKebabCase(param.name)}\` is deprecated and may be removed in a future release.`
|
|
2487
1059
|
)
|
|
2488
1060
|
);
|
|
2489
1061
|
if (param.deprecationMessage) {
|
|
2490
|
-
console.warn(
|
|
1062
|
+
console.warn(chalk8.yellow(` ${param.deprecationMessage}`));
|
|
2491
1063
|
}
|
|
2492
1064
|
console.warn();
|
|
2493
1065
|
}
|
|
@@ -2526,20 +1098,16 @@ function getAuthFlowIsHeadless({
|
|
|
2526
1098
|
if (isCallbackResume && !isHeadless) return null;
|
|
2527
1099
|
return isHeadless;
|
|
2528
1100
|
}
|
|
2529
|
-
function analyzeZodSchema(schema
|
|
1101
|
+
function analyzeZodSchema(schema) {
|
|
2530
1102
|
const parameters = [];
|
|
2531
1103
|
const schemaDef = schema._zod?.def;
|
|
2532
1104
|
if (schemaDef?.type === "effect" && schemaDef.innerType) {
|
|
2533
|
-
return analyzeZodSchema(schemaDef.innerType
|
|
1105
|
+
return analyzeZodSchema(schemaDef.innerType);
|
|
2534
1106
|
}
|
|
2535
1107
|
if (schema instanceof z.ZodObject) {
|
|
2536
1108
|
const shape = schema.shape;
|
|
2537
1109
|
for (const [key, fieldSchema] of Object.entries(shape)) {
|
|
2538
|
-
const param = analyzeZodField(
|
|
2539
|
-
key,
|
|
2540
|
-
fieldSchema,
|
|
2541
|
-
functionInfo
|
|
2542
|
-
);
|
|
1110
|
+
const param = analyzeZodField(key, fieldSchema);
|
|
2543
1111
|
if (param) {
|
|
2544
1112
|
parameters.push(param);
|
|
2545
1113
|
}
|
|
@@ -2547,7 +1115,7 @@ function analyzeZodSchema(schema, functionInfo) {
|
|
|
2547
1115
|
}
|
|
2548
1116
|
return parameters;
|
|
2549
1117
|
}
|
|
2550
|
-
function analyzeZodField(name, schema
|
|
1118
|
+
function analyzeZodField(name, schema) {
|
|
2551
1119
|
let baseSchema = schema;
|
|
2552
1120
|
let required = true;
|
|
2553
1121
|
let defaultValue = void 0;
|
|
@@ -2607,10 +1175,6 @@ function analyzeZodField(name, schema, functionInfo) {
|
|
|
2607
1175
|
} else if (baseSchema instanceof z.ZodObject || baseSchema instanceof z.ZodRecord) {
|
|
2608
1176
|
paramType = "object";
|
|
2609
1177
|
}
|
|
2610
|
-
let paramHasResolver = false;
|
|
2611
|
-
if (functionInfo?.resolvers?.[name] || functionInfo?.boundResolvers?.[name]) {
|
|
2612
|
-
paramHasResolver = true;
|
|
2613
|
-
}
|
|
2614
1178
|
return {
|
|
2615
1179
|
name,
|
|
2616
1180
|
type: paramType,
|
|
@@ -2618,16 +1182,21 @@ function analyzeZodField(name, schema, functionInfo) {
|
|
|
2618
1182
|
description: schema.description,
|
|
2619
1183
|
default: defaultValue,
|
|
2620
1184
|
choices,
|
|
2621
|
-
hasResolver: paramHasResolver,
|
|
2622
1185
|
isPositional: isPositional(schema),
|
|
2623
1186
|
elementType,
|
|
2624
1187
|
deprecationMessage,
|
|
2625
1188
|
isDeprecated
|
|
2626
1189
|
};
|
|
2627
1190
|
}
|
|
2628
|
-
function
|
|
1191
|
+
function positionalProjection(schema, positional) {
|
|
1192
|
+
if (!positional?.length || !schema) return [];
|
|
1193
|
+
const shape = schema.shape;
|
|
1194
|
+
if (!shape) return [];
|
|
1195
|
+
return positional.filter((name) => name in shape).map((name) => ({ name, schema: shape[name] }));
|
|
1196
|
+
}
|
|
1197
|
+
function analyzePositionalProjection(projection) {
|
|
2629
1198
|
const cliParams = [];
|
|
2630
|
-
for (const param of
|
|
1199
|
+
for (const param of projection) {
|
|
2631
1200
|
let schema = param.schema;
|
|
2632
1201
|
let isOptional = false;
|
|
2633
1202
|
if (schema instanceof z.ZodOptional) {
|
|
@@ -2637,11 +1206,7 @@ function analyzeInputParameters(inputParameters, functionInfo) {
|
|
|
2637
1206
|
if (schema instanceof z.ZodObject) {
|
|
2638
1207
|
const shape = schema.shape;
|
|
2639
1208
|
for (const [key, fieldSchema] of Object.entries(shape)) {
|
|
2640
|
-
const analyzed = analyzeZodField(
|
|
2641
|
-
key,
|
|
2642
|
-
fieldSchema,
|
|
2643
|
-
functionInfo
|
|
2644
|
-
);
|
|
1209
|
+
const analyzed = analyzeZodField(key, fieldSchema);
|
|
2645
1210
|
if (analyzed) {
|
|
2646
1211
|
if (isOptional) {
|
|
2647
1212
|
analyzed.required = false;
|
|
@@ -2650,7 +1215,7 @@ function analyzeInputParameters(inputParameters, functionInfo) {
|
|
|
2650
1215
|
}
|
|
2651
1216
|
}
|
|
2652
1217
|
} else {
|
|
2653
|
-
const analyzed = analyzeZodField(param.name, param.schema
|
|
1218
|
+
const analyzed = analyzeZodField(param.name, param.schema);
|
|
2654
1219
|
if (analyzed) {
|
|
2655
1220
|
analyzed.required = !isOptional;
|
|
2656
1221
|
analyzed.isPositional = true;
|
|
@@ -2660,29 +1225,25 @@ function analyzeInputParameters(inputParameters, functionInfo) {
|
|
|
2660
1225
|
}
|
|
2661
1226
|
return cliParams;
|
|
2662
1227
|
}
|
|
2663
|
-
function
|
|
2664
|
-
const
|
|
2665
|
-
for (const
|
|
2666
|
-
|
|
2667
|
-
if (
|
|
2668
|
-
schema = schema._zod.def.innerType;
|
|
2669
|
-
}
|
|
2670
|
-
if (schema instanceof z.ZodObject) {
|
|
2671
|
-
const shape = schema.shape;
|
|
1228
|
+
function nestPositionalParams(projection, flatParams) {
|
|
1229
|
+
const out2 = {};
|
|
1230
|
+
for (const { name, schema } of projection) {
|
|
1231
|
+
const inner = schema instanceof z.ZodOptional ? schema._zod.def.innerType : schema;
|
|
1232
|
+
if (inner instanceof z.ZodObject) {
|
|
2672
1233
|
const obj = {};
|
|
2673
1234
|
let hasValues = false;
|
|
2674
|
-
for (const key of Object.keys(shape)) {
|
|
1235
|
+
for (const key of Object.keys(inner.shape)) {
|
|
2675
1236
|
if (key in flatParams && flatParams[key] !== void 0) {
|
|
2676
1237
|
obj[key] = flatParams[key];
|
|
2677
1238
|
hasValues = true;
|
|
2678
1239
|
}
|
|
2679
1240
|
}
|
|
2680
|
-
|
|
2681
|
-
} else {
|
|
2682
|
-
|
|
1241
|
+
if (hasValues) out2[name] = obj;
|
|
1242
|
+
} else if (flatParams[name] !== void 0) {
|
|
1243
|
+
out2[name] = flatParams[name];
|
|
2683
1244
|
}
|
|
2684
1245
|
}
|
|
2685
|
-
return
|
|
1246
|
+
return out2;
|
|
2686
1247
|
}
|
|
2687
1248
|
function methodNameToCliCommand(methodName) {
|
|
2688
1249
|
return toKebabCase(methodName);
|
|
@@ -2694,7 +1255,7 @@ function generateCliCommands(program2, sdk) {
|
|
|
2694
1255
|
}
|
|
2695
1256
|
const registry = sdk.getRegistry({ package: "cli" });
|
|
2696
1257
|
registry.functions.forEach((fnInfo) => {
|
|
2697
|
-
if (!fnInfo.inputSchema
|
|
1258
|
+
if (!fnInfo.inputSchema) {
|
|
2698
1259
|
console.warn(`Schema not found for ${fnInfo.name}`);
|
|
2699
1260
|
return;
|
|
2700
1261
|
}
|
|
@@ -2764,12 +1325,11 @@ function generateCliCommands(program2, sdk) {
|
|
|
2764
1325
|
});
|
|
2765
1326
|
}
|
|
2766
1327
|
function createCommandConfig(cliCommandName, functionInfo, sdk) {
|
|
2767
|
-
const usesInputParameters = !!functionInfo.inputParameters;
|
|
2768
1328
|
const schema = functionInfo.inputSchema;
|
|
2769
|
-
const
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
1329
|
+
const projection = positionalProjection(schema, functionInfo.positional);
|
|
1330
|
+
const usesPositionalProjection = projection.length > 0;
|
|
1331
|
+
const parameters = usesPositionalProjection ? analyzePositionalProjection(projection) : analyzeZodSchema(schema);
|
|
1332
|
+
for (const param of parameters) param.promptable = true;
|
|
2773
1333
|
const schemaAliases = getSchemaAliases(schema);
|
|
2774
1334
|
if (schemaAliases) {
|
|
2775
1335
|
const aliasedNames = new Set(Object.keys(schemaAliases));
|
|
@@ -2819,72 +1379,55 @@ function createCommandConfig(cliCommandName, functionInfo, sdk) {
|
|
|
2819
1379
|
}
|
|
2820
1380
|
}
|
|
2821
1381
|
}
|
|
2822
|
-
const
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
const
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
missing.set(p.name, isRegisteredPositional(p.name));
|
|
2852
|
-
}
|
|
1382
|
+
const resolvers = functionInfo.resolvers;
|
|
1383
|
+
const seedInput = usesPositionalProjection ? nestPositionalParams(projection, rawParams) : Object.fromEntries(
|
|
1384
|
+
Object.entries(rawParams).filter(([, v]) => v !== void 0)
|
|
1385
|
+
);
|
|
1386
|
+
const controller = createController(sdk);
|
|
1387
|
+
const spinner = promptingEnabled && !options.debug ? ora({ text: "", spinner: "dots" }) : void 0;
|
|
1388
|
+
let resolved;
|
|
1389
|
+
try {
|
|
1390
|
+
const isRegisteredPositional = (name) => {
|
|
1391
|
+
const p = parameters.find((param) => param.name === name);
|
|
1392
|
+
return !!p && takesPositionalSlot(p);
|
|
1393
|
+
};
|
|
1394
|
+
spinner?.start();
|
|
1395
|
+
resolved = await controller.resolve({
|
|
1396
|
+
method: functionInfo.name,
|
|
1397
|
+
input: seedInput,
|
|
1398
|
+
answer: spinner ? withEngineSpinner(createCliAnswer(), spinner) : promptingEnabled ? createCliAnswer() : ({ state }) => {
|
|
1399
|
+
const missing = /* @__PURE__ */ new Map();
|
|
1400
|
+
missing.set(
|
|
1401
|
+
state.current?.join(".") ?? "value",
|
|
1402
|
+
isRegisteredPositional(String(state.current?.[0] ?? ""))
|
|
1403
|
+
);
|
|
1404
|
+
for (const p of parameters) {
|
|
1405
|
+
if (!p.required || p.isDeprecated || p.isAlias) continue;
|
|
1406
|
+
if (p.name in state.resolved) continue;
|
|
1407
|
+
if (state.settled.includes(p.name)) continue;
|
|
1408
|
+
if (resolvers?.[p.name]?.type === "constant") continue;
|
|
1409
|
+
if (!missing.has(p.name)) {
|
|
1410
|
+
missing.set(p.name, isRegisteredPositional(p.name));
|
|
2853
1411
|
}
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
)
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
}
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
throw err;
|
|
2868
|
-
} finally {
|
|
2869
|
-
spinner?.stop();
|
|
1412
|
+
}
|
|
1413
|
+
throw new ZapierCliMissingParametersError(
|
|
1414
|
+
[...missing].map(([name, isPositional2]) => ({
|
|
1415
|
+
name,
|
|
1416
|
+
isPositional: isPositional2
|
|
1417
|
+
}))
|
|
1418
|
+
);
|
|
1419
|
+
},
|
|
1420
|
+
interactive: promptingEnabled
|
|
1421
|
+
});
|
|
1422
|
+
} catch (err) {
|
|
1423
|
+
if (err instanceof CoreCancelledSignal) {
|
|
1424
|
+
throw new ZapierCliUserCancellationError();
|
|
2870
1425
|
}
|
|
2871
|
-
|
|
2872
|
-
}
|
|
2873
|
-
|
|
2874
|
-
const resolved = await resolver.resolveParameters(
|
|
2875
|
-
schema,
|
|
2876
|
-
rawParams,
|
|
2877
|
-
sdk,
|
|
2878
|
-
functionInfo.name,
|
|
2879
|
-
{
|
|
2880
|
-
interactiveMode,
|
|
2881
|
-
debug: !!options.debug || process.env.DEBUG === "true" || process.argv.includes("--debug")
|
|
2882
|
-
}
|
|
2883
|
-
);
|
|
2884
|
-
Object.assign(resolvedParams, resolved);
|
|
2885
|
-
} else {
|
|
2886
|
-
Object.assign(resolvedParams, rawParams);
|
|
1426
|
+
throw err;
|
|
1427
|
+
} finally {
|
|
1428
|
+
spinner?.stop();
|
|
2887
1429
|
}
|
|
1430
|
+
Object.assign(resolvedParams, resolved);
|
|
2888
1431
|
const confirm = functionInfo.confirm;
|
|
2889
1432
|
let confirmMessageAfter;
|
|
2890
1433
|
if (confirm && interactiveMode) {
|
|
@@ -2893,7 +1436,7 @@ function createCommandConfig(cliCommandName, functionInfo, sdk) {
|
|
|
2893
1436
|
functionInfo.itemType
|
|
2894
1437
|
);
|
|
2895
1438
|
if (!confirmResult.confirmed) {
|
|
2896
|
-
console.log(
|
|
1439
|
+
console.log(chalk8.yellow("Operation cancelled."));
|
|
2897
1440
|
return;
|
|
2898
1441
|
}
|
|
2899
1442
|
confirmMessageAfter = confirmResult.messageAfter;
|
|
@@ -2921,10 +1464,9 @@ function createCommandConfig(cliCommandName, functionInfo, sdk) {
|
|
|
2921
1464
|
}
|
|
2922
1465
|
case "single": {
|
|
2923
1466
|
const callSdkMethod = () => {
|
|
2924
|
-
if (
|
|
2925
|
-
const positionalArgs =
|
|
2926
|
-
|
|
2927
|
-
resolvedParams
|
|
1467
|
+
if (usesPositionalProjection) {
|
|
1468
|
+
const positionalArgs = (functionInfo.positional ?? []).map(
|
|
1469
|
+
(name) => resolvedParams[name]
|
|
2928
1470
|
);
|
|
2929
1471
|
return sdkMethod(...positionalArgs);
|
|
2930
1472
|
}
|
|
@@ -2955,7 +1497,7 @@ function createCommandConfig(cliCommandName, functionInfo, sdk) {
|
|
|
2955
1497
|
renderer.renderItem(normalizedResult.value);
|
|
2956
1498
|
}
|
|
2957
1499
|
if (confirmMessageAfter) {
|
|
2958
|
-
console.log(
|
|
1500
|
+
console.log(chalk8.yellow(`
|
|
2959
1501
|
${confirmMessageAfter}`));
|
|
2960
1502
|
}
|
|
2961
1503
|
break;
|
|
@@ -3032,7 +1574,7 @@ function addCommand(program2, commandName, config2) {
|
|
|
3032
1574
|
let hasPositionalArray = false;
|
|
3033
1575
|
config2.parameters.forEach((param) => {
|
|
3034
1576
|
const kebabName = toKebabCase(param.name);
|
|
3035
|
-
if (param.
|
|
1577
|
+
if (param.promptable && param.required) {
|
|
3036
1578
|
command.argument(
|
|
3037
1579
|
`[${kebabName}]`,
|
|
3038
1580
|
param.description || `${kebabName} parameter`
|
|
@@ -4151,20 +2693,20 @@ var getCallablePromise = () => {
|
|
|
4151
2693
|
var getCallablePromise_default = getCallablePromise;
|
|
4152
2694
|
var log = {
|
|
4153
2695
|
info: (message, ...args) => {
|
|
4154
|
-
console.error(
|
|
2696
|
+
console.error(chalk8.blue("\u2139"), message, ...args);
|
|
4155
2697
|
},
|
|
4156
2698
|
error: (message, ...args) => {
|
|
4157
|
-
console.error(
|
|
2699
|
+
console.error(chalk8.red("\u2716"), message, ...args);
|
|
4158
2700
|
},
|
|
4159
2701
|
success: (message, ...args) => {
|
|
4160
|
-
console.error(
|
|
2702
|
+
console.error(chalk8.green("\u2713"), message, ...args);
|
|
4161
2703
|
},
|
|
4162
2704
|
warn: (message, ...args) => {
|
|
4163
|
-
console.error(
|
|
2705
|
+
console.error(chalk8.yellow("\u26A0"), message, ...args);
|
|
4164
2706
|
},
|
|
4165
2707
|
debug: (message, ...args) => {
|
|
4166
2708
|
if (process.env.DEBUG === "true" || process.argv.includes("--debug")) {
|
|
4167
|
-
console.error(
|
|
2709
|
+
console.error(chalk8.gray("\u{1F41B}"), message, ...args);
|
|
4168
2710
|
}
|
|
4169
2711
|
}
|
|
4170
2712
|
};
|
|
@@ -7321,7 +5863,7 @@ function buildTemplateVariables({
|
|
|
7321
5863
|
};
|
|
7322
5864
|
}
|
|
7323
5865
|
function cleanupProject({ projectDir }) {
|
|
7324
|
-
console.log("\n" +
|
|
5866
|
+
console.log("\n" + chalk8.yellow("!") + " Cleaning up...");
|
|
7325
5867
|
rmSync(projectDir, { recursive: true, force: true });
|
|
7326
5868
|
}
|
|
7327
5869
|
async function withInterruptCleanup(cleanup, fn) {
|
|
@@ -7531,8 +6073,8 @@ function buildNextSteps({
|
|
|
7531
6073
|
}
|
|
7532
6074
|
function createConsoleDisplayHooks() {
|
|
7533
6075
|
return {
|
|
7534
|
-
onItemComplete: (message) => console.log(" " +
|
|
7535
|
-
onWarn: (message) => console.warn(
|
|
6076
|
+
onItemComplete: (message) => console.log(" " + chalk8.green("\u2713") + " " + chalk8.dim(message)),
|
|
6077
|
+
onWarn: (message) => console.warn(chalk8.yellow("!") + " " + message),
|
|
7536
6078
|
onStepStart: ({
|
|
7537
6079
|
description,
|
|
7538
6080
|
stepNumber,
|
|
@@ -7541,31 +6083,31 @@ function createConsoleDisplayHooks() {
|
|
|
7541
6083
|
nonInteractive
|
|
7542
6084
|
}) => {
|
|
7543
6085
|
const progressMessage = `${description}...`;
|
|
7544
|
-
const stepCounter =
|
|
6086
|
+
const stepCounter = chalk8.dim(`${stepNumber}/${totalSteps}`);
|
|
7545
6087
|
if (nonInteractive) {
|
|
7546
6088
|
console.log(
|
|
7547
|
-
"\n" +
|
|
6089
|
+
"\n" + chalk8.bold(`\u276F ${progressMessage}`) + " " + stepCounter + "\n"
|
|
7548
6090
|
);
|
|
7549
6091
|
} else {
|
|
7550
6092
|
console.log(
|
|
7551
|
-
|
|
6093
|
+
chalk8.dim("\u2192") + " " + progressMessage + " " + stepCounter
|
|
7552
6094
|
);
|
|
7553
6095
|
}
|
|
7554
6096
|
if (command) {
|
|
7555
|
-
console.log(" " +
|
|
6097
|
+
console.log(" " + chalk8.cyan(`$ ${command}`));
|
|
7556
6098
|
}
|
|
7557
6099
|
},
|
|
7558
6100
|
onStepSuccess: ({ stepNumber, totalSteps }) => console.log(
|
|
7559
|
-
"\n" +
|
|
6101
|
+
"\n" + chalk8.green("\u2713") + " " + chalk8.dim(`Step ${stepNumber}/${totalSteps} complete`) + "\n"
|
|
7560
6102
|
),
|
|
7561
6103
|
onStepError: ({ description, command, err }) => {
|
|
7562
6104
|
const detail = err instanceof Error && err.message ? `
|
|
7563
|
-
${
|
|
6105
|
+
${chalk8.dim(err.message)}` : "";
|
|
7564
6106
|
const hint = command ? `
|
|
7565
|
-
${
|
|
6107
|
+
${chalk8.dim("run manually:")} ${chalk8.cyan(`$ ${command}`)}` : "";
|
|
7566
6108
|
console.error(
|
|
7567
6109
|
`
|
|
7568
|
-
${
|
|
6110
|
+
${chalk8.red("\u2716")} ${chalk8.bold(description)}${chalk8.dim(" failed")}${detail}${hint}`
|
|
7569
6111
|
);
|
|
7570
6112
|
}
|
|
7571
6113
|
};
|
|
@@ -7577,22 +6119,22 @@ function displaySummaryAndNextSteps({
|
|
|
7577
6119
|
packageManager
|
|
7578
6120
|
}) {
|
|
7579
6121
|
const formatStatus = (complete) => ({
|
|
7580
|
-
icon: complete ?
|
|
7581
|
-
text: complete ?
|
|
6122
|
+
icon: complete ? chalk8.green("\u2713") : chalk8.yellow("!"),
|
|
6123
|
+
text: complete ? chalk8.green("Setup complete") : chalk8.yellow("Setup interrupted")
|
|
7582
6124
|
});
|
|
7583
|
-
const formatNextStep = (step, i) => " " +
|
|
7584
|
-
const formatCommand = (cmd) => " " +
|
|
7585
|
-
const formatCompletedStep = (step) => " " +
|
|
6125
|
+
const formatNextStep = (step, i) => " " + chalk8.dim(`${i + 1}.`) + " " + chalk8.bold(step.description);
|
|
6126
|
+
const formatCommand = (cmd) => " " + chalk8.cyan(`$ ${cmd}`);
|
|
6127
|
+
const formatCompletedStep = (step) => " " + chalk8.green("\u2713") + " " + step.description;
|
|
7586
6128
|
const { execCmd } = getPackageManagerCommands({ packageManager });
|
|
7587
6129
|
const leftoverSteps = steps.filter(
|
|
7588
6130
|
(s) => !completedSetupStepIds.includes(s.id)
|
|
7589
6131
|
);
|
|
7590
6132
|
const isComplete = leftoverSteps.length === 0;
|
|
7591
6133
|
const status = formatStatus(isComplete);
|
|
7592
|
-
console.log("\n" +
|
|
7593
|
-
console.log(" " +
|
|
6134
|
+
console.log("\n" + chalk8.bold("\u276F Summary") + "\n");
|
|
6135
|
+
console.log(" " + chalk8.dim("Project") + " " + chalk8.bold(projectName));
|
|
7594
6136
|
console.log(
|
|
7595
|
-
" " +
|
|
6137
|
+
" " + chalk8.dim("Status") + " " + status.icon + " " + status.text
|
|
7596
6138
|
);
|
|
7597
6139
|
const completedSteps = steps.filter(
|
|
7598
6140
|
(s) => completedSetupStepIds.includes(s.id)
|
|
@@ -7602,7 +6144,7 @@ function displaySummaryAndNextSteps({
|
|
|
7602
6144
|
for (const step of completedSteps) console.log(formatCompletedStep(step));
|
|
7603
6145
|
}
|
|
7604
6146
|
const nextSteps = buildNextSteps({ projectName, leftoverSteps, execCmd });
|
|
7605
|
-
console.log("\n" +
|
|
6147
|
+
console.log("\n" + chalk8.bold("\u276F Next Steps") + "\n");
|
|
7606
6148
|
nextSteps.forEach((step, i) => {
|
|
7607
6149
|
console.log(formatNextStep(step, i));
|
|
7608
6150
|
if (step.command) console.log(formatCommand(step.command));
|
|
@@ -7679,13 +6221,13 @@ function createInteractiveCallback() {
|
|
|
7679
6221
|
const attrs = message.message_attributes;
|
|
7680
6222
|
console.log(
|
|
7681
6223
|
`
|
|
7682
|
-
${
|
|
6224
|
+
${chalk8.bold(`Message #${messageNumber}`)} ${chalk8.dim(message.id)} ${chalk8.dim(`(lease #${attrs.lease_count})`)}`
|
|
7683
6225
|
);
|
|
7684
6226
|
if (attrs.error_message) {
|
|
7685
|
-
console.log(
|
|
6227
|
+
console.log(chalk8.yellow(` upstream error: ${attrs.error_message}`));
|
|
7686
6228
|
}
|
|
7687
6229
|
if (attrs.possible_duplicate_data) {
|
|
7688
|
-
console.log(
|
|
6230
|
+
console.log(chalk8.yellow(" possible duplicate data"));
|
|
7689
6231
|
}
|
|
7690
6232
|
while (true) {
|
|
7691
6233
|
let action;
|
|
@@ -7715,7 +6257,7 @@ ${chalk.bold(`Message #${messageNumber}`)} ${chalk.dim(message.id)} ${chalk.dim(
|
|
|
7715
6257
|
throw error;
|
|
7716
6258
|
}
|
|
7717
6259
|
if (action === "view") {
|
|
7718
|
-
console.log(
|
|
6260
|
+
console.log(chalk8.dim(JSON.stringify(message.payload, null, 2)));
|
|
7719
6261
|
continue;
|
|
7720
6262
|
}
|
|
7721
6263
|
if (action === "ack") {
|
|
@@ -7818,7 +6360,7 @@ function describeReason(reason) {
|
|
|
7818
6360
|
}
|
|
7819
6361
|
function printDrainError(reason, message) {
|
|
7820
6362
|
console.error(
|
|
7821
|
-
|
|
6363
|
+
chalk8.red(`Error processing ${message.id}: ${describeReason(reason)}`)
|
|
7822
6364
|
);
|
|
7823
6365
|
}
|
|
7824
6366
|
function printDrainSummary(counts) {
|
|
@@ -7828,7 +6370,7 @@ function printDrainSummary(counts) {
|
|
|
7828
6370
|
if (skipped > 0) parts.push(`${skipped} skipped`);
|
|
7829
6371
|
parts.push(`${counts.rejected} rejected`);
|
|
7830
6372
|
console.log(
|
|
7831
|
-
|
|
6373
|
+
chalk8.dim(
|
|
7832
6374
|
`
|
|
7833
6375
|
Processed ${total} message${total === 1 ? "" : "s"} (${parts.join(", ")}).`
|
|
7834
6376
|
)
|
|
@@ -7836,7 +6378,7 @@ Processed ${total} message${total === 1 ? "" : "s"} (${parts.join(", ")}).`
|
|
|
7836
6378
|
}
|
|
7837
6379
|
function warnInteractiveContinueOnErrorOverride() {
|
|
7838
6380
|
console.warn(
|
|
7839
|
-
|
|
6381
|
+
chalk8.yellow(
|
|
7840
6382
|
'Note: continueOnError=false is overridden to true in interactive mode (the "Skip (let lease expire)" choice would otherwise terminate the drain).'
|
|
7841
6383
|
)
|
|
7842
6384
|
);
|
|
@@ -8162,7 +6704,7 @@ function renderDeprecationNotices() {
|
|
|
8162
6704
|
console.error();
|
|
8163
6705
|
for (const message of messages) {
|
|
8164
6706
|
for (const line of buildBoxLines(message)) {
|
|
8165
|
-
console.error(
|
|
6707
|
+
console.error(chalk8.red.bold(line));
|
|
8166
6708
|
}
|
|
8167
6709
|
console.error();
|
|
8168
6710
|
}
|
|
@@ -8183,7 +6725,7 @@ function buildBoxLines(message) {
|
|
|
8183
6725
|
// package.json with { type: 'json' }
|
|
8184
6726
|
var package_default2 = {
|
|
8185
6727
|
name: "@zapier/zapier-sdk-cli",
|
|
8186
|
-
version: "0.66.
|
|
6728
|
+
version: "0.66.3"};
|
|
8187
6729
|
|
|
8188
6730
|
// src/sdk.ts
|
|
8189
6731
|
var warnedDeprecatedMethods = /* @__PURE__ */ new Set();
|
|
@@ -8194,9 +6736,9 @@ var cliCoreOptions = {
|
|
|
8194
6736
|
warnedDeprecatedMethods.add(methodName);
|
|
8195
6737
|
console.warn();
|
|
8196
6738
|
console.warn(
|
|
8197
|
-
|
|
6739
|
+
chalk8.yellow.bold("\u26A0\uFE0F DEPRECATION WARNING") + chalk8.yellow(` - \`${toKebabCase(methodName)}\` is deprecated.`)
|
|
8198
6740
|
);
|
|
8199
|
-
console.warn(
|
|
6741
|
+
console.warn(chalk8.yellow(` ${deprecation.message}`));
|
|
8200
6742
|
console.warn();
|
|
8201
6743
|
}
|
|
8202
6744
|
};
|
|
@@ -8486,26 +7028,26 @@ function displayUpdateNotification(versionInfo, packageName) {
|
|
|
8486
7028
|
if (versionInfo.isDeprecated) {
|
|
8487
7029
|
console.error();
|
|
8488
7030
|
console.error(
|
|
8489
|
-
|
|
7031
|
+
chalk8.red.bold("\u26A0\uFE0F DEPRECATION WARNING") + chalk8.red(
|
|
8490
7032
|
` - ${packageName} v${versionInfo.currentVersion} is deprecated.`
|
|
8491
7033
|
)
|
|
8492
7034
|
);
|
|
8493
7035
|
if (versionInfo.deprecationMessage) {
|
|
8494
|
-
console.error(
|
|
7036
|
+
console.error(chalk8.red(` ${versionInfo.deprecationMessage}`));
|
|
8495
7037
|
}
|
|
8496
|
-
console.error(
|
|
7038
|
+
console.error(chalk8.red(` Please update to the latest version.`));
|
|
8497
7039
|
console.error();
|
|
8498
7040
|
}
|
|
8499
7041
|
if (versionInfo.hasUpdate) {
|
|
8500
7042
|
console.error();
|
|
8501
7043
|
console.error(
|
|
8502
|
-
|
|
7044
|
+
chalk8.yellow.bold("\u{1F4E6} Update available!") + chalk8.yellow(
|
|
8503
7045
|
` ${packageName} v${versionInfo.currentVersion} \u2192 v${versionInfo.latestVersion}`
|
|
8504
7046
|
)
|
|
8505
7047
|
);
|
|
8506
7048
|
console.error(
|
|
8507
|
-
|
|
8508
|
-
` Run ${
|
|
7049
|
+
chalk8.yellow(
|
|
7050
|
+
` Run ${chalk8.bold(getUpdateCommand(packageName))} to update.`
|
|
8509
7051
|
)
|
|
8510
7052
|
);
|
|
8511
7053
|
console.error();
|
|
@@ -8613,11 +7155,11 @@ function buildFrameLines(state, frameIndex) {
|
|
|
8613
7155
|
const bodyWidth = width - 2;
|
|
8614
7156
|
const bodyTextWidth = innerWidth - 2;
|
|
8615
7157
|
const content = [];
|
|
8616
|
-
content.push(
|
|
7158
|
+
content.push(chalk8.bold.cyan("Approval review"));
|
|
8617
7159
|
content.push("");
|
|
8618
7160
|
if (!state.verdict) {
|
|
8619
7161
|
content.push(
|
|
8620
|
-
|
|
7162
|
+
chalk8.yellow(`${SPINNER_FRAMES[frameIndex]} Checking approval...`)
|
|
8621
7163
|
);
|
|
8622
7164
|
}
|
|
8623
7165
|
const recentMessages = state.messages.slice(-5);
|
|
@@ -8628,13 +7170,13 @@ function buildFrameLines(state, frameIndex) {
|
|
|
8628
7170
|
"\n"
|
|
8629
7171
|
);
|
|
8630
7172
|
segments.forEach((segment, segmentIndex) => {
|
|
8631
|
-
const prefix = segmentIndex === 0 ?
|
|
8632
|
-
content.push(`${prefix}${dimmed ?
|
|
7173
|
+
const prefix = segmentIndex === 0 ? chalk8.cyan("> ") : " ";
|
|
7174
|
+
content.push(`${prefix}${dimmed ? chalk8.dim(segment) : segment}`);
|
|
8633
7175
|
});
|
|
8634
7176
|
});
|
|
8635
7177
|
if (state.streamError) {
|
|
8636
7178
|
if (hasMessages || !state.verdict) content.push("");
|
|
8637
|
-
content.push(
|
|
7179
|
+
content.push(chalk8.bold.red("Approval stream error"));
|
|
8638
7180
|
for (const segment of wrapAnsi3(state.streamError, bodyTextWidth, {
|
|
8639
7181
|
hard: true
|
|
8640
7182
|
}).split("\n")) {
|
|
@@ -8644,7 +7186,7 @@ function buildFrameLines(state, frameIndex) {
|
|
|
8644
7186
|
if (state.verdict) {
|
|
8645
7187
|
if (hasMessages || state.streamError) content.push("");
|
|
8646
7188
|
content.push(
|
|
8647
|
-
|
|
7189
|
+
chalk8.bold.green(`${state.verdict.icon} ${state.verdict.label}`)
|
|
8648
7190
|
);
|
|
8649
7191
|
if (state.verdict.reason) {
|
|
8650
7192
|
for (const segment of wrapAnsi3(state.verdict.reason, bodyTextWidth, {
|
|
@@ -8656,12 +7198,12 @@ function buildFrameLines(state, frameIndex) {
|
|
|
8656
7198
|
}
|
|
8657
7199
|
const pad = (line) => {
|
|
8658
7200
|
const padding = " ".repeat(Math.max(0, innerWidth - displayWidth(line)));
|
|
8659
|
-
return `${
|
|
7201
|
+
return `${chalk8.cyan("\u2502")} ${line}${padding} ${chalk8.cyan("\u2502")}`;
|
|
8660
7202
|
};
|
|
8661
7203
|
return [
|
|
8662
|
-
|
|
7204
|
+
chalk8.cyan(`\u256D${"\u2500".repeat(bodyWidth)}\u256E`),
|
|
8663
7205
|
...content.map(pad),
|
|
8664
|
-
|
|
7206
|
+
chalk8.cyan(`\u2570${"\u2500".repeat(bodyWidth)}\u256F`)
|
|
8665
7207
|
];
|
|
8666
7208
|
}
|
|
8667
7209
|
function createApprovalProgressRenderer({
|