@zapier/zapier-sdk-cli 0.8.4 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +35 -51
  3. package/dist/cli.cjs +950 -433
  4. package/dist/cli.mjs +951 -434
  5. package/dist/index.cjs +729 -336
  6. package/dist/index.mjs +730 -337
  7. package/dist/package.json +1 -1
  8. package/dist/src/plugins/add/ast-generator.d.ts +37 -0
  9. package/dist/src/plugins/add/ast-generator.js +403 -0
  10. package/dist/src/plugins/add/index.d.ts +13 -0
  11. package/dist/src/plugins/add/index.js +120 -0
  12. package/dist/src/plugins/add/schemas.d.ts +18 -0
  13. package/dist/src/plugins/add/schemas.js +19 -0
  14. package/dist/src/plugins/getLoginConfigPath/index.d.ts +15 -0
  15. package/dist/src/plugins/getLoginConfigPath/index.js +19 -0
  16. package/dist/src/plugins/getLoginConfigPath/schemas.d.ts +3 -0
  17. package/dist/src/plugins/getLoginConfigPath/schemas.js +5 -0
  18. package/dist/src/plugins/index.d.ts +2 -2
  19. package/dist/src/plugins/index.js +2 -2
  20. package/dist/src/sdk.js +3 -3
  21. package/dist/src/utils/cli-generator-utils.d.ts +2 -1
  22. package/dist/src/utils/cli-generator-utils.js +11 -5
  23. package/dist/src/utils/cli-generator.js +65 -65
  24. package/dist/src/utils/parameter-resolver.d.ts +4 -1
  25. package/dist/src/utils/parameter-resolver.js +92 -15
  26. package/dist/src/utils/schema-formatter.d.ts +5 -1
  27. package/dist/src/utils/schema-formatter.js +48 -18
  28. package/dist/tsconfig.tsbuildinfo +1 -1
  29. package/package.json +4 -4
  30. package/src/plugins/add/ast-generator.ts +777 -0
  31. package/src/plugins/add/index.test.ts +58 -0
  32. package/src/plugins/add/index.ts +187 -0
  33. package/src/plugins/add/schemas.ts +26 -0
  34. package/src/plugins/getLoginConfigPath/index.ts +45 -0
  35. package/src/plugins/getLoginConfigPath/schemas.ts +10 -0
  36. package/src/plugins/index.ts +2 -2
  37. package/src/sdk.ts +4 -4
  38. package/src/utils/cli-generator-utils.ts +17 -5
  39. package/src/utils/cli-generator.ts +90 -79
  40. package/src/utils/parameter-resolver.ts +155 -21
  41. package/src/utils/schema-formatter.ts +68 -33
  42. package/tsup.config.ts +1 -1
  43. package/dist/src/plugins/generateTypes/index.d.ts +0 -21
  44. package/dist/src/plugins/generateTypes/index.js +0 -312
  45. package/dist/src/plugins/generateTypes/schemas.d.ts +0 -18
  46. package/dist/src/plugins/generateTypes/schemas.js +0 -14
  47. package/dist/src/plugins/getConfigPath/index.d.ts +0 -15
  48. package/dist/src/plugins/getConfigPath/index.js +0 -19
  49. package/dist/src/plugins/getConfigPath/schemas.d.ts +0 -3
  50. package/dist/src/plugins/getConfigPath/schemas.js +0 -5
  51. package/src/plugins/generateTypes/index.ts +0 -444
  52. package/src/plugins/generateTypes/schemas.ts +0 -23
  53. package/src/plugins/getConfigPath/index.ts +0 -42
  54. package/src/plugins/getConfigPath/schemas.ts +0 -8
