@zapier/zapier-sdk-cli 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/zapier-sdk.js +4 -0
- package/bin/zsdk.js +4 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +25 -0
- package/dist/commands/action.d.ts +2 -0
- package/dist/commands/action.js +295 -0
- package/dist/commands/browse.d.ts +2 -0
- package/dist/commands/browse.js +257 -0
- package/dist/commands/bundle.d.ts +2 -0
- package/dist/commands/bundle.js +101 -0
- package/dist/commands/generate.d.ts +9 -0
- package/dist/commands/generate.js +281 -0
- package/dist/index.d.ts +0 -0
- package/dist/index.js +3 -0
- package/dist/utils/auth-picker.d.ts +17 -0
- package/dist/utils/auth-picker.js +121 -0
- package/dist/utils/cli-generator.d.ts +4 -0
- package/dist/utils/cli-generator.js +414 -0
- package/dist/utils/pager.d.ts +48 -0
- package/dist/utils/pager.js +147 -0
- package/dist/utils/parameter-resolver.d.ts +18 -0
- package/dist/utils/parameter-resolver.js +413 -0
- package/dist/utils/schema-formatter.d.ts +2 -0
- package/dist/utils/schema-formatter.js +72 -0
- package/dist/utils/schema-generator.d.ts +4 -0
- package/dist/utils/schema-generator.js +389 -0
- package/package.json +42 -0
- package/src/cli.ts +32 -0
- package/src/index.ts +2 -0
- package/src/utils/cli-generator.ts +578 -0
- package/src/utils/pager.ts +202 -0
- package/src/utils/parameter-resolver.ts +573 -0
- package/src/utils/schema-formatter.ts +88 -0
- package/test/cli.test.ts +46 -0
- package/tsconfig.build.json +6 -0
- package/tsconfig.json +22 -0
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.generateCLICommands = generateCLICommands;
|
|
7
|
+
exports.enhanceCommandHelp = enhanceCommandHelp;
|
|
8
|
+
const zod_1 = require("zod");
|
|
9
|
+
const schemas_1 = require("../../../actions-sdk/dist/schemas");
|
|
10
|
+
const parameter_resolver_1 = require("./parameter-resolver");
|
|
11
|
+
const pager_1 = require("./pager");
|
|
12
|
+
const schema_formatter_1 = require("./schema-formatter");
|
|
13
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
14
|
+
const util_1 = __importDefault(require("util"));
|
|
15
|
+
// ============================================================================
|
|
16
|
+
// JSON Formatting
|
|
17
|
+
// ============================================================================
|
|
18
|
+
function formatJSONOutput(data) {
|
|
19
|
+
// Show success message for action results
|
|
20
|
+
if (data &&
|
|
21
|
+
typeof data === "object" &&
|
|
22
|
+
!Array.isArray(data) &&
|
|
23
|
+
(data.success !== undefined || data.id || data.status)) {
|
|
24
|
+
console.log(chalk_1.default.green("ā
Action completed successfully!\n"));
|
|
25
|
+
}
|
|
26
|
+
// Use util.inspect for colored output
|
|
27
|
+
console.log(util_1.default.inspect(data, { colors: true, depth: null, breakLength: 80 }));
|
|
28
|
+
}
|
|
29
|
+
// ============================================================================
|
|
30
|
+
// Schema Analysis
|
|
31
|
+
// ============================================================================
|
|
32
|
+
function analyzeZodSchema(schema) {
|
|
33
|
+
const parameters = [];
|
|
34
|
+
if (schema instanceof zod_1.z.ZodObject) {
|
|
35
|
+
const shape = schema.shape;
|
|
36
|
+
for (const [key, fieldSchema] of Object.entries(shape)) {
|
|
37
|
+
const param = analyzeZodField(key, fieldSchema);
|
|
38
|
+
if (param) {
|
|
39
|
+
parameters.push(param);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return parameters;
|
|
44
|
+
}
|
|
45
|
+
function analyzeZodField(name, schema) {
|
|
46
|
+
let baseSchema = schema;
|
|
47
|
+
let required = true;
|
|
48
|
+
let defaultValue = undefined;
|
|
49
|
+
// Unwrap optional and default wrappers
|
|
50
|
+
if (baseSchema instanceof zod_1.z.ZodOptional) {
|
|
51
|
+
required = false;
|
|
52
|
+
baseSchema = baseSchema._def.innerType;
|
|
53
|
+
}
|
|
54
|
+
if (baseSchema instanceof zod_1.z.ZodDefault) {
|
|
55
|
+
required = false;
|
|
56
|
+
defaultValue = baseSchema._def.defaultValue();
|
|
57
|
+
baseSchema = baseSchema._def.innerType;
|
|
58
|
+
}
|
|
59
|
+
// Determine parameter type
|
|
60
|
+
let paramType = "string";
|
|
61
|
+
let choices;
|
|
62
|
+
if (baseSchema instanceof zod_1.z.ZodString) {
|
|
63
|
+
paramType = "string";
|
|
64
|
+
}
|
|
65
|
+
else if (baseSchema instanceof zod_1.z.ZodNumber) {
|
|
66
|
+
paramType = "number";
|
|
67
|
+
}
|
|
68
|
+
else if (baseSchema instanceof zod_1.z.ZodBoolean) {
|
|
69
|
+
paramType = "boolean";
|
|
70
|
+
}
|
|
71
|
+
else if (baseSchema instanceof zod_1.z.ZodArray) {
|
|
72
|
+
paramType = "array";
|
|
73
|
+
}
|
|
74
|
+
else if (baseSchema instanceof zod_1.z.ZodEnum) {
|
|
75
|
+
paramType = "string";
|
|
76
|
+
choices = baseSchema._def.values;
|
|
77
|
+
}
|
|
78
|
+
else if (baseSchema instanceof zod_1.z.ZodRecord) {
|
|
79
|
+
// Handle Record<string, any> as JSON string input
|
|
80
|
+
paramType = "string";
|
|
81
|
+
}
|
|
82
|
+
// Extract resolver metadata
|
|
83
|
+
const resolverMeta = schema._def.resolverMeta;
|
|
84
|
+
return {
|
|
85
|
+
name,
|
|
86
|
+
type: paramType,
|
|
87
|
+
required,
|
|
88
|
+
description: schema.description,
|
|
89
|
+
default: defaultValue,
|
|
90
|
+
choices,
|
|
91
|
+
resolverMeta,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
// ============================================================================
|
|
95
|
+
// CLI Command Generation
|
|
96
|
+
// ============================================================================
|
|
97
|
+
function generateCLICommands(program, sdk) {
|
|
98
|
+
// Check if SDKSchemas is available
|
|
99
|
+
if (!schemas_1.SDKSchemas) {
|
|
100
|
+
console.error("SDKSchemas not available");
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
// Generate namespace commands (apps, actions, auths, fields)
|
|
104
|
+
Object.entries(schemas_1.SDKSchemas).forEach(([namespace, methods]) => {
|
|
105
|
+
if (namespace === "generate" || namespace === "bundle") {
|
|
106
|
+
// Handle root tools separately
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
const namespaceCommand = program
|
|
110
|
+
.command(namespace)
|
|
111
|
+
.description(`${namespace} management commands`);
|
|
112
|
+
if (typeof methods === "object" && methods !== null) {
|
|
113
|
+
Object.entries(methods).forEach(([method, schema]) => {
|
|
114
|
+
const config = createCommandConfig(namespace, method, schema, sdk);
|
|
115
|
+
addSubCommand(namespaceCommand, method, config);
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
// Generate root tool commands
|
|
120
|
+
if (schemas_1.SDKSchemas.generate) {
|
|
121
|
+
const generateConfig = createCommandConfig("", "generate", schemas_1.SDKSchemas.generate, sdk);
|
|
122
|
+
addSubCommand(program, "generate", generateConfig);
|
|
123
|
+
}
|
|
124
|
+
if (schemas_1.SDKSchemas.bundle) {
|
|
125
|
+
const bundleConfig = createCommandConfig("", "bundle", schemas_1.SDKSchemas.bundle, sdk);
|
|
126
|
+
addSubCommand(program, "bundle", bundleConfig);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
function createCommandConfig(namespace, method, schema, sdk) {
|
|
130
|
+
const parameters = analyzeZodSchema(schema);
|
|
131
|
+
const description = schema.description || `${namespace} ${method} command`;
|
|
132
|
+
const handler = async (...args) => {
|
|
133
|
+
try {
|
|
134
|
+
// The last argument is always the command object with parsed options
|
|
135
|
+
const command = args[args.length - 1];
|
|
136
|
+
const options = command.opts();
|
|
137
|
+
// Check if this is a list command with pagination support
|
|
138
|
+
const isListCommand = method === "list";
|
|
139
|
+
const hasPaginationParams = parameters.some((p) => p.name === "limit" || p.name === "offset");
|
|
140
|
+
const hasUserSpecifiedLimit = "limit" in options && options.limit !== undefined;
|
|
141
|
+
const shouldUsePaging = isListCommand && hasPaginationParams && !hasUserSpecifiedLimit;
|
|
142
|
+
const shouldUseJSON = options.json;
|
|
143
|
+
// Convert CLI args to SDK method parameters
|
|
144
|
+
const rawParams = convertCLIArgsToSDKParams(parameters, args.slice(0, -1), options);
|
|
145
|
+
// NEW: Resolve missing parameters interactively using schema metadata
|
|
146
|
+
const resolver = new parameter_resolver_1.SchemaParameterResolver();
|
|
147
|
+
const resolvedParams = await resolver.resolveParameters(schema, rawParams, sdk);
|
|
148
|
+
if (shouldUsePaging && !shouldUseJSON) {
|
|
149
|
+
// Use interactive paging for list commands
|
|
150
|
+
await handlePaginatedList(namespace, method, resolvedParams, sdk);
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
// Call the appropriate SDK method with complete, validated parameters
|
|
154
|
+
let result;
|
|
155
|
+
if (namespace === "") {
|
|
156
|
+
// Root tool (generate, bundle)
|
|
157
|
+
result = await sdk[method](resolvedParams);
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
// Regular namespace method
|
|
161
|
+
result = await sdk[namespace][method](resolvedParams);
|
|
162
|
+
}
|
|
163
|
+
// Special handling for generate and bundle commands - don't output to console if writing to file
|
|
164
|
+
const isRootCommandWithOutput = namespace === "" && (method === "generate" || method === "bundle");
|
|
165
|
+
const hasOutputFile = isRootCommandWithOutput && resolvedParams.output;
|
|
166
|
+
// Output result (JSON or formatted)
|
|
167
|
+
if (!hasOutputFile && (shouldUseJSON || !isListCommand)) {
|
|
168
|
+
// Use raw JSON if --json flag is specified, otherwise use pretty formatting
|
|
169
|
+
if (shouldUseJSON) {
|
|
170
|
+
console.log(JSON.stringify(result, null, 2));
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
formatJSONOutput(result);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
else if (!hasOutputFile) {
|
|
177
|
+
// Format list results nicely (non-paginated)
|
|
178
|
+
formatNonPaginatedResults(namespace, result, resolvedParams.limit, hasUserSpecifiedLimit, shouldUseJSON);
|
|
179
|
+
}
|
|
180
|
+
else if (hasOutputFile) {
|
|
181
|
+
// Show success message for file output instead of printing generated content
|
|
182
|
+
console.log(chalk_1.default.green(`ā
${method} completed successfully!`));
|
|
183
|
+
console.log(chalk_1.default.gray(`Output written to: ${resolvedParams.output}`));
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
catch (error) {
|
|
188
|
+
console.error("Error:", error instanceof Error ? error.message : "Unknown error");
|
|
189
|
+
process.exit(1);
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
return {
|
|
193
|
+
description,
|
|
194
|
+
parameters,
|
|
195
|
+
handler,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
function addSubCommand(parentCommand, name, config) {
|
|
199
|
+
const command = parentCommand.command(name).description(config.description);
|
|
200
|
+
// Add parameters to command
|
|
201
|
+
config.parameters.forEach((param) => {
|
|
202
|
+
if (param.resolverMeta?.resolver && param.required) {
|
|
203
|
+
// Required parameters with resolvers become optional positional arguments (resolver handles prompting)
|
|
204
|
+
command.argument(`[${param.name}]`, param.description || `${param.name} parameter`);
|
|
205
|
+
}
|
|
206
|
+
else if (param.required) {
|
|
207
|
+
// Required parameters without resolvers become required positional arguments
|
|
208
|
+
command.argument(`<${param.name}>`, param.description || `${param.name} parameter`);
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
// Optional parameters become flags (whether they have resolvers or not)
|
|
212
|
+
const flags = [
|
|
213
|
+
`--${param.name.replace(/([A-Z])/g, "-$1").toLowerCase()}`,
|
|
214
|
+
];
|
|
215
|
+
if (param.type === "boolean") {
|
|
216
|
+
command.option(flags.join(", "), param.description);
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
const flagSignature = flags.join(", ") + ` <${param.type}>`;
|
|
220
|
+
command.option(flagSignature, param.description, param.default);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
// Add formatting options for all commands
|
|
225
|
+
command.option("--json", "Output raw JSON instead of formatted results");
|
|
226
|
+
command.action(config.handler);
|
|
227
|
+
}
|
|
228
|
+
// ============================================================================
|
|
229
|
+
// Parameter Conversion
|
|
230
|
+
// ============================================================================
|
|
231
|
+
function convertCLIArgsToSDKParams(parameters, positionalArgs, options) {
|
|
232
|
+
const sdkParams = {};
|
|
233
|
+
// Handle positional arguments (required parameters only, whether they have resolvers or not)
|
|
234
|
+
let argIndex = 0;
|
|
235
|
+
parameters.forEach((param) => {
|
|
236
|
+
if (param.required && argIndex < positionalArgs.length) {
|
|
237
|
+
sdkParams[param.name] = convertValue(positionalArgs[argIndex], param.type);
|
|
238
|
+
argIndex++;
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
// Handle option flags
|
|
242
|
+
Object.entries(options).forEach(([key, value]) => {
|
|
243
|
+
// Convert kebab-case back to camelCase
|
|
244
|
+
const camelKey = key.replace(/-([a-z])/g, (g) => g[1].toUpperCase());
|
|
245
|
+
const param = parameters.find((p) => p.name === camelKey);
|
|
246
|
+
if (param && value !== undefined) {
|
|
247
|
+
sdkParams[camelKey] = convertValue(value, param.type);
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
return sdkParams;
|
|
251
|
+
}
|
|
252
|
+
function convertValue(value, type) {
|
|
253
|
+
switch (type) {
|
|
254
|
+
case "number":
|
|
255
|
+
return Number(value);
|
|
256
|
+
case "boolean":
|
|
257
|
+
return Boolean(value);
|
|
258
|
+
case "array":
|
|
259
|
+
return Array.isArray(value) ? value : [value];
|
|
260
|
+
case "string":
|
|
261
|
+
default:
|
|
262
|
+
// Handle JSON string for objects
|
|
263
|
+
if (typeof value === "string" &&
|
|
264
|
+
(value.startsWith("{") || value.startsWith("["))) {
|
|
265
|
+
try {
|
|
266
|
+
return JSON.parse(value);
|
|
267
|
+
}
|
|
268
|
+
catch {
|
|
269
|
+
return value;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
return value;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
// ============================================================================
|
|
276
|
+
// Pagination Handlers
|
|
277
|
+
// ============================================================================
|
|
278
|
+
async function handlePaginatedList(namespace, method, baseParams, sdk) {
|
|
279
|
+
const limit = baseParams.limit || 20;
|
|
280
|
+
const itemName = getItemName(namespace);
|
|
281
|
+
console.log(chalk_1.default.blue(`š Fetching ${itemName}...`));
|
|
282
|
+
const pager = (0, pager_1.createPager)({
|
|
283
|
+
pageSize: Math.min(limit, 20),
|
|
284
|
+
itemName,
|
|
285
|
+
});
|
|
286
|
+
const displayFunction = (items, totalShown, totalAvailable) => {
|
|
287
|
+
// Only clear screen if we have items to show
|
|
288
|
+
if (items.length > 0) {
|
|
289
|
+
console.clear();
|
|
290
|
+
}
|
|
291
|
+
console.log(chalk_1.default.blue(`š ${getListTitle(namespace)}\n`));
|
|
292
|
+
if (items.length === 0) {
|
|
293
|
+
console.log(chalk_1.default.yellow(`No ${itemName} found.`));
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
// Get the schema for this namespace/method to extract formatting info
|
|
297
|
+
const schema = schemas_1.SDKSchemas[namespace];
|
|
298
|
+
const listSchema = schema && typeof schema === "object" && "list" in schema
|
|
299
|
+
? schema.list
|
|
300
|
+
: null;
|
|
301
|
+
if (listSchema) {
|
|
302
|
+
(0, schema_formatter_1.formatItemsFromSchema)(listSchema, items);
|
|
303
|
+
}
|
|
304
|
+
else {
|
|
305
|
+
// Fallback to generic formatting
|
|
306
|
+
formatItemsGeneric(items);
|
|
307
|
+
}
|
|
308
|
+
const totalInfo = totalAvailable
|
|
309
|
+
? ` of ${totalAvailable.toLocaleString()} total`
|
|
310
|
+
: "";
|
|
311
|
+
console.log(chalk_1.default.green(`\nā
Showing ${totalShown}${totalInfo} ${itemName}`));
|
|
312
|
+
};
|
|
313
|
+
await pager.paginate((params) => sdk[namespace][method]({
|
|
314
|
+
...baseParams,
|
|
315
|
+
...params,
|
|
316
|
+
}), {}, displayFunction);
|
|
317
|
+
}
|
|
318
|
+
function formatNonPaginatedResults(namespace, result, requestedLimit, userSpecifiedLimit, useRawJSON) {
|
|
319
|
+
if (!Array.isArray(result)) {
|
|
320
|
+
if (useRawJSON) {
|
|
321
|
+
console.log(JSON.stringify(result, null, 2));
|
|
322
|
+
}
|
|
323
|
+
else {
|
|
324
|
+
formatJSONOutput(result);
|
|
325
|
+
}
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
if (useRawJSON) {
|
|
329
|
+
console.log(JSON.stringify(result, null, 2));
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
const itemName = getItemName(namespace);
|
|
333
|
+
if (result.length === 0) {
|
|
334
|
+
console.log(chalk_1.default.yellow(`No ${itemName} found.`));
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
console.log(chalk_1.default.green(`\nā
Found ${result.length} ${itemName}:\n`));
|
|
338
|
+
// Get the schema for this namespace/method to extract formatting info
|
|
339
|
+
const schema = schemas_1.SDKSchemas[namespace];
|
|
340
|
+
const listSchema = schema && typeof schema === "object" && "list" in schema
|
|
341
|
+
? schema.list
|
|
342
|
+
: null;
|
|
343
|
+
if (listSchema) {
|
|
344
|
+
(0, schema_formatter_1.formatItemsFromSchema)(listSchema, result);
|
|
345
|
+
}
|
|
346
|
+
else {
|
|
347
|
+
// Fallback to generic formatting
|
|
348
|
+
formatItemsGeneric(result);
|
|
349
|
+
}
|
|
350
|
+
// Show appropriate status message
|
|
351
|
+
if (userSpecifiedLimit && requestedLimit) {
|
|
352
|
+
console.log(chalk_1.default.gray(`\nš Showing up to ${requestedLimit} ${itemName} (--limit ${requestedLimit})`));
|
|
353
|
+
}
|
|
354
|
+
else {
|
|
355
|
+
console.log(chalk_1.default.gray(`\nš All available ${itemName} shown`));
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
function formatItemsGeneric(items) {
|
|
359
|
+
// Fallback formatting for items without schema metadata
|
|
360
|
+
items.forEach((item, index) => {
|
|
361
|
+
const name = item.name || item.key || item.id || "Item";
|
|
362
|
+
console.log(`${chalk_1.default.gray(`${index + 1}.`)} ${chalk_1.default.cyan(name)}`);
|
|
363
|
+
if (item.description) {
|
|
364
|
+
console.log(` ${chalk_1.default.dim(item.description)}`);
|
|
365
|
+
}
|
|
366
|
+
console.log();
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
function getItemName(namespace) {
|
|
370
|
+
switch (namespace) {
|
|
371
|
+
case "apps":
|
|
372
|
+
return "apps";
|
|
373
|
+
case "actions":
|
|
374
|
+
return "actions";
|
|
375
|
+
case "auths":
|
|
376
|
+
return "authentications";
|
|
377
|
+
case "fields":
|
|
378
|
+
return "fields";
|
|
379
|
+
default:
|
|
380
|
+
return "items";
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
function getListTitle(namespace) {
|
|
384
|
+
switch (namespace) {
|
|
385
|
+
case "apps":
|
|
386
|
+
return "Available Apps";
|
|
387
|
+
case "actions":
|
|
388
|
+
return "Available Actions";
|
|
389
|
+
case "auths":
|
|
390
|
+
return "Available Authentications";
|
|
391
|
+
case "fields":
|
|
392
|
+
return "Available Fields";
|
|
393
|
+
default:
|
|
394
|
+
return "Available Items";
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
// ============================================================================
|
|
398
|
+
// Help Text Enhancement
|
|
399
|
+
// ============================================================================
|
|
400
|
+
function enhanceCommandHelp(program) {
|
|
401
|
+
// Add custom help that shows schema-driven nature
|
|
402
|
+
program.on("--help", () => {
|
|
403
|
+
console.log("");
|
|
404
|
+
console.log("Commands are automatically generated from SDK schemas.");
|
|
405
|
+
console.log("Each command maps directly to an SDK method with the same parameters.");
|
|
406
|
+
console.log("");
|
|
407
|
+
console.log("Examples:");
|
|
408
|
+
console.log(" zapier-sdk apps list --category=productivity --limit=10");
|
|
409
|
+
console.log(' zapier-sdk actions run slack search user_by_email --inputs=\'{"email":"user@example.com"}\'');
|
|
410
|
+
console.log(" zapier-sdk generate my-app --output=./generated/");
|
|
411
|
+
console.log(" zsdk apps list --limit=5 # Using the shorter alias");
|
|
412
|
+
console.log("");
|
|
413
|
+
});
|
|
414
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export interface PagerOptions {
|
|
2
|
+
pageSize?: number;
|
|
3
|
+
showPrompt?: boolean;
|
|
4
|
+
itemName?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface PaginatedResult<T> {
|
|
7
|
+
items: T[];
|
|
8
|
+
hasMore: boolean;
|
|
9
|
+
totalShown: number;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Generic pager that handles pagination for any data source
|
|
13
|
+
* Supports interactive "load more" functionality
|
|
14
|
+
*/
|
|
15
|
+
export declare class Pager<T> {
|
|
16
|
+
private pageSize;
|
|
17
|
+
private showPrompt;
|
|
18
|
+
private itemName;
|
|
19
|
+
private allItems;
|
|
20
|
+
private currentOffset;
|
|
21
|
+
constructor(options?: PagerOptions);
|
|
22
|
+
/**
|
|
23
|
+
* Fetch and display paginated results with interactive loading
|
|
24
|
+
*/
|
|
25
|
+
paginate<TParams>(fetchFunction: (params: TParams & {
|
|
26
|
+
limit: number;
|
|
27
|
+
offset?: number;
|
|
28
|
+
}) => Promise<T[]>, baseParams: TParams, displayFunction: (items: T[], totalShown: number, totalAvailable?: number) => void): Promise<PaginatedResult<T>>;
|
|
29
|
+
/**
|
|
30
|
+
* Reset the pager state
|
|
31
|
+
*/
|
|
32
|
+
reset(): void;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Convenience function to create a pager for a specific use case
|
|
36
|
+
*/
|
|
37
|
+
export declare function createPager<T>(options?: PagerOptions): Pager<T>;
|
|
38
|
+
/**
|
|
39
|
+
* Simple pagination without interactivity - just fetches all results up to a limit
|
|
40
|
+
*/
|
|
41
|
+
export declare function fetchAllPages<T, TParams>(fetchFunction: (params: TParams & {
|
|
42
|
+
limit: number;
|
|
43
|
+
offset?: number;
|
|
44
|
+
}) => Promise<T[]>, baseParams: TParams, maxResults?: number): Promise<T[]>;
|
|
45
|
+
/**
|
|
46
|
+
* Display helper for showing pagination status
|
|
47
|
+
*/
|
|
48
|
+
export declare function showPaginationStatus(currentCount: number, requestedLimit: number, itemName?: string): void;
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.Pager = void 0;
|
|
7
|
+
exports.createPager = createPager;
|
|
8
|
+
exports.fetchAllPages = fetchAllPages;
|
|
9
|
+
exports.showPaginationStatus = showPaginationStatus;
|
|
10
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
11
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
12
|
+
/**
|
|
13
|
+
* Generic pager that handles pagination for any data source
|
|
14
|
+
* Supports interactive "load more" functionality
|
|
15
|
+
*/
|
|
16
|
+
class Pager {
|
|
17
|
+
constructor(options = {}) {
|
|
18
|
+
this.allItems = [];
|
|
19
|
+
this.currentOffset = 0;
|
|
20
|
+
this.pageSize = options.pageSize || 20;
|
|
21
|
+
this.showPrompt = options.showPrompt !== false;
|
|
22
|
+
this.itemName = options.itemName || "items";
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Fetch and display paginated results with interactive loading
|
|
26
|
+
*/
|
|
27
|
+
async paginate(fetchFunction, baseParams, displayFunction) {
|
|
28
|
+
let hasMore = true;
|
|
29
|
+
let totalAvailable;
|
|
30
|
+
while (hasMore) {
|
|
31
|
+
// Fetch next page
|
|
32
|
+
const params = {
|
|
33
|
+
...baseParams,
|
|
34
|
+
limit: this.pageSize,
|
|
35
|
+
offset: this.currentOffset,
|
|
36
|
+
};
|
|
37
|
+
try {
|
|
38
|
+
const items = await fetchFunction(params);
|
|
39
|
+
if (items.length === 0) {
|
|
40
|
+
// Still call display function to show "No items found" message
|
|
41
|
+
displayFunction(this.allItems, this.allItems.length, totalAvailable);
|
|
42
|
+
hasMore = false;
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
// Check for pagination metadata to get total count
|
|
46
|
+
const pagination = items.__pagination;
|
|
47
|
+
if (pagination && pagination.count) {
|
|
48
|
+
totalAvailable = pagination.count;
|
|
49
|
+
hasMore = pagination.hasNext;
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
// Fallback: check if we got fewer items than requested
|
|
53
|
+
hasMore = items.length >= this.pageSize;
|
|
54
|
+
}
|
|
55
|
+
// Add to our collection
|
|
56
|
+
this.allItems.push(...items);
|
|
57
|
+
this.currentOffset += items.length;
|
|
58
|
+
// Display current batch
|
|
59
|
+
displayFunction(this.allItems, this.allItems.length, totalAvailable);
|
|
60
|
+
// If prompting is disabled, continue automatically
|
|
61
|
+
if (!this.showPrompt) {
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
// If we have total count info, show more detailed prompt
|
|
65
|
+
const totalInfo = totalAvailable
|
|
66
|
+
? ` of ${totalAvailable.toLocaleString()}`
|
|
67
|
+
: "";
|
|
68
|
+
const message = `Load more ${this.itemName}? (${this.allItems.length}${totalInfo} shown so far)`;
|
|
69
|
+
// Ask user if they want to load more
|
|
70
|
+
const { loadMore } = await inquirer_1.default.prompt([
|
|
71
|
+
{
|
|
72
|
+
type: "confirm",
|
|
73
|
+
name: "loadMore",
|
|
74
|
+
message,
|
|
75
|
+
default: true,
|
|
76
|
+
},
|
|
77
|
+
]);
|
|
78
|
+
if (!loadMore) {
|
|
79
|
+
hasMore = false;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
// Re-throw the error to be handled by the caller
|
|
84
|
+
throw error;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return {
|
|
88
|
+
items: this.allItems,
|
|
89
|
+
hasMore: this.currentOffset > 0 && hasMore,
|
|
90
|
+
totalShown: this.allItems.length,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Reset the pager state
|
|
95
|
+
*/
|
|
96
|
+
reset() {
|
|
97
|
+
this.allItems = [];
|
|
98
|
+
this.currentOffset = 0;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
exports.Pager = Pager;
|
|
102
|
+
/**
|
|
103
|
+
* Convenience function to create a pager for a specific use case
|
|
104
|
+
*/
|
|
105
|
+
function createPager(options = {}) {
|
|
106
|
+
return new Pager(options);
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Simple pagination without interactivity - just fetches all results up to a limit
|
|
110
|
+
*/
|
|
111
|
+
async function fetchAllPages(fetchFunction, baseParams, maxResults = 100) {
|
|
112
|
+
const pageSize = Math.min(maxResults, 50); // Reasonable page size
|
|
113
|
+
const allItems = [];
|
|
114
|
+
let offset = 0;
|
|
115
|
+
while (allItems.length < maxResults) {
|
|
116
|
+
const remainingItems = maxResults - allItems.length;
|
|
117
|
+
const currentPageSize = Math.min(pageSize, remainingItems);
|
|
118
|
+
const params = {
|
|
119
|
+
...baseParams,
|
|
120
|
+
limit: currentPageSize,
|
|
121
|
+
offset,
|
|
122
|
+
};
|
|
123
|
+
const items = await fetchFunction(params);
|
|
124
|
+
if (items.length === 0) {
|
|
125
|
+
break; // No more data
|
|
126
|
+
}
|
|
127
|
+
allItems.push(...items);
|
|
128
|
+
offset += items.length;
|
|
129
|
+
// If we got fewer items than requested, we've reached the end
|
|
130
|
+
if (items.length < currentPageSize) {
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return allItems;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Display helper for showing pagination status
|
|
138
|
+
*/
|
|
139
|
+
function showPaginationStatus(currentCount, requestedLimit, itemName = "items") {
|
|
140
|
+
if (currentCount >= requestedLimit) {
|
|
141
|
+
console.log(chalk_1.default.yellow(`\nš Showing first ${currentCount} ${itemName} (limit: ${requestedLimit})`));
|
|
142
|
+
console.log(chalk_1.default.gray(`Use --limit to increase the limit, or add paging with --page`));
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
console.log(chalk_1.default.gray(`\nš Showing all ${currentCount} ${itemName}`));
|
|
146
|
+
}
|
|
147
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { ActionsSDK } from "@zapier/actions-sdk";
|
|
3
|
+
export declare class SchemaParameterResolver {
|
|
4
|
+
resolveParameters(schema: z.ZodSchema, providedParams: any, sdk: ActionsSDK): Promise<any>;
|
|
5
|
+
private findAllResolvableParameters;
|
|
6
|
+
private findResolvableParameters;
|
|
7
|
+
private analyzeSchema;
|
|
8
|
+
private analyzeSchemaField;
|
|
9
|
+
private sortByDependencies;
|
|
10
|
+
private resolveParameter;
|
|
11
|
+
private promptStaticInput;
|
|
12
|
+
private resolveDynamicParameter;
|
|
13
|
+
private resolveFieldsParameter;
|
|
14
|
+
private promptForField;
|
|
15
|
+
private getNestedValue;
|
|
16
|
+
private setNestedValue;
|
|
17
|
+
private isUserCancellation;
|
|
18
|
+
}
|