@zapier/zapier-sdk-cli 0.4.0 → 0.4.2

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 (70) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/cli.js +961 -284
  3. package/dist/src/cli.d.ts +2 -0
  4. package/dist/src/cli.js +28 -0
  5. package/dist/src/commands/bundle-code/cli.d.ts +2 -0
  6. package/dist/src/commands/bundle-code/cli.js +77 -0
  7. package/dist/src/commands/bundle-code/index.d.ts +5 -0
  8. package/dist/src/commands/bundle-code/index.js +62 -0
  9. package/dist/src/commands/bundle-code/schemas.d.ts +24 -0
  10. package/dist/src/commands/bundle-code/schemas.js +19 -0
  11. package/dist/src/commands/configPath.d.ts +2 -0
  12. package/dist/src/commands/configPath.js +9 -0
  13. package/dist/src/commands/generate-types/cli.d.ts +2 -0
  14. package/dist/src/commands/generate-types/cli.js +73 -0
  15. package/dist/src/commands/generate-types/index.d.ts +8 -0
  16. package/dist/src/commands/generate-types/index.js +273 -0
  17. package/dist/src/commands/generate-types/schemas.d.ts +18 -0
  18. package/dist/src/commands/generate-types/schemas.js +11 -0
  19. package/dist/src/commands/index.d.ts +6 -0
  20. package/dist/src/commands/index.js +6 -0
  21. package/dist/src/commands/login.d.ts +2 -0
  22. package/dist/src/commands/login.js +25 -0
  23. package/dist/src/commands/logout.d.ts +2 -0
  24. package/dist/src/commands/logout.js +16 -0
  25. package/dist/src/commands/mcp.d.ts +2 -0
  26. package/dist/src/commands/mcp.js +11 -0
  27. package/dist/src/index.d.ts +0 -0
  28. package/dist/src/index.js +3 -0
  29. package/dist/src/utils/api/client.d.ts +15 -0
  30. package/dist/src/utils/api/client.js +27 -0
  31. package/dist/src/utils/auth/login.d.ts +2 -0
  32. package/dist/src/utils/auth/login.js +134 -0
  33. package/dist/src/utils/cli-generator-utils.d.ts +13 -0
  34. package/dist/src/utils/cli-generator-utils.js +116 -0
  35. package/dist/src/utils/cli-generator.d.ts +3 -0
  36. package/dist/src/utils/cli-generator.js +443 -0
  37. package/dist/src/utils/constants.d.ts +5 -0
  38. package/dist/src/utils/constants.js +6 -0
  39. package/dist/src/utils/getCallablePromise.d.ts +6 -0
  40. package/dist/src/utils/getCallablePromise.js +14 -0
  41. package/dist/src/utils/log.d.ts +7 -0
  42. package/dist/src/utils/log.js +16 -0
  43. package/dist/src/utils/parameter-resolver.d.ts +14 -0
  44. package/dist/src/utils/parameter-resolver.js +387 -0
  45. package/dist/src/utils/schema-formatter.d.ts +2 -0
  46. package/dist/src/utils/schema-formatter.js +71 -0
  47. package/dist/src/utils/serializeAsync.d.ts +2 -0
  48. package/dist/src/utils/serializeAsync.js +16 -0
  49. package/dist/src/utils/spinner.d.ts +1 -0
  50. package/dist/src/utils/spinner.js +13 -0
  51. package/dist/tsconfig.tsbuildinfo +1 -0
  52. package/package.json +5 -3
  53. package/src/cli.test.ts +15 -0
  54. package/src/cli.ts +9 -3
  55. package/src/commands/bundle-code/cli.ts +103 -0
  56. package/src/commands/bundle-code/index.ts +91 -0
  57. package/src/commands/bundle-code/schemas.ts +24 -0
  58. package/src/commands/generate-types/cli.ts +110 -0
  59. package/src/commands/generate-types/index.ts +365 -0
  60. package/src/commands/generate-types/schemas.ts +23 -0
  61. package/src/commands/index.ts +3 -1
  62. package/src/commands/mcp.ts +14 -0
  63. package/src/utils/cli-generator-utils.ts +157 -0
  64. package/src/utils/cli-generator.ts +148 -91
  65. package/src/utils/parameter-resolver.ts +217 -85
  66. package/src/utils/schema-formatter.ts +1 -1
  67. package/tsconfig.json +3 -5
  68. package/src/commands/whoami.ts +0 -25
  69. package/src/utils/pager.ts +0 -202
  70. package/test/cli.test.ts +0 -46
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from "commander";
3
+ import { createZapierSdk } from "@zapier/zapier-sdk";
4
+ import { generateCliCommands } from "./utils/cli-generator";
5
+ import { createLoginCommand, createLogoutCommand, createConfigPathCommand, createGenerateTypesCommand, createBundleCodeCommand, createMcpCommand, } from "./commands/index";
6
+ const program = new Command();
7
+ program
8
+ .name("zapier-sdk")
9
+ .description("CLI for Zapier SDK - Commands auto-generated from SDK schemas")
10
+ .version("1.0.0")
11
+ .option("--debug", "Enable debug logging");
12
+ // Check for debug flag early
13
+ const isDebugMode = process.env.DEBUG === "true" || process.argv.includes("--debug");
14
+ // Create SDK instance - automatically handles token resolution
15
+ const sdk = createZapierSdk({
16
+ debug: isDebugMode,
17
+ });
18
+ // Add auth commands before generating SDK commands
19
+ program.addCommand(createLoginCommand());
20
+ program.addCommand(createLogoutCommand());
21
+ // Generate CLI commands from SDK schemas
22
+ generateCliCommands(program, sdk);
23
+ // Add build-time commands (CLI-specific, not from SDK)
24
+ program.addCommand(createGenerateTypesCommand());
25
+ program.addCommand(createBundleCodeCommand());
26
+ program.addCommand(createConfigPathCommand());
27
+ program.addCommand(createMcpCommand());
28
+ program.parse();
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare function createBundleCodeCommand(): Command;
@@ -0,0 +1,77 @@
1
+ import { Command } from "commander";
2
+ import { BundleCodeSchema } from "./schemas";
3
+ import { bundleCode } from "./index";
4
+ import chalk from "chalk";
5
+ import { analyzeZodSchema, convertCliArgsToSdkParams, } from "../../utils/cli-generator-utils";
6
+ export function createBundleCodeCommand() {
7
+ const parameters = analyzeZodSchema(BundleCodeSchema);
8
+ const description = BundleCodeSchema.description ||
9
+ "Bundle TypeScript code into executable JavaScript";
10
+ const command = new Command("bundle-code").description(description);
11
+ // Add parameters to command using same logic as CLI generator
12
+ parameters.forEach((param) => {
13
+ // Convert camelCase to kebab-case for CLI display
14
+ const kebabName = param.name.replace(/([A-Z])/g, "-$1").toLowerCase();
15
+ if (param.hasResolver && param.required) {
16
+ // Required parameters with resolvers become optional positional arguments (resolver handles prompting)
17
+ command.argument(`[${kebabName}]`, param.description || `${kebabName} parameter`);
18
+ }
19
+ else if (param.required) {
20
+ // Required parameters without resolvers become required positional arguments
21
+ command.argument(`<${kebabName}>`, param.description || `${kebabName} parameter`);
22
+ }
23
+ else if (param.isPositional) {
24
+ // Optional parameters marked as positional become optional positional arguments
25
+ command.argument(`[${kebabName}]`, param.description || `${kebabName} parameter`);
26
+ }
27
+ else {
28
+ // Optional parameters become flags (whether they have resolvers or not)
29
+ const flags = [`--${kebabName}`];
30
+ if (param.type === "boolean") {
31
+ command.option(flags.join(", "), param.description);
32
+ }
33
+ else {
34
+ const flagSignature = flags.join(", ") + ` <${param.type}>`;
35
+ command.option(flagSignature, param.description, param.default);
36
+ }
37
+ }
38
+ });
39
+ // Add formatting options like other commands
40
+ command.option("--json", "Output raw JSON instead of formatted results");
41
+ command.action(async (...args) => {
42
+ try {
43
+ // The last argument is always the command object with parsed options
44
+ const commandObj = args[args.length - 1];
45
+ const options = commandObj.opts();
46
+ // Convert CLI args to SDK method parameters
47
+ const rawParams = convertCliArgsToSdkParams(parameters, args.slice(0, -1), options);
48
+ // No parameter resolution needed for bundle-code since it doesn't use SDK
49
+ if (!rawParams.input) {
50
+ throw new Error("Input file path is required");
51
+ }
52
+ console.log(chalk.blue(`📦 Bundling ${rawParams.input}...`));
53
+ // Call our implementation
54
+ const result = await bundleCode(rawParams);
55
+ if (options.json) {
56
+ console.log(JSON.stringify({ result }, null, 2));
57
+ }
58
+ else if (rawParams.output && !rawParams.string) {
59
+ console.log(chalk.green("✅ Bundle created successfully!"));
60
+ console.log(chalk.gray(`Output written to: ${rawParams.output}`));
61
+ }
62
+ else if (rawParams.string) {
63
+ console.log(chalk.green("✅ Bundle generated as string!"));
64
+ console.log("\n" + result);
65
+ }
66
+ else {
67
+ console.log(chalk.green("✅ Bundle completed!"));
68
+ console.log("\n" + result);
69
+ }
70
+ }
71
+ catch (error) {
72
+ console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
73
+ process.exit(1);
74
+ }
75
+ });
76
+ return command;
77
+ }
@@ -0,0 +1,5 @@
1
+ import type { BundleCodeOptions } from "./schemas";
2
+ /**
3
+ * Bundle TypeScript code into executable JavaScript (CLI version)
4
+ */
5
+ export declare function bundleCode(options: BundleCodeOptions): Promise<string>;
@@ -0,0 +1,62 @@
1
+ import { buildSync } from "esbuild";
2
+ import * as fs from "fs";
3
+ import * as path from "path";
4
+ class ZapierBundleError extends Error {
5
+ constructor(message, details, originalError) {
6
+ super(message);
7
+ this.code = "ZAPIER_BUNDLE_ERROR";
8
+ this.name = "ZapierBundleError";
9
+ this.details = details;
10
+ this.originalError = originalError;
11
+ }
12
+ }
13
+ /**
14
+ * Bundle TypeScript code into executable JavaScript (CLI version)
15
+ */
16
+ export async function bundleCode(options) {
17
+ const { input, output, target = "es2020", cjs = false, minify = false, string: returnString = false, } = options;
18
+ // Resolve input path
19
+ const resolvedInput = path.resolve(process.cwd(), input);
20
+ try {
21
+ // Bundle with esbuild
22
+ const result = buildSync({
23
+ entryPoints: [resolvedInput],
24
+ bundle: true,
25
+ platform: "node",
26
+ target: target,
27
+ format: cjs ? "cjs" : "esm",
28
+ minify: minify,
29
+ write: false,
30
+ external: [], // Bundle everything
31
+ banner: {
32
+ js: "#!/usr/bin/env node",
33
+ },
34
+ });
35
+ if (result.errors.length > 0) {
36
+ const errorMessages = result.errors.map((e) => e.text);
37
+ throw new ZapierBundleError(`Bundle failed: ${errorMessages.join(", ")}`, errorMessages);
38
+ }
39
+ const bundledCode = result.outputFiles?.[0]?.text;
40
+ if (!bundledCode) {
41
+ throw new ZapierBundleError("No output generated");
42
+ }
43
+ let finalOutput = bundledCode;
44
+ if (returnString) {
45
+ // Output as quoted string for node -e using JSON.stringify
46
+ finalOutput = JSON.stringify(bundledCode);
47
+ }
48
+ // Write to file if output path specified
49
+ if (output) {
50
+ fs.mkdirSync(path.dirname(output), { recursive: true });
51
+ fs.writeFileSync(output, finalOutput, "utf8");
52
+ }
53
+ return finalOutput;
54
+ }
55
+ catch (error) {
56
+ // If it's already a ZapierBundleError, re-throw as-is
57
+ if (error instanceof ZapierBundleError) {
58
+ throw error;
59
+ }
60
+ throw new ZapierBundleError(`Bundle failed: ${error instanceof Error ? error.message : "Unknown error"}`, undefined, error instanceof Error ? error : undefined);
61
+ }
62
+ }
@@ -0,0 +1,24 @@
1
+ import { z } from "zod";
2
+ export declare const BundleCodeSchema: z.ZodObject<{
3
+ input: z.ZodString;
4
+ output: z.ZodOptional<z.ZodString>;
5
+ string: z.ZodDefault<z.ZodBoolean>;
6
+ minify: z.ZodDefault<z.ZodBoolean>;
7
+ target: z.ZodDefault<z.ZodString>;
8
+ cjs: z.ZodDefault<z.ZodBoolean>;
9
+ }, "strip", z.ZodTypeAny, {
10
+ string: boolean;
11
+ input: string;
12
+ minify: boolean;
13
+ target: string;
14
+ cjs: boolean;
15
+ output?: string | undefined;
16
+ }, {
17
+ input: string;
18
+ string?: boolean | undefined;
19
+ output?: string | undefined;
20
+ minify?: boolean | undefined;
21
+ target?: string | undefined;
22
+ cjs?: boolean | undefined;
23
+ }>;
24
+ export type BundleCodeOptions = z.infer<typeof BundleCodeSchema>;
@@ -0,0 +1,19 @@
1
+ import { z } from "zod";
2
+ import { OutputPropertySchema } from "@zapier/zapier-sdk";
3
+ // Bundle code schema - mirrors the original from SDK but for CLI use
4
+ export const BundleCodeSchema = z
5
+ .object({
6
+ input: z.string().min(1).describe("Input TypeScript file path to bundle"),
7
+ output: OutputPropertySchema.optional().describe("Output file path (defaults to input with .js extension)"),
8
+ string: z
9
+ .boolean()
10
+ .default(false)
11
+ .describe("Return bundled code as string instead of writing to file"),
12
+ minify: z.boolean().default(false).describe("Minify the bundled output"),
13
+ target: z.string().default("es2017").describe("ECMAScript target version"),
14
+ cjs: z
15
+ .boolean()
16
+ .default(false)
17
+ .describe("Output CommonJS format instead of ESM"),
18
+ })
19
+ .describe("Bundle TypeScript code into executable JavaScript");
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare function createConfigPathCommand(): Command;
@@ -0,0 +1,9 @@
1
+ import { Command } from "commander";
2
+ import { getConfigPath } from "@zapier/zapier-sdk-cli-login";
3
+ export function createConfigPathCommand() {
4
+ return new Command("get-config-path")
5
+ .description("Show the path to the configuration file")
6
+ .action(async () => {
7
+ console.log(`Configuration file: ${getConfigPath()}`);
8
+ });
9
+ }
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare function createGenerateTypesCommand(): Command;
@@ -0,0 +1,73 @@
1
+ import { Command } from "commander";
2
+ import { createZapierSdk } from "@zapier/zapier-sdk";
3
+ import { GenerateTypesSchema } from "./schemas";
4
+ import { generateTypes } from "./index";
5
+ import chalk from "chalk";
6
+ import { SchemaParameterResolver } from "../../utils/parameter-resolver";
7
+ import { analyzeZodSchema, convertCliArgsToSdkParams, } from "../../utils/cli-generator-utils";
8
+ export function createGenerateTypesCommand() {
9
+ const parameters = analyzeZodSchema(GenerateTypesSchema);
10
+ const description = GenerateTypesSchema.description ||
11
+ "Generate TypeScript SDK types for a specific app";
12
+ const command = new Command("generate-types").description(description);
13
+ // Add parameters to command using same logic as CLI generator
14
+ parameters.forEach((param) => {
15
+ // Convert camelCase to kebab-case for CLI display
16
+ const kebabName = param.name.replace(/([A-Z])/g, "-$1").toLowerCase();
17
+ if (param.hasResolver && param.required) {
18
+ // Required parameters with resolvers become optional positional arguments (resolver handles prompting)
19
+ command.argument(`[${kebabName}]`, param.description || `${kebabName} parameter`);
20
+ }
21
+ else if (param.required) {
22
+ // Required parameters without resolvers become required positional arguments
23
+ command.argument(`<${kebabName}>`, param.description || `${kebabName} parameter`);
24
+ }
25
+ else if (param.isPositional) {
26
+ // Optional parameters marked as positional become optional positional arguments
27
+ command.argument(`[${kebabName}]`, param.description || `${kebabName} parameter`);
28
+ }
29
+ else {
30
+ // Optional parameters become flags (whether they have resolvers or not)
31
+ const flags = [`--${kebabName}`];
32
+ if (param.type === "boolean") {
33
+ command.option(flags.join(", "), param.description);
34
+ }
35
+ else {
36
+ const flagSignature = flags.join(", ") + ` <${param.type}>`;
37
+ command.option(flagSignature, param.description, param.default);
38
+ }
39
+ }
40
+ });
41
+ // Add formatting options like other commands
42
+ command.option("--json", "Output raw JSON instead of formatted results");
43
+ command.action(async (...args) => {
44
+ try {
45
+ // The last argument is always the command object with parsed options
46
+ const commandObj = args[args.length - 1];
47
+ const options = commandObj.opts();
48
+ // Convert CLI args to SDK method parameters
49
+ const rawParams = convertCliArgsToSdkParams(parameters, args.slice(0, -1), options);
50
+ // Create SDK instance
51
+ const sdk = createZapierSdk();
52
+ // Resolve missing parameters interactively using schema metadata
53
+ const resolver = new SchemaParameterResolver();
54
+ const resolvedParams = await resolver.resolveParameters(GenerateTypesSchema, rawParams, sdk);
55
+ console.log(chalk.blue(`🔧 Generating TypeScript types for ${resolvedParams.appKey}...`));
56
+ // Call our implementation
57
+ const result = await generateTypes({ ...resolvedParams, sdk });
58
+ if (options.json) {
59
+ console.log(JSON.stringify({ result }, null, 2));
60
+ }
61
+ else {
62
+ const output = resolvedParams.output || `./types/${resolvedParams.appKey}.d.ts`;
63
+ console.log(chalk.green("✅ TypeScript types generated successfully!"));
64
+ console.log(chalk.gray(`Output written to: ${output}`));
65
+ }
66
+ }
67
+ catch (error) {
68
+ console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
69
+ process.exit(1);
70
+ }
71
+ });
72
+ return command;
73
+ }
@@ -0,0 +1,8 @@
1
+ import type { createZapierSdk } from "@zapier/zapier-sdk";
2
+ import type { GenerateTypesOptions } from "./schemas";
3
+ /**
4
+ * Generate TypeScript types for a specific app (CLI version)
5
+ */
6
+ export declare function generateTypes(options: GenerateTypesOptions & {
7
+ sdk: ReturnType<typeof createZapierSdk>;
8
+ }): Promise<string>;
@@ -0,0 +1,273 @@
1
+ import * as fs from "fs";
2
+ import * as path from "path";
3
+ /**
4
+ * Generate the fetch method signature for app proxies
5
+ */
6
+ function generateFetchMethodSignature() {
7
+ return ` /** Make authenticated HTTP requests through Zapier's Relay service */
8
+ fetch: (options: Omit<z.infer<typeof RelayFetchSchema>, 'authenticationId'>) => Promise<Response>`;
9
+ }
10
+ /**
11
+ * Generate TypeScript types for a specific app (CLI version)
12
+ */
13
+ export async function generateTypes(options) {
14
+ const { appKey, authenticationId, output = `./types/${appKey}.d.ts`, sdk, } = options;
15
+ // Parse app identifier (support app@version format)
16
+ const { app, version } = parseAppIdentifier(appKey);
17
+ // Fetch all actions for the app
18
+ const actionsResult = await sdk.listActions({
19
+ appKey: app,
20
+ });
21
+ const actions = actionsResult.data;
22
+ if (actions.length === 0) {
23
+ const typeDefinitions = generateEmptyTypesFile(app, version);
24
+ if (output) {
25
+ fs.mkdirSync(path.dirname(output), { recursive: true });
26
+ fs.writeFileSync(output, typeDefinitions, "utf8");
27
+ }
28
+ return typeDefinitions;
29
+ }
30
+ // Fetch input fields for each action
31
+ const actionsWithFields = [];
32
+ if (authenticationId) {
33
+ for (const action of actions) {
34
+ try {
35
+ const fieldsResult = await sdk.listInputFields({
36
+ appKey: action.app_key,
37
+ actionKey: action.key,
38
+ actionType: action.action_type,
39
+ authenticationId: authenticationId,
40
+ });
41
+ const fields = fieldsResult.data; // Direct array result
42
+ actionsWithFields.push({ ...action, inputFields: fields });
43
+ }
44
+ catch {
45
+ // If we can't get fields for an action, include it without fields
46
+ actionsWithFields.push({ ...action, inputFields: [] });
47
+ }
48
+ }
49
+ }
50
+ else {
51
+ // Convert actions to have empty input fields (will generate generic types)
52
+ actions.forEach((action) => {
53
+ actionsWithFields.push({ ...action, inputFields: [] });
54
+ });
55
+ }
56
+ // Generate TypeScript types
57
+ const typeDefinitions = generateTypeDefinitions(app, actionsWithFields, version);
58
+ // Write to file if output path specified
59
+ if (output) {
60
+ fs.mkdirSync(path.dirname(output), { recursive: true });
61
+ fs.writeFileSync(output, typeDefinitions, "utf8");
62
+ }
63
+ return typeDefinitions;
64
+ }
65
+ function parseAppIdentifier(identifier) {
66
+ const parts = identifier.split("@");
67
+ return {
68
+ app: parts[0],
69
+ version: parts[1],
70
+ };
71
+ }
72
+ function generateTypeDefinitions(appKey, actions, version) {
73
+ // Handle empty actions
74
+ if (actions.length === 0) {
75
+ return generateEmptyTypesFile(appKey, version);
76
+ }
77
+ // Group actions by type
78
+ const actionsByType = actions.reduce((acc, action) => {
79
+ if (!acc[action.action_type]) {
80
+ acc[action.action_type] = [];
81
+ }
82
+ acc[action.action_type].push(action);
83
+ return acc;
84
+ }, {});
85
+ const appName = capitalize(appKey);
86
+ const versionComment = version
87
+ ? ` * Generated for ${appKey}@${version}`
88
+ : ` * Generated for ${appKey}`;
89
+ let output = `/* eslint-disable @typescript-eslint/naming-convention */
90
+ /**
91
+ * Auto-generated TypeScript types for Zapier ${appKey} actions
92
+ ${versionComment}
93
+ * Generated on: ${new Date().toISOString()}
94
+ *
95
+ * Usage:
96
+ * import type { ${appName}Sdk } from './path/to/this/file'
97
+ * const sdk = createZapierSdk() as unknown as ${appName}Sdk
98
+ *
99
+ * // Direct usage (per-call auth):
100
+ * await sdk.apps.${appKey}.search.user_by_email({ authenticationId: 123, inputs: { email } })
101
+ *
102
+ * // Factory usage (pinned auth):
103
+ * const my${appName} = sdk.apps.${appKey}({ authenticationId: 123 })
104
+ * await my${appName}.search.user_by_email({ inputs: { email } })
105
+ */
106
+
107
+ import type { ActionExecutionOptions, ActionExecutionResult } from '@zapier/zapier-sdk'
108
+ import { z } from 'zod'
109
+ import { RelayFetchSchema } from '@zapier/zapier-sdk'
110
+
111
+ `;
112
+ // Generate input types for each action
113
+ actions.forEach((action) => {
114
+ if (action.inputFields.length > 0) {
115
+ const inputTypeName = `${appName}${capitalize(action.action_type)}${capitalize(sanitizeActionName(action.key))}Inputs`;
116
+ output += `interface ${inputTypeName} {\n`;
117
+ action.inputFields.forEach((field) => {
118
+ const isOptional = !field.required;
119
+ const fieldType = mapFieldTypeToTypeScript(field);
120
+ const description = field.helpText
121
+ ? ` /** ${escapeComment(field.helpText)} */\n`
122
+ : "";
123
+ output += `${description} ${sanitizeFieldName(field.key)}${isOptional ? "?" : ""}: ${fieldType}\n`;
124
+ });
125
+ output += `}\n\n`;
126
+ }
127
+ });
128
+ // Generate action type interfaces for each action type
129
+ Object.entries(actionsByType).forEach(([actionType, typeActions]) => {
130
+ const typeName = `${appName}${capitalize(actionType)}Actions`;
131
+ output += `interface ${typeName} {\n`;
132
+ typeActions.forEach((action) => {
133
+ const actionName = sanitizeActionName(action.key);
134
+ const description = action.description
135
+ ? ` /** ${escapeComment(action.description)} */\n`
136
+ : "";
137
+ // Generate type-safe action method signature
138
+ if (action.inputFields.length > 0) {
139
+ const inputTypeName = `${appName}${capitalize(action.action_type)}${capitalize(sanitizeActionName(action.key))}Inputs`;
140
+ output += `${description} ${actionName}: (options: { inputs: ${inputTypeName} } & Omit<ActionExecutionOptions, 'inputs'>) => Promise<ActionExecutionResult>\n`;
141
+ }
142
+ else {
143
+ // No specific input fields available - use generic Record<string, any> for inputs
144
+ output += `${description} ${actionName}: (options?: { inputs?: Record<string, any> } & ActionExecutionOptions) => Promise<ActionExecutionResult>\n`;
145
+ }
146
+ });
147
+ output += `}\n\n`;
148
+ });
149
+ // Generate the main app SDK interface with factory pattern support
150
+ // Generate the app proxy interface (actions grouped by type)
151
+ output += `interface ${appName}AppProxy {\n`;
152
+ Object.keys(actionsByType).forEach((actionType) => {
153
+ const typeName = `${appName}${capitalize(actionType)}Actions`;
154
+ output += ` ${actionType}: ${typeName}\n`;
155
+ });
156
+ // Always include fetch method for authenticated HTTP requests
157
+ output += generateFetchMethodSignature() + "\n";
158
+ output += `}\n\n`;
159
+ // Generate the factory function interface
160
+ output += `interface ${appName}AppFactory {\n`;
161
+ output += ` (options: { authenticationId: number }): ${appName}AppProxy\n`;
162
+ output += `}\n\n`;
163
+ // Combine factory and direct access
164
+ output += `type ${appName}AppWithFactory = ${appName}AppFactory & ${appName}AppProxy\n\n`;
165
+ // Generate the main SDK interface
166
+ output += `export interface ${appName}Sdk {\n`;
167
+ output += ` apps: {\n`;
168
+ output += ` ${appKey}: ${appName}AppWithFactory\n`;
169
+ output += ` }\n`;
170
+ output += `}\n`;
171
+ return output;
172
+ }
173
+ function generateEmptyTypesFile(appKey, version) {
174
+ const appName = capitalize(appKey);
175
+ const versionComment = version
176
+ ? ` * Generated for ${appKey}@${version}`
177
+ : ` * Generated for ${appKey}`;
178
+ return `/* eslint-disable @typescript-eslint/naming-convention */
179
+ /**
180
+ * Auto-generated TypeScript types for Zapier ${appKey} actions
181
+ ${versionComment}
182
+ * Generated on: ${new Date().toISOString()}
183
+ *
184
+ * No actions found for this app.
185
+ */
186
+
187
+ import type { ActionExecutionOptions, ActionExecutionResult } from '@zapier/zapier-sdk'
188
+ import { z } from 'zod'
189
+ import { RelayFetchSchema } from '@zapier/zapier-sdk'
190
+
191
+ interface ${appName}AppProxy {
192
+ // No actions available
193
+ ${generateFetchMethodSignature()}
194
+ }
195
+
196
+ interface ${appName}AppFactory {
197
+ (options: { authenticationId: number }): ${appName}AppProxy
198
+ }
199
+
200
+ type ${appName}AppWithFactory = ${appName}AppFactory & ${appName}AppProxy
201
+
202
+ export interface ${appName}Sdk {
203
+ apps: {
204
+ ${appKey}: ${appName}AppWithFactory
205
+ }
206
+ }
207
+ `;
208
+ }
209
+ function capitalize(str) {
210
+ return str.charAt(0).toUpperCase() + str.slice(1).replace(/[-_]/g, "");
211
+ }
212
+ function sanitizeActionName(actionKey) {
213
+ // Ensure the action name is a valid TypeScript identifier
214
+ let sanitized = actionKey.replace(/[^a-zA-Z0-9_$]/g, "_");
215
+ // If it starts with a number, prepend an underscore
216
+ if (/^[0-9]/.test(sanitized)) {
217
+ sanitized = "_" + sanitized;
218
+ }
219
+ return sanitized;
220
+ }
221
+ function sanitizeFieldName(fieldKey) {
222
+ // Ensure the field name is a valid TypeScript identifier
223
+ let sanitized = fieldKey.replace(/[^a-zA-Z0-9_$]/g, "_");
224
+ // If it starts with a number, prepend an underscore
225
+ if (/^[0-9]/.test(sanitized)) {
226
+ sanitized = "_" + sanitized;
227
+ }
228
+ return sanitized;
229
+ }
230
+ function escapeComment(comment) {
231
+ // Escape comment text to prevent breaking the JSDoc comment
232
+ return comment.replace(/\*\//g, "*\\/").replace(/\r?\n/g, " ");
233
+ }
234
+ function mapFieldTypeToTypeScript(field) {
235
+ // Handle choices (enum-like fields)
236
+ if (field.choices && field.choices.length > 0) {
237
+ const choiceValues = field.choices
238
+ .filter((choice) => choice.value !== undefined &&
239
+ choice.value !== null &&
240
+ choice.value !== "")
241
+ .map((choice) => typeof choice.value === "string" ? `"${choice.value}"` : choice.value);
242
+ if (choiceValues.length > 0) {
243
+ return choiceValues.join(" | ");
244
+ }
245
+ // If all choices were filtered out, fall through to default type handling
246
+ }
247
+ // Map Zapier field types to TypeScript types
248
+ switch (field.type?.toLowerCase()) {
249
+ case "string":
250
+ case "text":
251
+ case "email":
252
+ case "url":
253
+ case "password":
254
+ return "string";
255
+ case "integer":
256
+ case "number":
257
+ return "number";
258
+ case "boolean":
259
+ return "boolean";
260
+ case "datetime":
261
+ case "date":
262
+ return "string"; // ISO date strings
263
+ case "file":
264
+ return "string"; // File URL or content
265
+ case "array":
266
+ return "any[]";
267
+ case "object":
268
+ return "Record<string, any>";
269
+ default:
270
+ // Default to string for unknown types, with union for common cases
271
+ return "string | number | boolean";
272
+ }
273
+ }
@@ -0,0 +1,18 @@
1
+ import { z } from "zod";
2
+ export declare const GenerateTypesSchema: z.ZodObject<{
3
+ appKey: z.ZodString;
4
+ authenticationId: z.ZodOptional<z.ZodNumber>;
5
+ output: z.ZodOptional<z.ZodString>;
6
+ debug: z.ZodDefault<z.ZodBoolean>;
7
+ }, "strip", z.ZodTypeAny, {
8
+ appKey: string;
9
+ debug: boolean;
10
+ authenticationId?: number | undefined;
11
+ output?: string | undefined;
12
+ }, {
13
+ appKey: string;
14
+ authenticationId?: number | undefined;
15
+ output?: string | undefined;
16
+ debug?: boolean | undefined;
17
+ }>;
18
+ export type GenerateTypesOptions = z.infer<typeof GenerateTypesSchema>;
@@ -0,0 +1,11 @@
1
+ import { z } from "zod";
2
+ import { AppKeyPropertySchema, AuthenticationIdPropertySchema, OutputPropertySchema, DebugPropertySchema, } from "@zapier/zapier-sdk";
3
+ // Generate types schema - mirrors the original from SDK but for CLI use
4
+ export const GenerateTypesSchema = z
5
+ .object({
6
+ appKey: AppKeyPropertySchema.describe("App key to generate SDK code for"),
7
+ authenticationId: AuthenticationIdPropertySchema.optional(),
8
+ output: OutputPropertySchema.optional().describe("Output file path (defaults to generated/<appKey>.ts)"),
9
+ debug: DebugPropertySchema.describe("Enable debug logging during generation"),
10
+ })
11
+ .describe("Generate TypeScript SDK code for a specific app");
@@ -0,0 +1,6 @@
1
+ export { createLoginCommand } from "./login";
2
+ export { createLogoutCommand } from "./logout";
3
+ export { createConfigPathCommand } from "./configPath";
4
+ export { createGenerateTypesCommand } from "./generate-types/cli";
5
+ export { createBundleCodeCommand } from "./bundle-code/cli";
6
+ export { createMcpCommand } from "./mcp";
@@ -0,0 +1,6 @@
1
+ export { createLoginCommand } from "./login";
2
+ export { createLogoutCommand } from "./logout";
3
+ export { createConfigPathCommand } from "./configPath";
4
+ export { createGenerateTypesCommand } from "./generate-types/cli";
5
+ export { createBundleCodeCommand } from "./bundle-code/cli";
6
+ export { createMcpCommand } from "./mcp";
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare function createLoginCommand(): Command;