@@ -1,444 +0,0 @@
1
- import type {
2
- Action,
3
- ActionField,
4
- ActionItem,
5
- Plugin,
6
- GetSdkType,
7
- ListActionsPluginProvides,
8
- ListInputFieldsPluginProvides,
9
- ManifestPluginProvides,
10
- } from "@zapier/zapier-sdk";
11
- import { GenerateTypesSchema, type GenerateTypesOptions } from "./schemas";
12
- import { createFunction } from "@zapier/zapier-sdk";
13
- import * as fs from "fs";
14
- import * as path from "path";
15
-
16
- export interface GenerateTypesPluginProvides {
17
- generateTypes: (options: GenerateTypesOptions) => Promise<string>;
18
- context: {
19
- meta: {
20
- generateTypes: {
21
- inputSchema: typeof GenerateTypesSchema;
22
- };
23
- };
24
- };
25
- }
26
-
27
- export const generateTypesPlugin: Plugin<
28
- GetSdkType<
29
- ListActionsPluginProvides &
30
- ListInputFieldsPluginProvides &
31
- ManifestPluginProvides
32
- >, // requires these SDK methods
33
- {}, // requires no context
34
- GenerateTypesPluginProvides
35
- > = ({ sdk }) => {
36
- const generateTypesWithSdk = createFunction(
37
- async function generateTypesWithSdk(
38
- options: GenerateTypesOptions,
39
- ): Promise<string> {
40
- return await generateTypes({ ...options, sdk });
41
- },
42
- GenerateTypesSchema,
43
- );
44
-
45
- return {
46
- generateTypes: generateTypesWithSdk,
47
- context: {
48
- meta: {
49
- generateTypes: {
50
- categories: ["utility"],
51
- inputSchema: GenerateTypesSchema,
52
- },
53
- },
54
- },
55
- };
56
- };
57
-
58
- interface ActionWithActionFields extends Omit<Action, "inputFields" | "type"> {
59
- inputFields: ActionField[];
60
- app_key: string;
61
- action_type: Action["type"];
62
- title: string;
63
- type: "action";
64
- }
65
-
66
- /**
67
- * Generate the fetch method signature for app proxies
68
- */
69
- function generateFetchMethodSignature(): string {
70
- return ` /** Make authenticated HTTP requests through Zapier's Relay service */
71
- fetch: (options: Omit<z.infer<typeof RelayFetchSchema>, 'authenticationId'>) => Promise<Response>`;
72
- }
73
-
74
- /**
75
- * Generate TypeScript types for a specific app (CLI version)
76
- */
77
- export async function generateTypes(
78
- options: GenerateTypesOptions & {
79
- sdk: GetSdkType<
80
- ListActionsPluginProvides &
81
- ListInputFieldsPluginProvides &
82
- ManifestPluginProvides
83
- >;
84
- },
85
- ): Promise<string> {
86
- const {
87
- appKey,
88
- authenticationId,
89
- output = `./types/${appKey}.d.ts`,
90
- sdk,
91
- } = options;
92
-
93
- // Parse app identifier (support app@version format)
94
- const { app, version } = parseAppIdentifier(appKey);
95
-
96
- // Fetch all actions for the app
97
- const actionsResult = await sdk.listActions({
98
- appKey: app,
99
- });
100
-
101
- const actions = actionsResult.data;
102
-
103
- if (actions.length === 0) {
104
- const typeDefinitions = generateEmptyTypesFile(app, version);
105
-
106
- if (output) {
107
- fs.mkdirSync(path.dirname(output), { recursive: true });
108
- fs.writeFileSync(output, typeDefinitions, "utf8");
109
- }
110
-
111
- return typeDefinitions;
112
- }
113
-
114
- // Fetch input fields for each action
115
- const actionsWithFields: ActionWithActionFields[] = [];
116
-
117
- if (authenticationId) {
118
- for (const action of actions) {
119
- try {
120
- // Check to see if the appKey is in the manifest
121
- const manifestEntry = sdk.getContext().getManifestEntry(appKey);
122
-
123
- const fieldsResult = await sdk.listInputFields({
124
- // 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
125
- appKey: manifestEntry ? appKey : action.app_key,
126
- actionKey: action.key,
127
- actionType: action.action_type,
128
- authenticationId: authenticationId,
129
- });
130
-
131
- const fields = fieldsResult.data.map((field: unknown): ActionField => {
132
- const fieldObj = field as {
133
- is_required?: boolean;
134
- required?: boolean;
135
- [key: string]: unknown;
136
- };
137
- return {
138
- ...fieldObj,
139
- required: fieldObj.is_required || fieldObj.required || false,
140
- } as ActionField;
141
- });
142
- actionsWithFields.push({
143
- ...action,
144
- inputFields: fields,
145
- name: action.title || action.key,
146
- });
147
- } catch {
148
- // If we can't get fields for an action, include it without fields
149
- actionsWithFields.push({
150
- ...action,
151
- inputFields: [],
152
- name: action.title || action.key,
153
- });
154
- }
155
- }
156
- } else {
157
- // Convert actions to have empty input fields (will generate generic types)
158
- actions.forEach((action: ActionItem) => {
159
- actionsWithFields.push({
160
- ...action,
161
- inputFields: [],
162
- name: action.title || action.key,
163
- });
164
- });
165
- }
166
-
167
- // Generate TypeScript types
168
- const typeDefinitions = generateTypeDefinitions(
169
- app,
170
- actionsWithFields,
171
- version,
172
- );
173
-
174
- // Write to file if output path specified
175
- if (output) {
176
- fs.mkdirSync(path.dirname(output), { recursive: true });
177
- fs.writeFileSync(output, typeDefinitions, "utf8");
178
- }
179
-
180
- return typeDefinitions;
181
- }
182
-
183
- function parseAppIdentifier(identifier: string): {
184
- app: string;
185
- version?: string;
186
- } {
187
- const parts = identifier.split("@");
188
- return {
189
- app: parts[0],
190
- version: parts[1],
191
- };
192
- }
193
-
194
- function generateTypeDefinitions(
195
- appKey: string,
196
- actions: ActionWithActionFields[],
197
- version?: string,
198
- ): string {
199
- // Handle empty actions
200
- if (actions.length === 0) {
201
- return generateEmptyTypesFile(appKey, version);
202
- }
203
-
204
- // Group actions by type
205
- const actionsByType = actions.reduce(
206
- (acc, action) => {
207
- if (!acc[action.action_type]) {
208
- acc[action.action_type] = [];
209
- }
210
- acc[action.action_type].push(action);
211
- return acc;
212
- },
213
- {} as Record<string, ActionWithActionFields[]>,
214
- );
215
-
216
- const appName = capitalize(appKey);
217
- const versionComment = version
218
- ? ` * Generated for ${appKey}@${version}`
219
- : ` * Generated for ${appKey}`;
220
-
221
- let output = `/* eslint-disable @typescript-eslint/naming-convention */
222
- /**
223
- * Auto-generated TypeScript types for Zapier ${appKey} actions
224
- ${versionComment}
225
- * Generated on: ${new Date().toISOString()}
226
- *
227
- * Usage:
228
- * import type { ${appName}Sdk } from './path/to/this/file'
229
- * const sdk = createZapierSdk() as unknown as ${appName}Sdk
230
- *
231
- * // Direct usage (per-call auth):
232
- * await sdk.apps.${appKey}.search.user_by_email({ authenticationId: 123, inputs: { email } })
233
- *
234
- * // Factory usage (pinned auth):
235
- * const my${appName} = sdk.apps.${appKey}({ authenticationId: 123 })
236
- * await my${appName}.search.user_by_email({ inputs: { email } })
237
- */
238
-
239
- import type { ActionExecutionOptions, ActionExecutionResult } from '@zapier/zapier-sdk'
240
- import { z } from 'zod'
241
- import { RelayFetchSchema } from '@zapier/zapier-sdk'
242
-
243
- `;
244
-
245
- // Generate input types for each action
246
- actions.forEach((action) => {
247
- if (action.inputFields.length > 0) {
248
- const inputTypeName = `${appName}${capitalize(action.action_type)}${capitalize(
249
- sanitizeActionName(action.key),
250
- )}Inputs`;
251
-
252
- output += `interface ${inputTypeName} {\n`;
253
-
254
- action.inputFields.forEach((field) => {
255
- const isOptional = !field.required;
256
- const fieldType = mapFieldTypeToTypeScript(field);
257
- const description = field.helpText
258
- ? ` /** ${escapeComment(field.helpText)} */\n`
259
- : "";
260
-
261
- output += `${description} ${sanitizeFieldName(field.key)}${
262
- isOptional ? "?" : ""
263
- }: ${fieldType}\n`;
264
- });
265
-
266
- output += `}\n\n`;
267
- }
268
- });
269
-
270
- // Generate action type interfaces for each action type
271
- Object.entries(actionsByType).forEach(([actionType, typeActions]) => {
272
- const typeName = `${appName}${capitalize(actionType)}Actions`;
273
-
274
- output += `interface ${typeName} {\n`;
275
-
276
- typeActions.forEach((action: ActionWithActionFields) => {
277
- const actionName = sanitizeActionName(action.key);
278
- const description = action.description
279
- ? ` /** ${escapeComment(action.description)} */\n`
280
- : "";
281
-
282
- // Generate type-safe action method signature
283
- if (action.inputFields.length > 0) {
284
- const inputTypeName = `${appName}${capitalize(action.action_type)}${capitalize(
285
- sanitizeActionName(action.key),
286
- )}Inputs`;
287
- output += `${description} ${actionName}: (options: { inputs: ${inputTypeName} } & Omit<ActionExecutionOptions, 'inputs'>) => Promise<ActionExecutionResult>\n`;
288
- } else {
289
- // No specific input fields available - use generic Record<string, any> for inputs
290
- output += `${description} ${actionName}: (options?: { inputs?: Record<string, any> } & ActionExecutionOptions) => Promise<ActionExecutionResult>\n`;
291
- }
292
- });
293
-
294
- output += `}\n\n`;
295
- });
296
-
297
- // Generate the main app SDK interface with factory pattern support
298
-
299
- // Generate the app proxy interface (actions grouped by type)
300
- output += `interface ${appName}AppProxy {\n`;
301
- Object.keys(actionsByType).forEach((actionType) => {
302
- const typeName = `${appName}${capitalize(actionType)}Actions`;
303
- output += ` ${actionType}: ${typeName}\n`;
304
- });
305
- // Always include fetch method for authenticated HTTP requests
306
- output += generateFetchMethodSignature() + "\n";
307
- output += `}\n\n`;
308
-
309
- // Generate the factory function interface
310
- output += `interface ${appName}AppFactory {\n`;
311
- output += ` (options: { authenticationId: number }): ${appName}AppProxy\n`;
312
- output += `}\n\n`;
313
-
314
- // Combine factory and direct access
315
- output += `type ${appName}AppWithFactory = ${appName}AppFactory & ${appName}AppProxy\n\n`;
316
-
317
- // Generate the main SDK interface
318
- output += `export interface ${appName}Sdk {\n`;
319
- output += ` apps: {\n`;
320
- output += ` ${appKey}: ${appName}AppWithFactory\n`;
321
- output += ` }\n`;
322
- output += `}\n`;
323
-
324
- return output;
325
- }
326
-
327
- function generateEmptyTypesFile(appKey: string, version?: string): string {
328
- const appName = capitalize(appKey);
329
- const versionComment = version
330
- ? ` * Generated for ${appKey}@${version}`
331
- : ` * Generated for ${appKey}`;
332
-
333
- return `/* eslint-disable @typescript-eslint/naming-convention */
334
- /**
335
- * Auto-generated TypeScript types for Zapier ${appKey} actions
336
- ${versionComment}
337
- * Generated on: ${new Date().toISOString()}
338
- *
339
- * No actions found for this app.
340
- */
341
-
342
- import type { ActionExecutionOptions, ActionExecutionResult } from '@zapier/zapier-sdk'
343
- import { z } from 'zod'
344
- import { RelayFetchSchema } from '@zapier/zapier-sdk'
345
-
346
- interface ${appName}AppProxy {
347
- // No actions available
348
- ${generateFetchMethodSignature()}
349
- }
350
-
351
- interface ${appName}AppFactory {
352
- (options: { authenticationId: number }): ${appName}AppProxy
353
- }
354
-
355
- type ${appName}AppWithFactory = ${appName}AppFactory & ${appName}AppProxy
356
-
357
- export interface ${appName}Sdk {
358
- apps: {
359
- ${appKey}: ${appName}AppWithFactory
360
- }
361
- }
362
- `;
363
- }
364
-
365
- function capitalize(str: string): string {
366
- return str.charAt(0).toUpperCase() + str.slice(1).replace(/[-_]/g, "");
367
- }
368
-
369
- function sanitizeActionName(actionKey: string): string {
370
- // Ensure the action name is a valid TypeScript identifier
371
- let sanitized = actionKey.replace(/[^a-zA-Z0-9_$]/g, "_");
372
-
373
- // If it starts with a number, prepend an underscore
374
- if (/^[0-9]/.test(sanitized)) {
375
- sanitized = "_" + sanitized;
376
- }
377
-
378
- return sanitized;
379
- }
380
-
381
- function sanitizeFieldName(fieldKey: string): string {
382
- // Ensure the field name is a valid TypeScript identifier
383
- let sanitized = fieldKey.replace(/[^a-zA-Z0-9_$]/g, "_");
384
-
385
- // If it starts with a number, prepend an underscore
386
- if (/^[0-9]/.test(sanitized)) {
387
- sanitized = "_" + sanitized;
388
- }
389
-
390
- return sanitized;
391
- }
392
-
393
- function escapeComment(comment: string): string {
394
- // Escape comment text to prevent breaking the JSDoc comment
395
- return comment.replace(/\*\//g, "*\\/").replace(/\r?\n/g, " ");
396
- }
397
-
398
- function mapFieldTypeToTypeScript(field: ActionField): string {
399
- // Handle choices (enum-like fields)
400
- if (field.choices && field.choices.length > 0) {
401
- const choiceValues = field.choices
402
- .filter(
403
- (choice) =>
404
- choice.value !== undefined &&
405
- choice.value !== null &&
406
- choice.value !== "",
407
- )
408
- .map((choice) =>
409
- typeof choice.value === "string" ? `"${choice.value}"` : choice.value,
410
- );
411
-
412
- if (choiceValues.length > 0) {
413
- return choiceValues.join(" | ");
414
- }
415
- // If all choices were filtered out, fall through to default type handling
416
- }
417
-
418
- // Map Zapier field types to TypeScript types
419
- switch (field.type?.toLowerCase()) {
420
- case "string":
421
- case "text":
422
- case "email":
423
- case "url":
424
- case "password":
425
- return "string";
426
- case "integer":
427
- case "number":
428
- return "number";
429
- case "boolean":
430
- return "boolean";
431
- case "datetime":
432
- case "date":
433
- return "string"; // ISO date strings
434
- case "file":
435
- return "string"; // File URL or content
436
- case "array":
437
- return "any[]";
438
- case "object":
439
- return "Record<string, any>";
440
- default:
441
- // Default to string for unknown types, with union for common cases
442
- return "string | number | boolean";
443
- }
444
- }
@@ -1,23 +0,0 @@
1
- import { z } from "zod";
2
- import {
3
- AppKeyPropertySchema,
4
- AuthenticationIdPropertySchema,
5
- OutputPropertySchema,
6
- } from "@zapier/zapier-sdk";
7
-
8
- // Generate types schema - mirrors the original from SDK but for CLI use
9
- export const GenerateTypesSchema = z
10
- .object({
11
- appKey: AppKeyPropertySchema.describe("App key to generate SDK code for"),
12
- authenticationId: AuthenticationIdPropertySchema.optional(),
13
- output: OutputPropertySchema.optional().describe(
14
- "Output file path (defaults to generated/<appKey>.ts)",
15
- ),
16
- lockFilePath: z
17
- .string()
18
- .optional()
19
- .describe("Path to the .zapierrc lock file (defaults to .zapierrc)"),
20
- })
21
- .describe("Generate TypeScript SDK code for a specific app");
22
-
23
- export type GenerateTypesOptions = z.infer<typeof GenerateTypesSchema>;
@@ -1,42 +0,0 @@
1
- import type { Plugin } from "@zapier/zapier-sdk";
2
- import { GetConfigPathSchema, type GetConfigPathOptions } from "./schemas";
3
- import { createFunction } from "@zapier/zapier-sdk";
4
- import { getConfigPath } from "@zapier/zapier-sdk-cli-login";
5
-
6
- export interface GetConfigPathPluginProvides {
7
- getConfigPath: (options?: GetConfigPathOptions) => Promise<string>;
8
- context: {
9
- meta: {
10
- getConfigPath: {
11
- inputSchema: typeof GetConfigPathSchema;
12
- };
13
- };
14
- };
15
- }
16
-
17
- export const getConfigPathPlugin: Plugin<
18
- {}, // requires no existing SDK methods
19
- {}, // requires no context
20
- GetConfigPathPluginProvides
21
- > = () => {
22
- const getConfigPathWithSdk = createFunction(
23
- async function getConfigPathWithSdk(
24
- _options?: GetConfigPathOptions,
25
- ): Promise<string> {
26
- return getConfigPath();
27
- },
28
- GetConfigPathSchema,
29
- );
30
-
31
- return {
32
- getConfigPath: getConfigPathWithSdk,
33
- context: {
34
- meta: {
35
- getConfigPath: {
36
- categories: ["utility"],
37
- inputSchema: GetConfigPathSchema,
38
- },
39
- },
40
- },
41
- };
42
- };
@@ -1,8 +0,0 @@
1
- import { z } from "zod";
2
-
3
- // Get config path schema - simple command with no parameters
4
- export const GetConfigPathSchema = z
5
- .object({})
6
- .describe("Show the path to the configuration file");
7
-
8
- export type GetConfigPathOptions = z.infer<typeof GetConfigPathSchema>;