@zapier/zapier-sdk-cli 0.6.2 → 0.6.4
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 +17 -0
- package/README.md +115 -12
- package/bin/{zapier-sdk.js → zapier-sdk.mjs} +1 -1
- package/dist/cli.cjs +1711 -0
- package/dist/cli.d.mts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/{cli.js → cli.mjs} +204 -456
- package/dist/index.cjs +770 -0
- package/dist/index.d.mts +12 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.mjs +739 -0
- package/dist/package.json +67 -0
- package/dist/src/cli.js +8 -14
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.js +1 -1
- package/dist/src/plugins/bundleCode/index.d.ts +15 -0
- package/dist/src/{commands/bundle-code → plugins/bundleCode}/index.js +19 -1
- package/dist/src/{commands/bundle-code → plugins/bundleCode}/schemas.d.ts +8 -8
- package/dist/src/{commands/bundle-code → plugins/bundleCode}/schemas.js +4 -4
- package/dist/src/plugins/generateTypes/index.d.ts +21 -0
- package/dist/src/{commands/generate-types → plugins/generateTypes}/index.js +18 -0
- package/dist/src/{commands/generate-types → plugins/generateTypes}/schemas.d.ts +0 -3
- package/dist/src/{commands/generate-types → plugins/generateTypes}/schemas.js +1 -2
- package/dist/src/plugins/getConfigPath/index.d.ts +15 -0
- package/dist/src/plugins/getConfigPath/index.js +19 -0
- package/dist/src/plugins/getConfigPath/schemas.d.ts +3 -0
- package/dist/src/plugins/getConfigPath/schemas.js +5 -0
- package/dist/src/plugins/index.d.ts +6 -0
- package/dist/src/plugins/index.js +6 -0
- package/dist/src/plugins/login/index.d.ts +15 -0
- package/dist/src/plugins/login/index.js +26 -0
- package/dist/src/plugins/login/schemas.d.ts +9 -0
- package/dist/src/plugins/login/schemas.js +10 -0
- package/dist/src/plugins/logout/index.d.ts +15 -0
- package/dist/src/plugins/logout/index.js +18 -0
- package/dist/src/plugins/logout/schemas.d.ts +3 -0
- package/dist/src/plugins/logout/schemas.js +5 -0
- package/dist/src/plugins/mcp/index.d.ts +15 -0
- package/dist/src/plugins/mcp/index.js +24 -0
- package/dist/src/plugins/mcp/schemas.d.ts +9 -0
- package/dist/src/plugins/mcp/schemas.js +10 -0
- package/dist/src/sdk.d.ts +9 -0
- package/dist/src/sdk.js +22 -0
- package/dist/src/utils/cli-generator.js +4 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +19 -8
- package/src/cli.ts +8 -21
- package/src/index.ts +2 -0
- package/src/{commands/bundle-code → plugins/bundleCode}/index.ts +39 -2
- package/src/{commands/bundle-code → plugins/bundleCode}/schemas.ts +4 -4
- package/src/{commands/generate-types → plugins/generateTypes}/index.ts +56 -3
- package/src/{commands/generate-types → plugins/generateTypes}/schemas.ts +0 -4
- package/src/plugins/getConfigPath/index.ts +42 -0
- package/src/plugins/getConfigPath/schemas.ts +8 -0
- package/src/plugins/index.ts +6 -0
- package/src/plugins/login/index.ts +48 -0
- package/src/plugins/login/schemas.ts +13 -0
- package/src/plugins/logout/index.ts +37 -0
- package/src/plugins/logout/schemas.ts +8 -0
- package/src/plugins/mcp/index.ts +43 -0
- package/src/plugins/mcp/schemas.ts +13 -0
- package/src/sdk.ts +43 -0
- package/src/utils/cli-generator.ts +5 -0
- package/tsconfig.build.json +15 -3
- package/tsconfig.json +2 -2
- package/tsup.config.ts +10 -4
- package/bin/zsdk.js +0 -4
- package/dist/index.js +0 -0
- package/dist/src/commands/bundle-code/cli.d.ts +0 -2
- package/dist/src/commands/bundle-code/cli.js +0 -77
- package/dist/src/commands/bundle-code/index.d.ts +0 -5
- package/dist/src/commands/configPath.d.ts +0 -2
- package/dist/src/commands/configPath.js +0 -9
- package/dist/src/commands/generate-types/cli.d.ts +0 -2
- package/dist/src/commands/generate-types/cli.js +0 -84
- package/dist/src/commands/generate-types/index.d.ts +0 -8
- package/dist/src/commands/index.d.ts +0 -6
- package/dist/src/commands/index.js +0 -6
- package/dist/src/commands/login.d.ts +0 -2
- package/dist/src/commands/login.js +0 -25
- package/dist/src/commands/logout.d.ts +0 -2
- package/dist/src/commands/logout.js +0 -16
- package/dist/src/commands/mcp.d.ts +0 -2
- package/dist/src/commands/mcp.js +0 -11
- package/src/commands/bundle-code/cli.ts +0 -118
- package/src/commands/configPath.ts +0 -10
- package/src/commands/generate-types/cli.ts +0 -126
- package/src/commands/index.ts +0 -6
- package/src/commands/login.ts +0 -34
- package/src/commands/logout.ts +0 -19
- package/src/commands/mcp.ts +0 -14
package/dist/cli.cjs
ADDED
|
@@ -0,0 +1,1711 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var commander = require('commander');
|
|
5
|
+
var zod = require('zod');
|
|
6
|
+
var zapierSdk = require('@zapier/zapier-sdk');
|
|
7
|
+
var inquirer = require('inquirer');
|
|
8
|
+
var chalk3 = require('chalk');
|
|
9
|
+
var util = require('util');
|
|
10
|
+
var open = require('open');
|
|
11
|
+
var crypto = require('crypto');
|
|
12
|
+
var express = require('express');
|
|
13
|
+
var pkceChallenge = require('pkce-challenge');
|
|
14
|
+
var ora = require('ora');
|
|
15
|
+
var zapierSdkCliLogin = require('@zapier/zapier-sdk-cli-login');
|
|
16
|
+
var zapierSdkMcp = require('@zapier/zapier-sdk-mcp');
|
|
17
|
+
var fs = require('fs');
|
|
18
|
+
var path = require('path');
|
|
19
|
+
var esbuild = require('esbuild');
|
|
20
|
+
|
|
21
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
22
|
+
|
|
23
|
+
function _interopNamespace(e) {
|
|
24
|
+
if (e && e.__esModule) return e;
|
|
25
|
+
var n = Object.create(null);
|
|
26
|
+
if (e) {
|
|
27
|
+
Object.keys(e).forEach(function (k) {
|
|
28
|
+
if (k !== 'default') {
|
|
29
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
30
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
31
|
+
enumerable: true,
|
|
32
|
+
get: function () { return e[k]; }
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
n.default = e;
|
|
38
|
+
return Object.freeze(n);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
var inquirer__default = /*#__PURE__*/_interopDefault(inquirer);
|
|
42
|
+
var chalk3__default = /*#__PURE__*/_interopDefault(chalk3);
|
|
43
|
+
var util__default = /*#__PURE__*/_interopDefault(util);
|
|
44
|
+
var open__default = /*#__PURE__*/_interopDefault(open);
|
|
45
|
+
var crypto__default = /*#__PURE__*/_interopDefault(crypto);
|
|
46
|
+
var express__default = /*#__PURE__*/_interopDefault(express);
|
|
47
|
+
var pkceChallenge__default = /*#__PURE__*/_interopDefault(pkceChallenge);
|
|
48
|
+
var ora__default = /*#__PURE__*/_interopDefault(ora);
|
|
49
|
+
var fs__namespace = /*#__PURE__*/_interopNamespace(fs);
|
|
50
|
+
var path__namespace = /*#__PURE__*/_interopNamespace(path);
|
|
51
|
+
|
|
52
|
+
var SchemaParameterResolver = class {
|
|
53
|
+
async resolveParameters(schema, providedParams, sdk2) {
|
|
54
|
+
const parseResult = schema.safeParse(providedParams);
|
|
55
|
+
const allParams = this.extractParametersFromSchema(schema);
|
|
56
|
+
const resolvableParams = allParams.filter(
|
|
57
|
+
(param) => zapierSdk.hasResolver(param.name)
|
|
58
|
+
);
|
|
59
|
+
const missingResolvable = resolvableParams.filter((param) => {
|
|
60
|
+
const hasValue = this.getNestedValue(providedParams, param.path) !== void 0;
|
|
61
|
+
return !hasValue;
|
|
62
|
+
});
|
|
63
|
+
const functionallyRequired = missingResolvable.filter((param) => {
|
|
64
|
+
if (param.isRequired) return true;
|
|
65
|
+
if (param.name === "inputs") {
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
return false;
|
|
69
|
+
});
|
|
70
|
+
const alwaysPrompt = missingResolvable.filter((param) => {
|
|
71
|
+
if (functionallyRequired.includes(param)) return false;
|
|
72
|
+
if (param.name === "authenticationId") {
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
return false;
|
|
76
|
+
});
|
|
77
|
+
const trulyOptional = missingResolvable.filter(
|
|
78
|
+
(param) => !functionallyRequired.includes(param) && !alwaysPrompt.includes(param)
|
|
79
|
+
);
|
|
80
|
+
if (parseResult.success && functionallyRequired.length === 0 && alwaysPrompt.length === 0) {
|
|
81
|
+
return parseResult.data;
|
|
82
|
+
}
|
|
83
|
+
if (functionallyRequired.length === 0 && alwaysPrompt.length === 0) {
|
|
84
|
+
if (!parseResult.success) {
|
|
85
|
+
throw parseResult.error;
|
|
86
|
+
}
|
|
87
|
+
return parseResult.data;
|
|
88
|
+
}
|
|
89
|
+
const resolvedParams = { ...providedParams };
|
|
90
|
+
const context = {
|
|
91
|
+
sdk: sdk2,
|
|
92
|
+
currentParams: providedParams,
|
|
93
|
+
resolvedParams
|
|
94
|
+
};
|
|
95
|
+
if (functionallyRequired.length > 0) {
|
|
96
|
+
const requiredParamNames = functionallyRequired.map((p) => p.name);
|
|
97
|
+
const requiredResolutionOrder = zapierSdk.getResolutionOrderForParams(requiredParamNames);
|
|
98
|
+
const orderedRequiredParams = requiredResolutionOrder.map((paramName) => {
|
|
99
|
+
let param = functionallyRequired.find((p) => p.name === paramName);
|
|
100
|
+
if (!param) {
|
|
101
|
+
param = alwaysPrompt.find((p) => p.name === paramName);
|
|
102
|
+
}
|
|
103
|
+
if (!param) {
|
|
104
|
+
param = trulyOptional.find((p) => p.name === paramName);
|
|
105
|
+
}
|
|
106
|
+
return param;
|
|
107
|
+
}).filter((param) => param !== void 0);
|
|
108
|
+
for (const param of orderedRequiredParams) {
|
|
109
|
+
try {
|
|
110
|
+
const value = await this.resolveParameter(param, context);
|
|
111
|
+
this.setNestedValue(resolvedParams, param.path, value);
|
|
112
|
+
context.resolvedParams = resolvedParams;
|
|
113
|
+
} catch (error) {
|
|
114
|
+
if (this.isUserCancellation(error)) {
|
|
115
|
+
console.log(chalk3__default.default.yellow("\n\nOperation cancelled by user"));
|
|
116
|
+
process.exit(0);
|
|
117
|
+
}
|
|
118
|
+
throw error;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
const resolvedParamNames = new Set(
|
|
122
|
+
orderedRequiredParams.map((p) => p.name)
|
|
123
|
+
);
|
|
124
|
+
alwaysPrompt.splice(
|
|
125
|
+
0,
|
|
126
|
+
alwaysPrompt.length,
|
|
127
|
+
...alwaysPrompt.filter((p) => !resolvedParamNames.has(p.name))
|
|
128
|
+
);
|
|
129
|
+
trulyOptional.splice(
|
|
130
|
+
0,
|
|
131
|
+
trulyOptional.length,
|
|
132
|
+
...trulyOptional.filter((p) => !resolvedParamNames.has(p.name))
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
if (alwaysPrompt.length > 0) {
|
|
136
|
+
const alwaysPromptNames = alwaysPrompt.map((p) => p.name);
|
|
137
|
+
const alwaysPromptResolutionOrder = zapierSdk.getResolutionOrderForParams(alwaysPromptNames);
|
|
138
|
+
const orderedAlwaysPromptParams = alwaysPromptResolutionOrder.map((paramName) => alwaysPrompt.find((p) => p.name === paramName)).filter((param) => param !== void 0);
|
|
139
|
+
for (const param of orderedAlwaysPromptParams) {
|
|
140
|
+
try {
|
|
141
|
+
const value = await this.resolveParameter(param, context);
|
|
142
|
+
this.setNestedValue(resolvedParams, param.path, value);
|
|
143
|
+
context.resolvedParams = resolvedParams;
|
|
144
|
+
} catch (error) {
|
|
145
|
+
if (this.isUserCancellation(error)) {
|
|
146
|
+
console.log(chalk3__default.default.yellow("\n\nOperation cancelled by user"));
|
|
147
|
+
process.exit(0);
|
|
148
|
+
}
|
|
149
|
+
throw error;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
if (trulyOptional.length > 0) {
|
|
154
|
+
const optionalNames = trulyOptional.map((p) => p.name).join(", ");
|
|
155
|
+
const shouldResolveOptional = await inquirer__default.default.prompt([
|
|
156
|
+
{
|
|
157
|
+
type: "confirm",
|
|
158
|
+
name: "resolveOptional",
|
|
159
|
+
message: `Would you like to be prompted for optional parameters (${optionalNames})?`,
|
|
160
|
+
default: false
|
|
161
|
+
}
|
|
162
|
+
]);
|
|
163
|
+
if (shouldResolveOptional.resolveOptional) {
|
|
164
|
+
const optionalParamNames = trulyOptional.map((p) => p.name);
|
|
165
|
+
const optionalResolutionOrder = zapierSdk.getResolutionOrderForParams(optionalParamNames);
|
|
166
|
+
const orderedOptionalParams = optionalResolutionOrder.map((paramName) => trulyOptional.find((p) => p.name === paramName)).filter((param) => param !== void 0);
|
|
167
|
+
for (const param of orderedOptionalParams) {
|
|
168
|
+
try {
|
|
169
|
+
const value = await this.resolveParameter(param, context);
|
|
170
|
+
this.setNestedValue(resolvedParams, param.path, value);
|
|
171
|
+
context.resolvedParams = resolvedParams;
|
|
172
|
+
} catch (error) {
|
|
173
|
+
if (this.isUserCancellation(error)) {
|
|
174
|
+
console.log(chalk3__default.default.yellow("\n\nOperation cancelled by user"));
|
|
175
|
+
process.exit(0);
|
|
176
|
+
}
|
|
177
|
+
throw error;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
const finalResult = schema.safeParse(resolvedParams);
|
|
183
|
+
if (!finalResult.success) {
|
|
184
|
+
console.error(
|
|
185
|
+
chalk3__default.default.red("\u274C Parameter validation failed after resolution:")
|
|
186
|
+
);
|
|
187
|
+
throw finalResult.error;
|
|
188
|
+
}
|
|
189
|
+
return finalResult.data;
|
|
190
|
+
}
|
|
191
|
+
extractParametersFromSchema(schema) {
|
|
192
|
+
const parameters = [];
|
|
193
|
+
if (schema instanceof zod.z.ZodObject) {
|
|
194
|
+
const shape = schema.shape;
|
|
195
|
+
for (const [key, fieldSchema] of Object.entries(shape)) {
|
|
196
|
+
const param = this.analyzeFieldSchema(key, fieldSchema);
|
|
197
|
+
if (param) {
|
|
198
|
+
parameters.push(param);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return parameters;
|
|
203
|
+
}
|
|
204
|
+
analyzeFieldSchema(fieldName, fieldSchema) {
|
|
205
|
+
let baseSchema = fieldSchema;
|
|
206
|
+
let isRequired = true;
|
|
207
|
+
if (baseSchema instanceof zod.z.ZodOptional) {
|
|
208
|
+
isRequired = false;
|
|
209
|
+
baseSchema = baseSchema._def.innerType;
|
|
210
|
+
}
|
|
211
|
+
if (baseSchema instanceof zod.z.ZodDefault) {
|
|
212
|
+
isRequired = false;
|
|
213
|
+
baseSchema = baseSchema._def.innerType;
|
|
214
|
+
}
|
|
215
|
+
return this.createResolvableParameter([fieldName], baseSchema, isRequired);
|
|
216
|
+
}
|
|
217
|
+
createResolvableParameter(path3, schema, isRequired) {
|
|
218
|
+
if (path3.length === 0) return null;
|
|
219
|
+
const name = path3[path3.length - 1];
|
|
220
|
+
return {
|
|
221
|
+
name,
|
|
222
|
+
path: path3,
|
|
223
|
+
schema,
|
|
224
|
+
description: schema.description,
|
|
225
|
+
isRequired
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
async resolveParameter(param, context) {
|
|
229
|
+
const resolver = zapierSdk.getResolver(param.name);
|
|
230
|
+
if (!resolver) {
|
|
231
|
+
throw new Error(`No resolver found for parameter: ${param.name}`);
|
|
232
|
+
}
|
|
233
|
+
console.log(chalk3__default.default.blue(`
|
|
234
|
+
\u{1F50D} Resolving ${param.name}...`));
|
|
235
|
+
const typedResolver = resolver;
|
|
236
|
+
if (typedResolver.type === "static") {
|
|
237
|
+
const promptConfig = {
|
|
238
|
+
type: typedResolver.inputType === "password" ? "password" : "input",
|
|
239
|
+
name: param.name,
|
|
240
|
+
message: `Enter ${param.name}:`,
|
|
241
|
+
...typedResolver.placeholder && {
|
|
242
|
+
default: typedResolver.placeholder
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
const answers = await inquirer__default.default.prompt([promptConfig]);
|
|
246
|
+
return answers[param.name];
|
|
247
|
+
} else if (typedResolver.type === "dynamic") {
|
|
248
|
+
try {
|
|
249
|
+
if (param.isRequired && param.name !== "authenticationId") {
|
|
250
|
+
console.log(chalk3__default.default.gray(`Fetching options for ${param.name}...`));
|
|
251
|
+
}
|
|
252
|
+
const items = await typedResolver.fetch(
|
|
253
|
+
context.sdk,
|
|
254
|
+
context.resolvedParams
|
|
255
|
+
);
|
|
256
|
+
const safeItems = items || [];
|
|
257
|
+
const promptConfig = typedResolver.prompt(
|
|
258
|
+
safeItems,
|
|
259
|
+
context.resolvedParams
|
|
260
|
+
);
|
|
261
|
+
const answers = await inquirer__default.default.prompt([promptConfig]);
|
|
262
|
+
return answers[param.name];
|
|
263
|
+
} catch (error) {
|
|
264
|
+
throw error;
|
|
265
|
+
}
|
|
266
|
+
} else if (typedResolver.type === "fields") {
|
|
267
|
+
return await this.resolveFieldsRecursively(
|
|
268
|
+
resolver,
|
|
269
|
+
context,
|
|
270
|
+
param
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
throw new Error(`Unknown resolver type for ${param.name}`);
|
|
274
|
+
}
|
|
275
|
+
async resolveFieldsRecursively(resolver, context, param) {
|
|
276
|
+
const typedResolver = resolver;
|
|
277
|
+
const inputs = {};
|
|
278
|
+
let processedFieldKeys = /* @__PURE__ */ new Set();
|
|
279
|
+
let iteration = 0;
|
|
280
|
+
const maxIterations = 5;
|
|
281
|
+
while (iteration < maxIterations) {
|
|
282
|
+
iteration++;
|
|
283
|
+
const updatedContext = {
|
|
284
|
+
...context,
|
|
285
|
+
resolvedParams: {
|
|
286
|
+
...context.resolvedParams,
|
|
287
|
+
inputs
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
console.log(
|
|
291
|
+
chalk3__default.default.gray(
|
|
292
|
+
`Fetching input fields for ${param.name}${iteration > 1 ? ` (iteration ${iteration})` : ""}...`
|
|
293
|
+
)
|
|
294
|
+
);
|
|
295
|
+
const fields = await typedResolver.fetch(
|
|
296
|
+
updatedContext.sdk,
|
|
297
|
+
updatedContext.resolvedParams
|
|
298
|
+
);
|
|
299
|
+
if (!fields || fields.length === 0) {
|
|
300
|
+
if (iteration === 1) {
|
|
301
|
+
console.log(
|
|
302
|
+
chalk3__default.default.yellow(`No input fields required for this action.`)
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
break;
|
|
306
|
+
}
|
|
307
|
+
const newFields = fields.filter(
|
|
308
|
+
(field) => !(field.key && processedFieldKeys.has(field.key))
|
|
309
|
+
);
|
|
310
|
+
if (newFields.length === 0) {
|
|
311
|
+
break;
|
|
312
|
+
}
|
|
313
|
+
const newRequiredFields = newFields.filter(
|
|
314
|
+
(field) => field.required
|
|
315
|
+
);
|
|
316
|
+
const newOptionalFields = newFields.filter(
|
|
317
|
+
(field) => !field.required
|
|
318
|
+
);
|
|
319
|
+
if (newRequiredFields.length > 0) {
|
|
320
|
+
console.log(
|
|
321
|
+
chalk3__default.default.blue(
|
|
322
|
+
`
|
|
323
|
+
\u{1F4DD} Please provide values for the following ${iteration === 1 ? "" : "additional "}input fields:`
|
|
324
|
+
)
|
|
325
|
+
);
|
|
326
|
+
for (const field of newRequiredFields) {
|
|
327
|
+
await this.promptForField(field, inputs);
|
|
328
|
+
processedFieldKeys.add(field.key);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
let shouldConfigureOptional = { configure: false };
|
|
332
|
+
if (newOptionalFields.length > 0) {
|
|
333
|
+
console.log(
|
|
334
|
+
chalk3__default.default.gray(
|
|
335
|
+
`
|
|
336
|
+
There are ${newOptionalFields.length} ${iteration === 1 ? "" : "additional "}optional field(s) available.`
|
|
337
|
+
)
|
|
338
|
+
);
|
|
339
|
+
try {
|
|
340
|
+
shouldConfigureOptional = await inquirer__default.default.prompt([
|
|
341
|
+
{
|
|
342
|
+
type: "confirm",
|
|
343
|
+
name: "configure",
|
|
344
|
+
message: `Would you like to configure ${iteration === 1 ? "" : "these additional "}optional fields?`,
|
|
345
|
+
default: false
|
|
346
|
+
}
|
|
347
|
+
]);
|
|
348
|
+
} catch (error) {
|
|
349
|
+
if (this.isUserCancellation(error)) {
|
|
350
|
+
console.log(chalk3__default.default.yellow("\n\nOperation cancelled by user"));
|
|
351
|
+
process.exit(0);
|
|
352
|
+
}
|
|
353
|
+
throw error;
|
|
354
|
+
}
|
|
355
|
+
if (shouldConfigureOptional.configure) {
|
|
356
|
+
console.log(chalk3__default.default.cyan(`
|
|
357
|
+
Optional fields:`));
|
|
358
|
+
for (const field of newOptionalFields) {
|
|
359
|
+
await this.promptForField(field, inputs);
|
|
360
|
+
processedFieldKeys.add(field.key);
|
|
361
|
+
}
|
|
362
|
+
} else {
|
|
363
|
+
newOptionalFields.forEach(
|
|
364
|
+
(field) => processedFieldKeys.add(field.key)
|
|
365
|
+
);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
if (newRequiredFields.length === 0 && (!newOptionalFields.length || !shouldConfigureOptional.configure)) {
|
|
369
|
+
break;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
if (iteration >= maxIterations) {
|
|
373
|
+
console.log(
|
|
374
|
+
chalk3__default.default.yellow(
|
|
375
|
+
`
|
|
376
|
+
\u26A0\uFE0F Maximum field resolution iterations reached. Some dynamic fields may not have been discovered.`
|
|
377
|
+
)
|
|
378
|
+
);
|
|
379
|
+
}
|
|
380
|
+
return inputs;
|
|
381
|
+
}
|
|
382
|
+
getNestedValue(obj, path3) {
|
|
383
|
+
return path3.reduce(
|
|
384
|
+
(current, key) => current?.[key],
|
|
385
|
+
obj
|
|
386
|
+
);
|
|
387
|
+
}
|
|
388
|
+
setNestedValue(obj, path3, value) {
|
|
389
|
+
const lastKey = path3[path3.length - 1];
|
|
390
|
+
const parent = path3.slice(0, -1).reduce((current, key) => {
|
|
391
|
+
const currentObj = current;
|
|
392
|
+
if (!(key in currentObj)) {
|
|
393
|
+
currentObj[key] = {};
|
|
394
|
+
}
|
|
395
|
+
return currentObj[key];
|
|
396
|
+
}, obj);
|
|
397
|
+
parent[lastKey] = value;
|
|
398
|
+
}
|
|
399
|
+
async promptForField(field, inputs) {
|
|
400
|
+
const fieldObj = field;
|
|
401
|
+
const fieldPrompt = {
|
|
402
|
+
type: fieldObj.type === "boolean" ? "confirm" : "input",
|
|
403
|
+
name: fieldObj.key,
|
|
404
|
+
message: `${fieldObj.label || fieldObj.key}${fieldObj.required ? " (required)" : " (optional)"}:`
|
|
405
|
+
};
|
|
406
|
+
if (fieldObj.helpText) {
|
|
407
|
+
fieldPrompt.prefix = chalk3__default.default.gray(`\u2139 ${fieldObj.helpText}
|
|
408
|
+
`);
|
|
409
|
+
}
|
|
410
|
+
if (fieldObj.default !== void 0) {
|
|
411
|
+
fieldPrompt.default = fieldObj.default;
|
|
412
|
+
}
|
|
413
|
+
if (fieldObj.choices && fieldObj.choices.length > 0) {
|
|
414
|
+
fieldPrompt.type = "list";
|
|
415
|
+
fieldPrompt.choices = fieldObj.choices.map(
|
|
416
|
+
(choice) => {
|
|
417
|
+
const choiceObj = choice;
|
|
418
|
+
return {
|
|
419
|
+
name: choiceObj.label || choiceObj.value,
|
|
420
|
+
value: choiceObj.value
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
);
|
|
424
|
+
}
|
|
425
|
+
try {
|
|
426
|
+
const answer = await inquirer__default.default.prompt([fieldPrompt]);
|
|
427
|
+
if (answer[fieldObj.key] !== void 0 && answer[fieldObj.key] !== "") {
|
|
428
|
+
inputs[fieldObj.key] = answer[fieldObj.key];
|
|
429
|
+
} else if (fieldObj.required) {
|
|
430
|
+
throw new Error(`Required field ${fieldObj.key} cannot be empty`);
|
|
431
|
+
}
|
|
432
|
+
} catch (error) {
|
|
433
|
+
if (this.isUserCancellation(error)) {
|
|
434
|
+
console.log(chalk3__default.default.yellow("\n\nOperation cancelled by user"));
|
|
435
|
+
process.exit(0);
|
|
436
|
+
}
|
|
437
|
+
throw error;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
isUserCancellation(error) {
|
|
441
|
+
const errorObj = error;
|
|
442
|
+
return errorObj?.name === "ExitPromptError" || errorObj?.message?.includes("User force closed") || errorObj?.isTTYError === true;
|
|
443
|
+
}
|
|
444
|
+
};
|
|
445
|
+
function getFormatMetadata(schema) {
|
|
446
|
+
return schema?._def?.formatMeta;
|
|
447
|
+
}
|
|
448
|
+
function getOutputSchema(schema) {
|
|
449
|
+
return schema?._def?.outputSchema;
|
|
450
|
+
}
|
|
451
|
+
function formatItemsFromSchema(inputSchema, items) {
|
|
452
|
+
const outputSchema = getOutputSchema(inputSchema);
|
|
453
|
+
if (!outputSchema) {
|
|
454
|
+
formatItemsGeneric(items);
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
const formatMeta = getFormatMetadata(outputSchema);
|
|
458
|
+
if (!formatMeta) {
|
|
459
|
+
formatItemsGeneric(items);
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
items.forEach((item, index) => {
|
|
463
|
+
formatSingleItem(item, index, formatMeta);
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
function formatSingleItem(item, index, formatMeta) {
|
|
467
|
+
const formatted = formatMeta.format(item);
|
|
468
|
+
let titleLine = `${chalk3__default.default.gray(`${index + 1}.`)} ${chalk3__default.default.cyan(formatted.title)}`;
|
|
469
|
+
if (formatted.subtitle) {
|
|
470
|
+
titleLine += ` ${chalk3__default.default.gray(formatted.subtitle)}`;
|
|
471
|
+
}
|
|
472
|
+
console.log(titleLine);
|
|
473
|
+
for (const detail of formatted.details) {
|
|
474
|
+
const styledText = applyStyle(detail.text, detail.style);
|
|
475
|
+
console.log(` ${styledText}`);
|
|
476
|
+
}
|
|
477
|
+
console.log();
|
|
478
|
+
}
|
|
479
|
+
function applyStyle(value, style) {
|
|
480
|
+
switch (style) {
|
|
481
|
+
case "dim":
|
|
482
|
+
return chalk3__default.default.dim(value);
|
|
483
|
+
case "accent":
|
|
484
|
+
return chalk3__default.default.magenta(value);
|
|
485
|
+
case "warning":
|
|
486
|
+
return chalk3__default.default.red(value);
|
|
487
|
+
case "success":
|
|
488
|
+
return chalk3__default.default.green(value);
|
|
489
|
+
case "normal":
|
|
490
|
+
default:
|
|
491
|
+
return chalk3__default.default.blue(value);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
function formatItemsGeneric(items) {
|
|
495
|
+
items.forEach((item, index) => {
|
|
496
|
+
const itemObj = item;
|
|
497
|
+
const name = itemObj.title || itemObj.name || itemObj.key || itemObj.id || "Item";
|
|
498
|
+
console.log(`${chalk3__default.default.gray(`${index + 1}.`)} ${chalk3__default.default.cyan(name)}`);
|
|
499
|
+
if (itemObj.description) {
|
|
500
|
+
console.log(` ${chalk3__default.default.dim(itemObj.description)}`);
|
|
501
|
+
}
|
|
502
|
+
console.log();
|
|
503
|
+
});
|
|
504
|
+
}
|
|
505
|
+
function formatJsonOutput(data) {
|
|
506
|
+
if (data === void 0) {
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
509
|
+
if (data && typeof data === "object" && !Array.isArray(data) && (data.success !== void 0 || data.id || data.status)) {
|
|
510
|
+
console.log(chalk3__default.default.green("\u2705 Action completed successfully!\n"));
|
|
511
|
+
}
|
|
512
|
+
console.log(
|
|
513
|
+
util__default.default.inspect(data, { colors: true, depth: null, breakLength: 80 })
|
|
514
|
+
);
|
|
515
|
+
}
|
|
516
|
+
function analyzeZodSchema(schema) {
|
|
517
|
+
const parameters = [];
|
|
518
|
+
if (schema instanceof zod.z.ZodObject) {
|
|
519
|
+
const shape = schema.shape;
|
|
520
|
+
for (const [key, fieldSchema] of Object.entries(shape)) {
|
|
521
|
+
const param = analyzeZodField(key, fieldSchema);
|
|
522
|
+
if (param) {
|
|
523
|
+
parameters.push(param);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
return parameters;
|
|
528
|
+
}
|
|
529
|
+
function analyzeZodField(name, schema) {
|
|
530
|
+
let baseSchema = schema;
|
|
531
|
+
let required = true;
|
|
532
|
+
let defaultValue = void 0;
|
|
533
|
+
if (baseSchema instanceof zod.z.ZodOptional) {
|
|
534
|
+
required = false;
|
|
535
|
+
baseSchema = baseSchema._def.innerType;
|
|
536
|
+
}
|
|
537
|
+
if (baseSchema instanceof zod.z.ZodDefault) {
|
|
538
|
+
required = false;
|
|
539
|
+
defaultValue = baseSchema._def.defaultValue();
|
|
540
|
+
baseSchema = baseSchema._def.innerType;
|
|
541
|
+
}
|
|
542
|
+
let paramType = "string";
|
|
543
|
+
let choices;
|
|
544
|
+
if (baseSchema instanceof zod.z.ZodString) {
|
|
545
|
+
paramType = "string";
|
|
546
|
+
} else if (baseSchema instanceof zod.z.ZodNumber) {
|
|
547
|
+
paramType = "number";
|
|
548
|
+
} else if (baseSchema instanceof zod.z.ZodBoolean) {
|
|
549
|
+
paramType = "boolean";
|
|
550
|
+
} else if (baseSchema instanceof zod.z.ZodArray) {
|
|
551
|
+
paramType = "array";
|
|
552
|
+
} else if (baseSchema instanceof zod.z.ZodEnum) {
|
|
553
|
+
paramType = "string";
|
|
554
|
+
choices = baseSchema._def.values;
|
|
555
|
+
} else if (baseSchema instanceof zod.z.ZodRecord) {
|
|
556
|
+
paramType = "string";
|
|
557
|
+
}
|
|
558
|
+
return {
|
|
559
|
+
name,
|
|
560
|
+
type: paramType,
|
|
561
|
+
required,
|
|
562
|
+
description: schema.description,
|
|
563
|
+
default: defaultValue,
|
|
564
|
+
choices,
|
|
565
|
+
hasResolver: zapierSdk.hasResolver(name),
|
|
566
|
+
isPositional: zapierSdk.isPositional(schema)
|
|
567
|
+
};
|
|
568
|
+
}
|
|
569
|
+
function toKebabCase(str) {
|
|
570
|
+
return str.replace(/([A-Z])/g, "-$1").toLowerCase();
|
|
571
|
+
}
|
|
572
|
+
function methodNameToCliCommand(methodName) {
|
|
573
|
+
return toKebabCase(methodName);
|
|
574
|
+
}
|
|
575
|
+
function generateCliCommands(program2, sdk2) {
|
|
576
|
+
if (typeof sdk2.getRegistry !== "function") {
|
|
577
|
+
console.error("SDK registry not available");
|
|
578
|
+
return;
|
|
579
|
+
}
|
|
580
|
+
const registry = sdk2.getRegistry();
|
|
581
|
+
registry.functions.forEach((fnInfo) => {
|
|
582
|
+
if (!fnInfo.inputSchema) {
|
|
583
|
+
console.warn(`Schema not found for ${fnInfo.name}`);
|
|
584
|
+
return;
|
|
585
|
+
}
|
|
586
|
+
const cliCommandName = methodNameToCliCommand(fnInfo.name);
|
|
587
|
+
const config = createCommandConfig(
|
|
588
|
+
cliCommandName,
|
|
589
|
+
fnInfo.name,
|
|
590
|
+
fnInfo.inputSchema,
|
|
591
|
+
sdk2
|
|
592
|
+
);
|
|
593
|
+
addCommand(program2, cliCommandName, config);
|
|
594
|
+
});
|
|
595
|
+
program2.configureHelp({
|
|
596
|
+
formatHelp: (cmd, helper) => {
|
|
597
|
+
const helpWidth = helper.helpWidth || 80;
|
|
598
|
+
let output = helper.commandUsage(cmd) + "\n";
|
|
599
|
+
if (cmd.description()) {
|
|
600
|
+
output += helper.wrap(cmd.description(), helpWidth, 0) + "\n";
|
|
601
|
+
}
|
|
602
|
+
const options = helper.visibleOptions(cmd);
|
|
603
|
+
if (options.length > 0) {
|
|
604
|
+
output += "\nOptions:\n";
|
|
605
|
+
const longestOptionLength = Math.max(
|
|
606
|
+
...options.map((opt) => helper.optionTerm(opt).length)
|
|
607
|
+
);
|
|
608
|
+
options.forEach((option) => {
|
|
609
|
+
const term = helper.optionTerm(option);
|
|
610
|
+
const padding = " ".repeat(
|
|
611
|
+
Math.max(2, longestOptionLength - term.length + 4)
|
|
612
|
+
);
|
|
613
|
+
output += ` ${term}${padding}${helper.optionDescription(option)}
|
|
614
|
+
`;
|
|
615
|
+
});
|
|
616
|
+
}
|
|
617
|
+
const commands = helper.visibleCommands(cmd);
|
|
618
|
+
if (commands.length > 0) {
|
|
619
|
+
output += "\nCommands:\n";
|
|
620
|
+
const categorizedCommands = /* @__PURE__ */ new Set();
|
|
621
|
+
registry.categories.forEach((category) => {
|
|
622
|
+
const categoryCommands = commands.filter(
|
|
623
|
+
(command) => category.functions.some((functionName) => {
|
|
624
|
+
const cliCommandName = methodNameToCliCommand(functionName);
|
|
625
|
+
return command.name() === cliCommandName;
|
|
626
|
+
})
|
|
627
|
+
);
|
|
628
|
+
if (categoryCommands.length > 0) {
|
|
629
|
+
output += `
|
|
630
|
+
${category.titlePlural}:
|
|
631
|
+
`;
|
|
632
|
+
categoryCommands.forEach((command) => {
|
|
633
|
+
output += ` ${helper.subcommandTerm(command)}
|
|
634
|
+
`;
|
|
635
|
+
categorizedCommands.add(command.name());
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
});
|
|
639
|
+
const otherCommands = commands.filter(
|
|
640
|
+
(command) => !categorizedCommands.has(command.name())
|
|
641
|
+
);
|
|
642
|
+
if (otherCommands.length > 0) {
|
|
643
|
+
output += `
|
|
644
|
+
Other:
|
|
645
|
+
`;
|
|
646
|
+
otherCommands.forEach((command) => {
|
|
647
|
+
output += ` ${helper.subcommandTerm(command)}
|
|
648
|
+
`;
|
|
649
|
+
});
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
return output;
|
|
653
|
+
}
|
|
654
|
+
});
|
|
655
|
+
}
|
|
656
|
+
function createCommandConfig(cliCommandName, sdkMethodName, schema, sdk2) {
|
|
657
|
+
const parameters = analyzeZodSchema(schema);
|
|
658
|
+
const description = schema.description || `${cliCommandName} command`;
|
|
659
|
+
const handler = async (...args) => {
|
|
660
|
+
try {
|
|
661
|
+
const commandObj = args[args.length - 1];
|
|
662
|
+
const options = commandObj.opts();
|
|
663
|
+
const isListCommand = cliCommandName.startsWith("list-");
|
|
664
|
+
const hasPaginationParams = parameters.some(
|
|
665
|
+
(p) => p.name === "maxItems" || p.name === "pageSize"
|
|
666
|
+
);
|
|
667
|
+
const hasUserSpecifiedMaxItems = "maxItems" in options && options.maxItems !== void 0;
|
|
668
|
+
const shouldUseJson = options.json;
|
|
669
|
+
const rawParams = convertCliArgsToSdkParams(
|
|
670
|
+
parameters,
|
|
671
|
+
args.slice(0, -1),
|
|
672
|
+
options
|
|
673
|
+
);
|
|
674
|
+
const resolver = new SchemaParameterResolver();
|
|
675
|
+
const resolvedParams = await resolver.resolveParameters(
|
|
676
|
+
schema,
|
|
677
|
+
rawParams,
|
|
678
|
+
sdk2
|
|
679
|
+
);
|
|
680
|
+
if (isListCommand && hasPaginationParams && !shouldUseJson && !hasUserSpecifiedMaxItems) {
|
|
681
|
+
const sdkObj = sdk2;
|
|
682
|
+
const sdkIterator = await sdkObj[sdkMethodName](resolvedParams);
|
|
683
|
+
await handlePaginatedListWithAsyncIteration(
|
|
684
|
+
sdkMethodName,
|
|
685
|
+
sdkIterator,
|
|
686
|
+
schema
|
|
687
|
+
);
|
|
688
|
+
} else {
|
|
689
|
+
const hasOutputFile = resolvedParams.output;
|
|
690
|
+
if (hasOutputFile) {
|
|
691
|
+
const sdkObj2 = sdk2;
|
|
692
|
+
await sdkObj2[sdkMethodName](resolvedParams);
|
|
693
|
+
console.log(
|
|
694
|
+
chalk3__default.default.green(`\u2705 ${cliCommandName} completed successfully!`)
|
|
695
|
+
);
|
|
696
|
+
console.log(chalk3__default.default.gray(`Output written to: ${hasOutputFile}`));
|
|
697
|
+
return;
|
|
698
|
+
}
|
|
699
|
+
const sdkObj = sdk2;
|
|
700
|
+
const result = await sdkObj[sdkMethodName](resolvedParams);
|
|
701
|
+
const items = result?.data ? result.data : result;
|
|
702
|
+
if (shouldUseJson) {
|
|
703
|
+
console.log(JSON.stringify(items, null, 2));
|
|
704
|
+
} else if (isListCommand) {
|
|
705
|
+
formatNonPaginatedResults(
|
|
706
|
+
items,
|
|
707
|
+
resolvedParams.maxItems,
|
|
708
|
+
hasUserSpecifiedMaxItems,
|
|
709
|
+
shouldUseJson,
|
|
710
|
+
schema,
|
|
711
|
+
sdkMethodName
|
|
712
|
+
);
|
|
713
|
+
} else {
|
|
714
|
+
formatJsonOutput(items);
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
} catch (error) {
|
|
718
|
+
if (error instanceof Error && error.message.includes('"code"')) {
|
|
719
|
+
try {
|
|
720
|
+
const validationErrors = JSON.parse(error.message);
|
|
721
|
+
console.error(chalk3__default.default.red("\u274C Validation Error:"));
|
|
722
|
+
validationErrors.forEach((err) => {
|
|
723
|
+
const errorObj = err;
|
|
724
|
+
const field = errorObj?.path?.join(".") || "unknown";
|
|
725
|
+
console.error(
|
|
726
|
+
chalk3__default.default.yellow(
|
|
727
|
+
` \u2022 ${field}: ${errorObj?.message || "Unknown error"}`
|
|
728
|
+
)
|
|
729
|
+
);
|
|
730
|
+
});
|
|
731
|
+
console.error(
|
|
732
|
+
"\n" + chalk3__default.default.dim(`Use --help to see available options`)
|
|
733
|
+
);
|
|
734
|
+
} catch {
|
|
735
|
+
console.error(chalk3__default.default.red("Error:"), error.message);
|
|
736
|
+
}
|
|
737
|
+
} else if (error instanceof zapierSdk.ZapierError) {
|
|
738
|
+
const formattedMessage = zapierSdk.formatErrorMessage(error);
|
|
739
|
+
console.error(chalk3__default.default.red("\u274C Error:"), formattedMessage);
|
|
740
|
+
} else {
|
|
741
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
742
|
+
console.error(chalk3__default.default.red("\u274C Error:"), errorMessage);
|
|
743
|
+
}
|
|
744
|
+
process.exit(1);
|
|
745
|
+
}
|
|
746
|
+
};
|
|
747
|
+
return {
|
|
748
|
+
description,
|
|
749
|
+
parameters,
|
|
750
|
+
handler
|
|
751
|
+
};
|
|
752
|
+
}
|
|
753
|
+
function addCommand(program2, commandName, config) {
|
|
754
|
+
const command = program2.command(commandName).description(config.description);
|
|
755
|
+
config.parameters.forEach((param) => {
|
|
756
|
+
const kebabName = param.name.replace(/([A-Z])/g, "-$1").toLowerCase();
|
|
757
|
+
if (param.hasResolver && param.required) {
|
|
758
|
+
command.argument(
|
|
759
|
+
`[${kebabName}]`,
|
|
760
|
+
param.description || `${kebabName} parameter`
|
|
761
|
+
);
|
|
762
|
+
} else if (param.required) {
|
|
763
|
+
command.argument(
|
|
764
|
+
`<${kebabName}>`,
|
|
765
|
+
param.description || `${kebabName} parameter`
|
|
766
|
+
);
|
|
767
|
+
} else if (param.isPositional) {
|
|
768
|
+
command.argument(
|
|
769
|
+
`[${kebabName}]`,
|
|
770
|
+
param.description || `${kebabName} parameter`
|
|
771
|
+
);
|
|
772
|
+
} else {
|
|
773
|
+
const flags = [`--${kebabName}`];
|
|
774
|
+
if (param.type === "boolean") {
|
|
775
|
+
command.option(flags.join(", "), param.description);
|
|
776
|
+
} else if (param.type === "array") {
|
|
777
|
+
const flagSignature = flags.join(", ") + ` <values...>`;
|
|
778
|
+
command.option(
|
|
779
|
+
flagSignature,
|
|
780
|
+
param.description,
|
|
781
|
+
param.default
|
|
782
|
+
);
|
|
783
|
+
} else {
|
|
784
|
+
const flagSignature = flags.join(", ") + ` <${param.type}>`;
|
|
785
|
+
command.option(
|
|
786
|
+
flagSignature,
|
|
787
|
+
param.description || "",
|
|
788
|
+
param.default
|
|
789
|
+
);
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
});
|
|
793
|
+
command.option("--json", "Output raw JSON instead of formatted results");
|
|
794
|
+
command.action(config.handler);
|
|
795
|
+
}
|
|
796
|
+
function convertCliArgsToSdkParams(parameters, positionalArgs, options) {
|
|
797
|
+
const sdkParams = {};
|
|
798
|
+
let argIndex = 0;
|
|
799
|
+
parameters.forEach((param) => {
|
|
800
|
+
if ((param.required || param.isPositional) && argIndex < positionalArgs.length) {
|
|
801
|
+
sdkParams[param.name] = convertValue(
|
|
802
|
+
positionalArgs[argIndex],
|
|
803
|
+
param.type
|
|
804
|
+
);
|
|
805
|
+
argIndex++;
|
|
806
|
+
}
|
|
807
|
+
});
|
|
808
|
+
Object.entries(options).forEach(([key, value]) => {
|
|
809
|
+
const camelKey = key.replace(/-([a-z])/g, (g) => g[1].toUpperCase());
|
|
810
|
+
const param = parameters.find((p) => p.name === camelKey);
|
|
811
|
+
if (param && value !== void 0) {
|
|
812
|
+
sdkParams[camelKey] = convertValue(value, param.type);
|
|
813
|
+
}
|
|
814
|
+
});
|
|
815
|
+
return sdkParams;
|
|
816
|
+
}
|
|
817
|
+
function convertValue(value, type) {
|
|
818
|
+
switch (type) {
|
|
819
|
+
case "number":
|
|
820
|
+
return Number(value);
|
|
821
|
+
case "boolean":
|
|
822
|
+
return Boolean(value);
|
|
823
|
+
case "array":
|
|
824
|
+
return Array.isArray(value) ? value : [value];
|
|
825
|
+
case "string":
|
|
826
|
+
default:
|
|
827
|
+
if (typeof value === "string" && (value.startsWith("{") || value.startsWith("["))) {
|
|
828
|
+
try {
|
|
829
|
+
return JSON.parse(value);
|
|
830
|
+
} catch {
|
|
831
|
+
return value;
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
return value;
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
async function handlePaginatedListWithAsyncIteration(sdkMethodName, sdkResult, schema) {
|
|
838
|
+
const itemName = getItemNameFromMethod(sdkMethodName);
|
|
839
|
+
let totalShown = 0;
|
|
840
|
+
let pageCount = 0;
|
|
841
|
+
console.log(chalk3__default.default.blue(`\u{1F4CB} ${getListTitleFromMethod(sdkMethodName)}
|
|
842
|
+
`));
|
|
843
|
+
try {
|
|
844
|
+
for await (const page of sdkResult) {
|
|
845
|
+
const items = page.data || page;
|
|
846
|
+
pageCount++;
|
|
847
|
+
if (!Array.isArray(items)) {
|
|
848
|
+
console.log(chalk3__default.default.yellow(`No ${itemName} found.`));
|
|
849
|
+
return;
|
|
850
|
+
}
|
|
851
|
+
if (items.length === 0 && pageCount === 1) {
|
|
852
|
+
console.log(chalk3__default.default.yellow(`No ${itemName} found.`));
|
|
853
|
+
return;
|
|
854
|
+
}
|
|
855
|
+
if (items.length === 0) {
|
|
856
|
+
break;
|
|
857
|
+
}
|
|
858
|
+
if (pageCount > 1) {
|
|
859
|
+
console.clear();
|
|
860
|
+
console.log(
|
|
861
|
+
chalk3__default.default.blue(`\u{1F4CB} ${getListTitleFromMethod(sdkMethodName)}
|
|
862
|
+
`)
|
|
863
|
+
);
|
|
864
|
+
}
|
|
865
|
+
if (schema) {
|
|
866
|
+
formatItemsFromSchema(schema, items);
|
|
867
|
+
} else {
|
|
868
|
+
formatItemsGeneric2(items);
|
|
869
|
+
}
|
|
870
|
+
totalShown += items.length;
|
|
871
|
+
console.log(
|
|
872
|
+
chalk3__default.default.green(
|
|
873
|
+
`
|
|
874
|
+
\u2705 Showing ${totalShown} ${itemName} (page ${pageCount})`
|
|
875
|
+
)
|
|
876
|
+
);
|
|
877
|
+
if (page.nextCursor) {
|
|
878
|
+
const { continueReading } = await inquirer__default.default.prompt([
|
|
879
|
+
{
|
|
880
|
+
type: "confirm",
|
|
881
|
+
name: "continueReading",
|
|
882
|
+
message: `Load next page?`,
|
|
883
|
+
default: true
|
|
884
|
+
}
|
|
885
|
+
]);
|
|
886
|
+
if (!continueReading) {
|
|
887
|
+
break;
|
|
888
|
+
}
|
|
889
|
+
} else {
|
|
890
|
+
break;
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
console.log(chalk3__default.default.gray(`
|
|
894
|
+
\u{1F4C4} Finished browsing ${itemName}`));
|
|
895
|
+
} catch (error) {
|
|
896
|
+
const items = sdkResult?.data || sdkResult;
|
|
897
|
+
if (Array.isArray(items)) {
|
|
898
|
+
if (items.length === 0) {
|
|
899
|
+
console.log(chalk3__default.default.yellow(`No ${itemName} found.`));
|
|
900
|
+
return;
|
|
901
|
+
}
|
|
902
|
+
if (schema) {
|
|
903
|
+
formatItemsFromSchema(schema, items);
|
|
904
|
+
} else {
|
|
905
|
+
formatItemsGeneric2(items);
|
|
906
|
+
}
|
|
907
|
+
console.log(chalk3__default.default.green(`
|
|
908
|
+
\u2705 Showing ${items.length} ${itemName}`));
|
|
909
|
+
} else {
|
|
910
|
+
throw error;
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
function formatNonPaginatedResults(result, requestedMaxItems, userSpecifiedMaxItems, useRawJson, schema, methodName) {
|
|
915
|
+
if (!Array.isArray(result)) {
|
|
916
|
+
if (useRawJson) {
|
|
917
|
+
console.log(JSON.stringify(result, null, 2));
|
|
918
|
+
} else {
|
|
919
|
+
formatJsonOutput(result);
|
|
920
|
+
}
|
|
921
|
+
return;
|
|
922
|
+
}
|
|
923
|
+
if (useRawJson) {
|
|
924
|
+
console.log(JSON.stringify(result, null, 2));
|
|
925
|
+
return;
|
|
926
|
+
}
|
|
927
|
+
const itemName = methodName ? getItemNameFromMethod(methodName) : "items";
|
|
928
|
+
if (result.length === 0) {
|
|
929
|
+
console.log(chalk3__default.default.yellow(`No ${itemName} found.`));
|
|
930
|
+
return;
|
|
931
|
+
}
|
|
932
|
+
console.log(chalk3__default.default.green(`
|
|
933
|
+
\u2705 Found ${result.length} ${itemName}:
|
|
934
|
+
`));
|
|
935
|
+
if (schema) {
|
|
936
|
+
formatItemsFromSchema(schema, result);
|
|
937
|
+
} else {
|
|
938
|
+
formatItemsGeneric2(result);
|
|
939
|
+
}
|
|
940
|
+
if (userSpecifiedMaxItems && requestedMaxItems) {
|
|
941
|
+
console.log(
|
|
942
|
+
chalk3__default.default.gray(
|
|
943
|
+
`
|
|
944
|
+
\u{1F4C4} Showing up to ${requestedMaxItems} ${itemName} (--max-items ${requestedMaxItems})`
|
|
945
|
+
)
|
|
946
|
+
);
|
|
947
|
+
} else {
|
|
948
|
+
console.log(chalk3__default.default.gray(`
|
|
949
|
+
\u{1F4C4} All available ${itemName} shown`));
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
function formatItemsGeneric2(items) {
|
|
953
|
+
items.forEach((item, index) => {
|
|
954
|
+
const itemObj = item;
|
|
955
|
+
const name = itemObj?.name || itemObj?.key || itemObj?.id || "Item";
|
|
956
|
+
console.log(`${chalk3__default.default.gray(`${index + 1}.`)} ${chalk3__default.default.cyan(String(name))}`);
|
|
957
|
+
if (itemObj?.description) {
|
|
958
|
+
console.log(` ${chalk3__default.default.dim(String(itemObj.description))}`);
|
|
959
|
+
}
|
|
960
|
+
console.log();
|
|
961
|
+
});
|
|
962
|
+
}
|
|
963
|
+
function getItemNameFromMethod(methodName) {
|
|
964
|
+
const listMatch = methodName.match(/^list(.+)$/);
|
|
965
|
+
if (listMatch) {
|
|
966
|
+
return listMatch[1].toLowerCase();
|
|
967
|
+
}
|
|
968
|
+
return "items";
|
|
969
|
+
}
|
|
970
|
+
function getListTitleFromMethod(methodName) {
|
|
971
|
+
const itemName = getItemNameFromMethod(methodName);
|
|
972
|
+
if (itemName === "items") return "Available Items";
|
|
973
|
+
const capitalized = itemName.charAt(0).toUpperCase() + itemName.slice(1);
|
|
974
|
+
return `Available ${capitalized}`;
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
// src/utils/constants.ts
|
|
978
|
+
var ZAPIER_BASE = "https://zapier.com";
|
|
979
|
+
var LOGIN_CLIENT_ID = "K5eEnRE9TTmSFATdkkWhKF8NOKwoiOnYAyIqJjae";
|
|
980
|
+
var LOGIN_PORTS = [49505, 50575, 52804, 55981, 61010, 63851];
|
|
981
|
+
var LOGIN_TIMEOUT_MS = 3e5;
|
|
982
|
+
var AUTH_MODE_HEADER = "X-Auth";
|
|
983
|
+
var spinPromise = async (promise, text) => {
|
|
984
|
+
const spinner = ora__default.default(text).start();
|
|
985
|
+
try {
|
|
986
|
+
const result = await promise;
|
|
987
|
+
spinner.succeed();
|
|
988
|
+
return result;
|
|
989
|
+
} catch (error) {
|
|
990
|
+
spinner.fail();
|
|
991
|
+
throw error;
|
|
992
|
+
}
|
|
993
|
+
};
|
|
994
|
+
var log = {
|
|
995
|
+
info: (message, ...args) => {
|
|
996
|
+
console.log(chalk3__default.default.blue("\u2139"), message, ...args);
|
|
997
|
+
},
|
|
998
|
+
error: (message, ...args) => {
|
|
999
|
+
console.error(chalk3__default.default.red("\u2716"), message, ...args);
|
|
1000
|
+
},
|
|
1001
|
+
success: (message, ...args) => {
|
|
1002
|
+
console.log(chalk3__default.default.green("\u2713"), message, ...args);
|
|
1003
|
+
},
|
|
1004
|
+
warn: (message, ...args) => {
|
|
1005
|
+
console.log(chalk3__default.default.yellow("\u26A0"), message, ...args);
|
|
1006
|
+
}
|
|
1007
|
+
};
|
|
1008
|
+
var log_default = log;
|
|
1009
|
+
|
|
1010
|
+
// src/utils/api/client.ts
|
|
1011
|
+
var createApiClient = () => {
|
|
1012
|
+
const post = async (url, data, options = {}) => {
|
|
1013
|
+
const { headers = {} } = options;
|
|
1014
|
+
const response = await fetch(url, {
|
|
1015
|
+
method: "POST",
|
|
1016
|
+
headers: {
|
|
1017
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
1018
|
+
Connection: "close",
|
|
1019
|
+
...headers
|
|
1020
|
+
},
|
|
1021
|
+
body: new URLSearchParams(data)
|
|
1022
|
+
});
|
|
1023
|
+
if (!response.ok) {
|
|
1024
|
+
throw new Error(`${response.status} ${response.statusText}`);
|
|
1025
|
+
}
|
|
1026
|
+
const responseData = await response.json();
|
|
1027
|
+
return {
|
|
1028
|
+
data: responseData,
|
|
1029
|
+
status: response.status
|
|
1030
|
+
};
|
|
1031
|
+
};
|
|
1032
|
+
return {
|
|
1033
|
+
post
|
|
1034
|
+
};
|
|
1035
|
+
};
|
|
1036
|
+
var api = createApiClient();
|
|
1037
|
+
var client_default = api;
|
|
1038
|
+
|
|
1039
|
+
// src/utils/getCallablePromise.ts
|
|
1040
|
+
var getCallablePromise = () => {
|
|
1041
|
+
let resolve2 = () => {
|
|
1042
|
+
};
|
|
1043
|
+
let reject = () => {
|
|
1044
|
+
};
|
|
1045
|
+
const promise = new Promise((_resolve, _reject) => {
|
|
1046
|
+
resolve2 = _resolve;
|
|
1047
|
+
reject = _reject;
|
|
1048
|
+
});
|
|
1049
|
+
return {
|
|
1050
|
+
promise,
|
|
1051
|
+
resolve: resolve2,
|
|
1052
|
+
reject
|
|
1053
|
+
};
|
|
1054
|
+
};
|
|
1055
|
+
var getCallablePromise_default = getCallablePromise;
|
|
1056
|
+
var findAvailablePort = () => {
|
|
1057
|
+
return new Promise((resolve2, reject) => {
|
|
1058
|
+
let portIndex = 0;
|
|
1059
|
+
const tryPort = (port) => {
|
|
1060
|
+
const server = express__default.default().listen(port, () => {
|
|
1061
|
+
server.close();
|
|
1062
|
+
resolve2(port);
|
|
1063
|
+
});
|
|
1064
|
+
server.on("error", (err) => {
|
|
1065
|
+
if (err.code === "EADDRINUSE") {
|
|
1066
|
+
if (portIndex < LOGIN_PORTS.length) {
|
|
1067
|
+
tryPort(LOGIN_PORTS[portIndex++]);
|
|
1068
|
+
} else {
|
|
1069
|
+
reject(
|
|
1070
|
+
new Error(
|
|
1071
|
+
`All configured OAuth callback ports are busy: ${LOGIN_PORTS.join(", ")}. Please try again later or close applications using these ports.`
|
|
1072
|
+
)
|
|
1073
|
+
);
|
|
1074
|
+
}
|
|
1075
|
+
} else {
|
|
1076
|
+
reject(err);
|
|
1077
|
+
}
|
|
1078
|
+
});
|
|
1079
|
+
};
|
|
1080
|
+
if (LOGIN_PORTS.length > 0) {
|
|
1081
|
+
tryPort(LOGIN_PORTS[portIndex++]);
|
|
1082
|
+
} else {
|
|
1083
|
+
reject(new Error("No OAuth callback ports configured"));
|
|
1084
|
+
}
|
|
1085
|
+
});
|
|
1086
|
+
};
|
|
1087
|
+
var generateRandomString = () => {
|
|
1088
|
+
const array = new Uint32Array(28);
|
|
1089
|
+
crypto__default.default.getRandomValues(array);
|
|
1090
|
+
return Array.from(
|
|
1091
|
+
array,
|
|
1092
|
+
(dec) => ("0" + dec.toString(16)).substring(-2)
|
|
1093
|
+
).join("");
|
|
1094
|
+
};
|
|
1095
|
+
var login = async (timeoutMs = LOGIN_TIMEOUT_MS) => {
|
|
1096
|
+
zapierSdkCliLogin.logout();
|
|
1097
|
+
const availablePort = await findAvailablePort();
|
|
1098
|
+
const redirectUri = `http://localhost:${availablePort}/oauth`;
|
|
1099
|
+
log_default.info(`Using port ${availablePort} for OAuth callback`);
|
|
1100
|
+
const { promise: promisedCode, resolve: setCode } = getCallablePromise_default();
|
|
1101
|
+
const app = express__default.default();
|
|
1102
|
+
app.get("/oauth", (req, res) => {
|
|
1103
|
+
setCode(String(req.query.code));
|
|
1104
|
+
res.setHeader("Connection", "close");
|
|
1105
|
+
res.end("You can now close this tab and return to the CLI.");
|
|
1106
|
+
});
|
|
1107
|
+
const server = app.listen(availablePort);
|
|
1108
|
+
const connections = /* @__PURE__ */ new Set();
|
|
1109
|
+
server.on("connection", (conn) => {
|
|
1110
|
+
connections.add(conn);
|
|
1111
|
+
conn.on("close", () => connections.delete(conn));
|
|
1112
|
+
});
|
|
1113
|
+
const cleanup = () => {
|
|
1114
|
+
server.close();
|
|
1115
|
+
log_default.info("\n\u274C Login cancelled by user");
|
|
1116
|
+
process.exit(0);
|
|
1117
|
+
};
|
|
1118
|
+
process.on("SIGINT", cleanup);
|
|
1119
|
+
process.on("SIGTERM", cleanup);
|
|
1120
|
+
const { code_verifier: codeVerifier, code_challenge: codeChallenge } = await pkceChallenge__default.default();
|
|
1121
|
+
const authUrl = `${ZAPIER_BASE}/oauth/authorize/?${new URLSearchParams({
|
|
1122
|
+
response_type: "code",
|
|
1123
|
+
client_id: LOGIN_CLIENT_ID,
|
|
1124
|
+
redirect_uri: redirectUri,
|
|
1125
|
+
scope: "internal offline_access",
|
|
1126
|
+
state: generateRandomString(),
|
|
1127
|
+
code_challenge: codeChallenge,
|
|
1128
|
+
code_challenge_method: "S256"
|
|
1129
|
+
}).toString()}`;
|
|
1130
|
+
log_default.info("Opening your browser to log in.");
|
|
1131
|
+
log_default.info("If it doesn't open, visit:", authUrl);
|
|
1132
|
+
open__default.default(authUrl);
|
|
1133
|
+
try {
|
|
1134
|
+
await spinPromise(
|
|
1135
|
+
Promise.race([
|
|
1136
|
+
promisedCode,
|
|
1137
|
+
new Promise(
|
|
1138
|
+
(_resolve, reject) => setTimeout(() => {
|
|
1139
|
+
reject(
|
|
1140
|
+
new Error(
|
|
1141
|
+
`Login timed out after ${Math.round(timeoutMs / 1e3)} seconds.`
|
|
1142
|
+
)
|
|
1143
|
+
);
|
|
1144
|
+
}, timeoutMs)
|
|
1145
|
+
)
|
|
1146
|
+
]),
|
|
1147
|
+
"Waiting for you to login and authorize"
|
|
1148
|
+
);
|
|
1149
|
+
} finally {
|
|
1150
|
+
process.off("SIGINT", cleanup);
|
|
1151
|
+
process.off("SIGTERM", cleanup);
|
|
1152
|
+
await new Promise((resolve2) => {
|
|
1153
|
+
const timeout = setTimeout(() => {
|
|
1154
|
+
log_default.info("Server close timed out, forcing connection shutdown...");
|
|
1155
|
+
connections.forEach((conn) => conn.destroy());
|
|
1156
|
+
resolve2();
|
|
1157
|
+
}, 1e3);
|
|
1158
|
+
server.close(() => {
|
|
1159
|
+
clearTimeout(timeout);
|
|
1160
|
+
resolve2();
|
|
1161
|
+
});
|
|
1162
|
+
});
|
|
1163
|
+
}
|
|
1164
|
+
log_default.info("Exchanging authorization code for tokens...");
|
|
1165
|
+
const { data } = await client_default.post(
|
|
1166
|
+
`${ZAPIER_BASE}/oauth/token/`,
|
|
1167
|
+
{
|
|
1168
|
+
grant_type: "authorization_code",
|
|
1169
|
+
code: await promisedCode,
|
|
1170
|
+
redirect_uri: redirectUri,
|
|
1171
|
+
client_id: LOGIN_CLIENT_ID,
|
|
1172
|
+
code_verifier: codeVerifier
|
|
1173
|
+
},
|
|
1174
|
+
{
|
|
1175
|
+
headers: {
|
|
1176
|
+
[AUTH_MODE_HEADER]: "no",
|
|
1177
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
);
|
|
1181
|
+
zapierSdkCliLogin.updateLogin(data);
|
|
1182
|
+
log_default.info("Token exchange completed successfully");
|
|
1183
|
+
return data.access_token;
|
|
1184
|
+
};
|
|
1185
|
+
var login_default = login;
|
|
1186
|
+
var LoginSchema = zod.z.object({
|
|
1187
|
+
timeout: zod.z.string().optional().describe("Login timeout in seconds (default: 300)")
|
|
1188
|
+
}).describe("Log in to Zapier to access your account");
|
|
1189
|
+
|
|
1190
|
+
// src/plugins/login/index.ts
|
|
1191
|
+
var loginWithSdk = zapierSdk.createFunction(async function loginWithSdk2(options) {
|
|
1192
|
+
const timeoutSeconds = options.timeout ? parseInt(options.timeout, 10) : 300;
|
|
1193
|
+
if (isNaN(timeoutSeconds) || timeoutSeconds <= 0) {
|
|
1194
|
+
throw new Error("Timeout must be a positive number");
|
|
1195
|
+
}
|
|
1196
|
+
await login_default(timeoutSeconds * 1e3);
|
|
1197
|
+
const user = await zapierSdkCliLogin.getLoggedInUser();
|
|
1198
|
+
console.log(`\u2705 Successfully logged in as ${user.email}`);
|
|
1199
|
+
setTimeout(() => process.exit(0), 100);
|
|
1200
|
+
}, LoginSchema);
|
|
1201
|
+
var loginPlugin = () => ({
|
|
1202
|
+
login: loginWithSdk,
|
|
1203
|
+
context: {
|
|
1204
|
+
meta: {
|
|
1205
|
+
login: {
|
|
1206
|
+
categories: ["account"],
|
|
1207
|
+
inputSchema: LoginSchema
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
});
|
|
1212
|
+
var LogoutSchema = zod.z.object({}).describe("Log out of your Zapier account");
|
|
1213
|
+
|
|
1214
|
+
// src/plugins/logout/index.ts
|
|
1215
|
+
var logoutWithSdk = zapierSdk.createFunction(async function logoutWithSdk2(_options) {
|
|
1216
|
+
zapierSdkCliLogin.logout();
|
|
1217
|
+
console.log("\u2705 Successfully logged out");
|
|
1218
|
+
}, LogoutSchema);
|
|
1219
|
+
var logoutPlugin = () => ({
|
|
1220
|
+
logout: logoutWithSdk,
|
|
1221
|
+
context: {
|
|
1222
|
+
meta: {
|
|
1223
|
+
logout: {
|
|
1224
|
+
categories: ["account"],
|
|
1225
|
+
inputSchema: LogoutSchema
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
});
|
|
1230
|
+
var McpSchema = zod.z.object({
|
|
1231
|
+
port: zod.z.string().optional().describe("Port to listen on (for future HTTP transport)")
|
|
1232
|
+
}).describe("Start MCP server for Zapier SDK");
|
|
1233
|
+
|
|
1234
|
+
// src/plugins/mcp/index.ts
|
|
1235
|
+
var mcpPlugin = ({ context }) => {
|
|
1236
|
+
const mcpWithSdk = zapierSdk.createFunction(async function mcpWithSdk2(options) {
|
|
1237
|
+
const mcpOptions = {
|
|
1238
|
+
...options,
|
|
1239
|
+
debug: context.options.debug
|
|
1240
|
+
};
|
|
1241
|
+
return await zapierSdkMcp.startMcpServerAsProcess(mcpOptions);
|
|
1242
|
+
}, McpSchema);
|
|
1243
|
+
return {
|
|
1244
|
+
mcp: mcpWithSdk,
|
|
1245
|
+
context: {
|
|
1246
|
+
meta: {
|
|
1247
|
+
mcp: {
|
|
1248
|
+
categories: ["utility"],
|
|
1249
|
+
inputSchema: McpSchema
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1253
|
+
};
|
|
1254
|
+
};
|
|
1255
|
+
var GenerateTypesSchema = zod.z.object({
|
|
1256
|
+
appKey: zapierSdk.AppKeyPropertySchema.describe("App key to generate SDK code for"),
|
|
1257
|
+
authenticationId: zapierSdk.AuthenticationIdPropertySchema.optional(),
|
|
1258
|
+
output: zapierSdk.OutputPropertySchema.optional().describe(
|
|
1259
|
+
"Output file path (defaults to generated/<appKey>.ts)"
|
|
1260
|
+
),
|
|
1261
|
+
lockFilePath: zod.z.string().optional().describe("Path to the .zapierrc lock file (defaults to .zapierrc)")
|
|
1262
|
+
}).describe("Generate TypeScript SDK code for a specific app");
|
|
1263
|
+
var generateTypesPlugin = ({ sdk: sdk2 }) => {
|
|
1264
|
+
const generateTypesWithSdk = zapierSdk.createFunction(
|
|
1265
|
+
async function generateTypesWithSdk2(options) {
|
|
1266
|
+
return await generateTypes({ ...options, sdk: sdk2 });
|
|
1267
|
+
},
|
|
1268
|
+
GenerateTypesSchema
|
|
1269
|
+
);
|
|
1270
|
+
return {
|
|
1271
|
+
generateTypes: generateTypesWithSdk,
|
|
1272
|
+
context: {
|
|
1273
|
+
meta: {
|
|
1274
|
+
generateTypes: {
|
|
1275
|
+
categories: ["utility"],
|
|
1276
|
+
inputSchema: GenerateTypesSchema
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
};
|
|
1281
|
+
};
|
|
1282
|
+
function generateFetchMethodSignature() {
|
|
1283
|
+
return ` /** Make authenticated HTTP requests through Zapier's Relay service */
|
|
1284
|
+
fetch: (options: Omit<z.infer<typeof RelayFetchSchema>, 'authenticationId'>) => Promise<Response>`;
|
|
1285
|
+
}
|
|
1286
|
+
async function generateTypes(options) {
|
|
1287
|
+
const {
|
|
1288
|
+
appKey,
|
|
1289
|
+
authenticationId,
|
|
1290
|
+
output = `./types/${appKey}.d.ts`,
|
|
1291
|
+
sdk: sdk2
|
|
1292
|
+
} = options;
|
|
1293
|
+
const { app, version } = parseAppIdentifier(appKey);
|
|
1294
|
+
const actionsResult = await sdk2.listActions({
|
|
1295
|
+
appKey: app
|
|
1296
|
+
});
|
|
1297
|
+
const actions = actionsResult.data;
|
|
1298
|
+
if (actions.length === 0) {
|
|
1299
|
+
const typeDefinitions2 = generateEmptyTypesFile(app, version);
|
|
1300
|
+
if (output) {
|
|
1301
|
+
fs__namespace.mkdirSync(path__namespace.dirname(output), { recursive: true });
|
|
1302
|
+
fs__namespace.writeFileSync(output, typeDefinitions2, "utf8");
|
|
1303
|
+
}
|
|
1304
|
+
return typeDefinitions2;
|
|
1305
|
+
}
|
|
1306
|
+
const actionsWithFields = [];
|
|
1307
|
+
if (authenticationId) {
|
|
1308
|
+
for (const action of actions) {
|
|
1309
|
+
try {
|
|
1310
|
+
const manifestEntry = sdk2.getContext().getManifestEntry(appKey);
|
|
1311
|
+
const fieldsResult = await sdk2.listInputFields({
|
|
1312
|
+
// If the appKey is in the manifest, use the appKey so that the types are consistent with the manifest's version, otherwise use the action.app_key
|
|
1313
|
+
appKey: manifestEntry ? appKey : action.app_key,
|
|
1314
|
+
actionKey: action.key,
|
|
1315
|
+
actionType: action.action_type,
|
|
1316
|
+
authenticationId
|
|
1317
|
+
});
|
|
1318
|
+
const fields = fieldsResult.data.map((field) => {
|
|
1319
|
+
const fieldObj = field;
|
|
1320
|
+
return {
|
|
1321
|
+
...fieldObj,
|
|
1322
|
+
required: fieldObj.is_required || fieldObj.required || false
|
|
1323
|
+
};
|
|
1324
|
+
});
|
|
1325
|
+
actionsWithFields.push({
|
|
1326
|
+
...action,
|
|
1327
|
+
inputFields: fields,
|
|
1328
|
+
name: action.title || action.key
|
|
1329
|
+
});
|
|
1330
|
+
} catch {
|
|
1331
|
+
actionsWithFields.push({
|
|
1332
|
+
...action,
|
|
1333
|
+
inputFields: [],
|
|
1334
|
+
name: action.title || action.key
|
|
1335
|
+
});
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
} else {
|
|
1339
|
+
actions.forEach((action) => {
|
|
1340
|
+
actionsWithFields.push({
|
|
1341
|
+
...action,
|
|
1342
|
+
inputFields: [],
|
|
1343
|
+
name: action.title || action.key
|
|
1344
|
+
});
|
|
1345
|
+
});
|
|
1346
|
+
}
|
|
1347
|
+
const typeDefinitions = generateTypeDefinitions(
|
|
1348
|
+
app,
|
|
1349
|
+
actionsWithFields,
|
|
1350
|
+
version
|
|
1351
|
+
);
|
|
1352
|
+
if (output) {
|
|
1353
|
+
fs__namespace.mkdirSync(path__namespace.dirname(output), { recursive: true });
|
|
1354
|
+
fs__namespace.writeFileSync(output, typeDefinitions, "utf8");
|
|
1355
|
+
}
|
|
1356
|
+
return typeDefinitions;
|
|
1357
|
+
}
|
|
1358
|
+
function parseAppIdentifier(identifier) {
|
|
1359
|
+
const parts = identifier.split("@");
|
|
1360
|
+
return {
|
|
1361
|
+
app: parts[0],
|
|
1362
|
+
version: parts[1]
|
|
1363
|
+
};
|
|
1364
|
+
}
|
|
1365
|
+
function generateTypeDefinitions(appKey, actions, version) {
|
|
1366
|
+
if (actions.length === 0) {
|
|
1367
|
+
return generateEmptyTypesFile(appKey, version);
|
|
1368
|
+
}
|
|
1369
|
+
const actionsByType = actions.reduce(
|
|
1370
|
+
(acc, action) => {
|
|
1371
|
+
if (!acc[action.action_type]) {
|
|
1372
|
+
acc[action.action_type] = [];
|
|
1373
|
+
}
|
|
1374
|
+
acc[action.action_type].push(action);
|
|
1375
|
+
return acc;
|
|
1376
|
+
},
|
|
1377
|
+
{}
|
|
1378
|
+
);
|
|
1379
|
+
const appName = capitalize(appKey);
|
|
1380
|
+
const versionComment = version ? ` * Generated for ${appKey}@${version}` : ` * Generated for ${appKey}`;
|
|
1381
|
+
let output = `/* eslint-disable @typescript-eslint/naming-convention */
|
|
1382
|
+
/**
|
|
1383
|
+
* Auto-generated TypeScript types for Zapier ${appKey} actions
|
|
1384
|
+
${versionComment}
|
|
1385
|
+
* Generated on: ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
1386
|
+
*
|
|
1387
|
+
* Usage:
|
|
1388
|
+
* import type { ${appName}Sdk } from './path/to/this/file'
|
|
1389
|
+
* const sdk = createZapierSdk() as unknown as ${appName}Sdk
|
|
1390
|
+
*
|
|
1391
|
+
* // Direct usage (per-call auth):
|
|
1392
|
+
* await sdk.apps.${appKey}.search.user_by_email({ authenticationId: 123, inputs: { email } })
|
|
1393
|
+
*
|
|
1394
|
+
* // Factory usage (pinned auth):
|
|
1395
|
+
* const my${appName} = sdk.apps.${appKey}({ authenticationId: 123 })
|
|
1396
|
+
* await my${appName}.search.user_by_email({ inputs: { email } })
|
|
1397
|
+
*/
|
|
1398
|
+
|
|
1399
|
+
import type { ActionExecutionOptions, ActionExecutionResult } from '@zapier/zapier-sdk'
|
|
1400
|
+
import { z } from 'zod'
|
|
1401
|
+
import { RelayFetchSchema } from '@zapier/zapier-sdk'
|
|
1402
|
+
|
|
1403
|
+
`;
|
|
1404
|
+
actions.forEach((action) => {
|
|
1405
|
+
if (action.inputFields.length > 0) {
|
|
1406
|
+
const inputTypeName = `${appName}${capitalize(action.action_type)}${capitalize(
|
|
1407
|
+
sanitizeActionName(action.key)
|
|
1408
|
+
)}Inputs`;
|
|
1409
|
+
output += `interface ${inputTypeName} {
|
|
1410
|
+
`;
|
|
1411
|
+
action.inputFields.forEach((field) => {
|
|
1412
|
+
const isOptional = !field.required;
|
|
1413
|
+
const fieldType = mapFieldTypeToTypeScript(field);
|
|
1414
|
+
const description = field.helpText ? ` /** ${escapeComment(field.helpText)} */
|
|
1415
|
+
` : "";
|
|
1416
|
+
output += `${description} ${sanitizeFieldName(field.key)}${isOptional ? "?" : ""}: ${fieldType}
|
|
1417
|
+
`;
|
|
1418
|
+
});
|
|
1419
|
+
output += `}
|
|
1420
|
+
|
|
1421
|
+
`;
|
|
1422
|
+
}
|
|
1423
|
+
});
|
|
1424
|
+
Object.entries(actionsByType).forEach(([actionType, typeActions]) => {
|
|
1425
|
+
const typeName = `${appName}${capitalize(actionType)}Actions`;
|
|
1426
|
+
output += `interface ${typeName} {
|
|
1427
|
+
`;
|
|
1428
|
+
typeActions.forEach((action) => {
|
|
1429
|
+
const actionName = sanitizeActionName(action.key);
|
|
1430
|
+
const description = action.description ? ` /** ${escapeComment(action.description)} */
|
|
1431
|
+
` : "";
|
|
1432
|
+
if (action.inputFields.length > 0) {
|
|
1433
|
+
const inputTypeName = `${appName}${capitalize(action.action_type)}${capitalize(
|
|
1434
|
+
sanitizeActionName(action.key)
|
|
1435
|
+
)}Inputs`;
|
|
1436
|
+
output += `${description} ${actionName}: (options: { inputs: ${inputTypeName} } & Omit<ActionExecutionOptions, 'inputs'>) => Promise<ActionExecutionResult>
|
|
1437
|
+
`;
|
|
1438
|
+
} else {
|
|
1439
|
+
output += `${description} ${actionName}: (options?: { inputs?: Record<string, any> } & ActionExecutionOptions) => Promise<ActionExecutionResult>
|
|
1440
|
+
`;
|
|
1441
|
+
}
|
|
1442
|
+
});
|
|
1443
|
+
output += `}
|
|
1444
|
+
|
|
1445
|
+
`;
|
|
1446
|
+
});
|
|
1447
|
+
output += `interface ${appName}AppProxy {
|
|
1448
|
+
`;
|
|
1449
|
+
Object.keys(actionsByType).forEach((actionType) => {
|
|
1450
|
+
const typeName = `${appName}${capitalize(actionType)}Actions`;
|
|
1451
|
+
output += ` ${actionType}: ${typeName}
|
|
1452
|
+
`;
|
|
1453
|
+
});
|
|
1454
|
+
output += generateFetchMethodSignature() + "\n";
|
|
1455
|
+
output += `}
|
|
1456
|
+
|
|
1457
|
+
`;
|
|
1458
|
+
output += `interface ${appName}AppFactory {
|
|
1459
|
+
`;
|
|
1460
|
+
output += ` (options: { authenticationId: number }): ${appName}AppProxy
|
|
1461
|
+
`;
|
|
1462
|
+
output += `}
|
|
1463
|
+
|
|
1464
|
+
`;
|
|
1465
|
+
output += `type ${appName}AppWithFactory = ${appName}AppFactory & ${appName}AppProxy
|
|
1466
|
+
|
|
1467
|
+
`;
|
|
1468
|
+
output += `export interface ${appName}Sdk {
|
|
1469
|
+
`;
|
|
1470
|
+
output += ` apps: {
|
|
1471
|
+
`;
|
|
1472
|
+
output += ` ${appKey}: ${appName}AppWithFactory
|
|
1473
|
+
`;
|
|
1474
|
+
output += ` }
|
|
1475
|
+
`;
|
|
1476
|
+
output += `}
|
|
1477
|
+
`;
|
|
1478
|
+
return output;
|
|
1479
|
+
}
|
|
1480
|
+
function generateEmptyTypesFile(appKey, version) {
|
|
1481
|
+
const appName = capitalize(appKey);
|
|
1482
|
+
const versionComment = version ? ` * Generated for ${appKey}@${version}` : ` * Generated for ${appKey}`;
|
|
1483
|
+
return `/* eslint-disable @typescript-eslint/naming-convention */
|
|
1484
|
+
/**
|
|
1485
|
+
* Auto-generated TypeScript types for Zapier ${appKey} actions
|
|
1486
|
+
${versionComment}
|
|
1487
|
+
* Generated on: ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
1488
|
+
*
|
|
1489
|
+
* No actions found for this app.
|
|
1490
|
+
*/
|
|
1491
|
+
|
|
1492
|
+
import type { ActionExecutionOptions, ActionExecutionResult } from '@zapier/zapier-sdk'
|
|
1493
|
+
import { z } from 'zod'
|
|
1494
|
+
import { RelayFetchSchema } from '@zapier/zapier-sdk'
|
|
1495
|
+
|
|
1496
|
+
interface ${appName}AppProxy {
|
|
1497
|
+
// No actions available
|
|
1498
|
+
${generateFetchMethodSignature()}
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1501
|
+
interface ${appName}AppFactory {
|
|
1502
|
+
(options: { authenticationId: number }): ${appName}AppProxy
|
|
1503
|
+
}
|
|
1504
|
+
|
|
1505
|
+
type ${appName}AppWithFactory = ${appName}AppFactory & ${appName}AppProxy
|
|
1506
|
+
|
|
1507
|
+
export interface ${appName}Sdk {
|
|
1508
|
+
apps: {
|
|
1509
|
+
${appKey}: ${appName}AppWithFactory
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1512
|
+
`;
|
|
1513
|
+
}
|
|
1514
|
+
function capitalize(str) {
|
|
1515
|
+
return str.charAt(0).toUpperCase() + str.slice(1).replace(/[-_]/g, "");
|
|
1516
|
+
}
|
|
1517
|
+
function sanitizeActionName(actionKey) {
|
|
1518
|
+
let sanitized = actionKey.replace(/[^a-zA-Z0-9_$]/g, "_");
|
|
1519
|
+
if (/^[0-9]/.test(sanitized)) {
|
|
1520
|
+
sanitized = "_" + sanitized;
|
|
1521
|
+
}
|
|
1522
|
+
return sanitized;
|
|
1523
|
+
}
|
|
1524
|
+
function sanitizeFieldName(fieldKey) {
|
|
1525
|
+
let sanitized = fieldKey.replace(/[^a-zA-Z0-9_$]/g, "_");
|
|
1526
|
+
if (/^[0-9]/.test(sanitized)) {
|
|
1527
|
+
sanitized = "_" + sanitized;
|
|
1528
|
+
}
|
|
1529
|
+
return sanitized;
|
|
1530
|
+
}
|
|
1531
|
+
function escapeComment(comment) {
|
|
1532
|
+
return comment.replace(/\*\//g, "*\\/").replace(/\r?\n/g, " ");
|
|
1533
|
+
}
|
|
1534
|
+
function mapFieldTypeToTypeScript(field) {
|
|
1535
|
+
if (field.choices && field.choices.length > 0) {
|
|
1536
|
+
const choiceValues = field.choices.filter(
|
|
1537
|
+
(choice) => choice.value !== void 0 && choice.value !== null && choice.value !== ""
|
|
1538
|
+
).map(
|
|
1539
|
+
(choice) => typeof choice.value === "string" ? `"${choice.value}"` : choice.value
|
|
1540
|
+
);
|
|
1541
|
+
if (choiceValues.length > 0) {
|
|
1542
|
+
return choiceValues.join(" | ");
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1545
|
+
switch (field.type?.toLowerCase()) {
|
|
1546
|
+
case "string":
|
|
1547
|
+
case "text":
|
|
1548
|
+
case "email":
|
|
1549
|
+
case "url":
|
|
1550
|
+
case "password":
|
|
1551
|
+
return "string";
|
|
1552
|
+
case "integer":
|
|
1553
|
+
case "number":
|
|
1554
|
+
return "number";
|
|
1555
|
+
case "boolean":
|
|
1556
|
+
return "boolean";
|
|
1557
|
+
case "datetime":
|
|
1558
|
+
case "date":
|
|
1559
|
+
return "string";
|
|
1560
|
+
// ISO date strings
|
|
1561
|
+
case "file":
|
|
1562
|
+
return "string";
|
|
1563
|
+
// File URL or content
|
|
1564
|
+
case "array":
|
|
1565
|
+
return "any[]";
|
|
1566
|
+
case "object":
|
|
1567
|
+
return "Record<string, any>";
|
|
1568
|
+
default:
|
|
1569
|
+
return "string | number | boolean";
|
|
1570
|
+
}
|
|
1571
|
+
}
|
|
1572
|
+
var BundleCodeSchema = zod.z.object({
|
|
1573
|
+
input: zod.z.string().min(1).describe("Input TypeScript file path to bundle"),
|
|
1574
|
+
output: zapierSdk.OutputPropertySchema.optional().describe(
|
|
1575
|
+
"Output file path (defaults to input with .js extension)"
|
|
1576
|
+
),
|
|
1577
|
+
string: zod.z.boolean().optional().describe("Return bundled code as string instead of writing to file"),
|
|
1578
|
+
minify: zod.z.boolean().optional().describe("Minify the bundled output"),
|
|
1579
|
+
target: zod.z.string().optional().describe("ECMAScript target version"),
|
|
1580
|
+
cjs: zod.z.boolean().optional().describe("Output CommonJS format instead of ESM")
|
|
1581
|
+
}).describe("Bundle TypeScript code into executable JavaScript");
|
|
1582
|
+
var bundleCodePlugin = () => {
|
|
1583
|
+
const bundleCodeWithSdk = zapierSdk.createFunction(async function bundleCodeWithSdk2(options) {
|
|
1584
|
+
return await bundleCode(options);
|
|
1585
|
+
}, BundleCodeSchema);
|
|
1586
|
+
return {
|
|
1587
|
+
bundleCode: bundleCodeWithSdk,
|
|
1588
|
+
context: {
|
|
1589
|
+
meta: {
|
|
1590
|
+
bundleCode: {
|
|
1591
|
+
categories: ["utility"],
|
|
1592
|
+
inputSchema: BundleCodeSchema
|
|
1593
|
+
}
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1596
|
+
};
|
|
1597
|
+
};
|
|
1598
|
+
var ZapierBundleError = class extends Error {
|
|
1599
|
+
constructor(message, details, originalError) {
|
|
1600
|
+
super(message);
|
|
1601
|
+
this.code = "ZAPIER_BUNDLE_ERROR";
|
|
1602
|
+
this.name = "ZapierBundleError";
|
|
1603
|
+
this.details = details;
|
|
1604
|
+
this.originalError = originalError;
|
|
1605
|
+
}
|
|
1606
|
+
};
|
|
1607
|
+
async function bundleCode(options) {
|
|
1608
|
+
const {
|
|
1609
|
+
input,
|
|
1610
|
+
output,
|
|
1611
|
+
target = "es2020",
|
|
1612
|
+
cjs = false,
|
|
1613
|
+
minify = false,
|
|
1614
|
+
string: returnString = false
|
|
1615
|
+
} = options;
|
|
1616
|
+
const resolvedInput = path__namespace.resolve(process.cwd(), input);
|
|
1617
|
+
try {
|
|
1618
|
+
const result = esbuild.buildSync({
|
|
1619
|
+
entryPoints: [resolvedInput],
|
|
1620
|
+
bundle: true,
|
|
1621
|
+
platform: "node",
|
|
1622
|
+
target,
|
|
1623
|
+
format: cjs ? "cjs" : "esm",
|
|
1624
|
+
minify,
|
|
1625
|
+
write: false,
|
|
1626
|
+
external: [],
|
|
1627
|
+
// Bundle everything
|
|
1628
|
+
banner: {
|
|
1629
|
+
js: "#!/usr/bin/env node"
|
|
1630
|
+
}
|
|
1631
|
+
});
|
|
1632
|
+
if (result.errors.length > 0) {
|
|
1633
|
+
const errorMessages = result.errors.map((e) => e.text);
|
|
1634
|
+
throw new ZapierBundleError(
|
|
1635
|
+
`Bundle failed: ${errorMessages.join(", ")}`,
|
|
1636
|
+
errorMessages
|
|
1637
|
+
);
|
|
1638
|
+
}
|
|
1639
|
+
const bundledCode = result.outputFiles?.[0]?.text;
|
|
1640
|
+
if (!bundledCode) {
|
|
1641
|
+
throw new ZapierBundleError("No output generated");
|
|
1642
|
+
}
|
|
1643
|
+
let finalOutput = bundledCode;
|
|
1644
|
+
if (returnString) {
|
|
1645
|
+
finalOutput = JSON.stringify(bundledCode);
|
|
1646
|
+
}
|
|
1647
|
+
if (output) {
|
|
1648
|
+
fs__namespace.mkdirSync(path__namespace.dirname(output), { recursive: true });
|
|
1649
|
+
fs__namespace.writeFileSync(output, finalOutput, "utf8");
|
|
1650
|
+
}
|
|
1651
|
+
return finalOutput;
|
|
1652
|
+
} catch (error) {
|
|
1653
|
+
if (error instanceof ZapierBundleError) {
|
|
1654
|
+
throw error;
|
|
1655
|
+
}
|
|
1656
|
+
throw new ZapierBundleError(
|
|
1657
|
+
`Bundle failed: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
1658
|
+
void 0,
|
|
1659
|
+
error instanceof Error ? error : void 0
|
|
1660
|
+
);
|
|
1661
|
+
}
|
|
1662
|
+
}
|
|
1663
|
+
var GetConfigPathSchema = zod.z.object({}).describe("Show the path to the configuration file");
|
|
1664
|
+
var getConfigPathPlugin = () => {
|
|
1665
|
+
const getConfigPathWithSdk = zapierSdk.createFunction(
|
|
1666
|
+
async function getConfigPathWithSdk2(_options) {
|
|
1667
|
+
return zapierSdkCliLogin.getConfigPath();
|
|
1668
|
+
},
|
|
1669
|
+
GetConfigPathSchema
|
|
1670
|
+
);
|
|
1671
|
+
return {
|
|
1672
|
+
getConfigPath: getConfigPathWithSdk,
|
|
1673
|
+
context: {
|
|
1674
|
+
meta: {
|
|
1675
|
+
getConfigPath: {
|
|
1676
|
+
categories: ["utility"],
|
|
1677
|
+
inputSchema: GetConfigPathSchema
|
|
1678
|
+
}
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
};
|
|
1682
|
+
};
|
|
1683
|
+
|
|
1684
|
+
// src/sdk.ts
|
|
1685
|
+
function createZapierCliSdk(options = {}) {
|
|
1686
|
+
let sdk2 = zapierSdk.createZapierSdkWithoutRegistry({
|
|
1687
|
+
debug: options.debug
|
|
1688
|
+
});
|
|
1689
|
+
sdk2 = sdk2.addPlugin(generateTypesPlugin);
|
|
1690
|
+
sdk2 = sdk2.addPlugin(bundleCodePlugin);
|
|
1691
|
+
sdk2 = sdk2.addPlugin(getConfigPathPlugin);
|
|
1692
|
+
sdk2 = sdk2.addPlugin(mcpPlugin);
|
|
1693
|
+
sdk2 = sdk2.addPlugin(loginPlugin);
|
|
1694
|
+
sdk2 = sdk2.addPlugin(logoutPlugin);
|
|
1695
|
+
const finalSdk = sdk2.addPlugin(zapierSdk.registryPlugin);
|
|
1696
|
+
return finalSdk;
|
|
1697
|
+
}
|
|
1698
|
+
|
|
1699
|
+
// package.json
|
|
1700
|
+
var package_default = {
|
|
1701
|
+
version: "0.6.4"};
|
|
1702
|
+
|
|
1703
|
+
// src/cli.ts
|
|
1704
|
+
var program = new commander.Command();
|
|
1705
|
+
program.name("zapier-sdk").description("CLI for Zapier SDK").version(package_default.version, "-v, --version", "display version number").option("--debug", "Enable debug logging");
|
|
1706
|
+
var isDebugMode = process.env.DEBUG === "true" || process.argv.includes("--debug");
|
|
1707
|
+
var sdk = createZapierCliSdk({
|
|
1708
|
+
debug: isDebugMode
|
|
1709
|
+
});
|
|
1710
|
+
generateCliCommands(program, sdk);
|
|
1711
|
+
program.parse();
|