@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
@@ -0,0 +1,58 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { AddSchema } from "./schemas";
3
+ import { DEFAULT_CONFIG_PATH } from "@zapier/zapier-sdk";
4
+
5
+ describe("Add plugin", () => {
6
+ describe("schema validation", () => {
7
+ it("should accept valid options with authenticationIds", () => {
8
+ const result = AddSchema.safeParse({
9
+ appKeys: ["slack", "gmail"],
10
+ authenticationIds: ["123", "456"],
11
+ configPath: DEFAULT_CONFIG_PATH,
12
+ typesOutput: "src/types",
13
+ });
14
+
15
+ expect(result.success).toBe(true);
16
+ if (result.success) {
17
+ expect(result.data.authenticationIds).toEqual(["123", "456"]);
18
+ }
19
+ });
20
+
21
+ it("should accept options without authenticationIds", () => {
22
+ const result = AddSchema.safeParse({
23
+ appKeys: ["slack"],
24
+ });
25
+
26
+ expect(result.success).toBe(true);
27
+ if (result.success) {
28
+ expect(result.data.authenticationIds).toBeUndefined();
29
+ }
30
+ });
31
+
32
+ it("should reject invalid authenticationIds type", () => {
33
+ const result = AddSchema.safeParse({
34
+ appKeys: ["slack"],
35
+ authenticationIds: "123", // Should be array
36
+ });
37
+
38
+ expect(result.success).toBe(false);
39
+ });
40
+
41
+ it("should reject authenticationIds with non-string items", () => {
42
+ const result = AddSchema.safeParse({
43
+ appKeys: ["slack"],
44
+ authenticationIds: [123, 456], // Should be strings
45
+ });
46
+
47
+ expect(result.success).toBe(false);
48
+ });
49
+
50
+ it("should require at least one appKey", () => {
51
+ const result = AddSchema.safeParse({
52
+ appKeys: [],
53
+ });
54
+
55
+ expect(result.success).toBe(false);
56
+ });
57
+ });
58
+ });
@@ -0,0 +1,187 @@
1
+ import type {
2
+ Plugin,
3
+ GetSdkType,
4
+ GetContextType,
5
+ ListActionsPluginProvides,
6
+ ListAppsPluginProvides,
7
+ ListInputFieldsPluginProvides,
8
+ ListAuthenticationsPluginProvides,
9
+ ManifestPluginProvides,
10
+ } from "@zapier/zapier-sdk";
11
+ import { createFunction } from "@zapier/zapier-sdk";
12
+ import { AddSchema, type AddOptions } from "./schemas";
13
+ import { AstTypeGenerator } from "./ast-generator";
14
+ import { mkdir, access, writeFile } from "fs/promises";
15
+ import { resolve, join } from "path";
16
+
17
+ /**
18
+ * Detect the best default directory for TypeScript types
19
+ * Looks for src or lib directories, falls back to current directory
20
+ */
21
+ async function detectTypesOutputDirectory(): Promise<string> {
22
+ // Check for common source directories in priority order
23
+ const candidates = ["src", "lib"];
24
+
25
+ for (const candidate of candidates) {
26
+ try {
27
+ await access(candidate);
28
+ return join(candidate, "zapier", "apps");
29
+ } catch {
30
+ // Directory doesn't exist, continue to next candidate
31
+ }
32
+ }
33
+
34
+ // Fall back to current directory
35
+ return "./zapier/apps/";
36
+ }
37
+ export interface AddPluginProvides {
38
+ add: (options: AddOptions) => Promise<void>;
39
+ context: {
40
+ meta: {
41
+ add: {
42
+ inputSchema: typeof AddSchema;
43
+ };
44
+ };
45
+ };
46
+ }
47
+
48
+ export const addPlugin: Plugin<
49
+ GetSdkType<
50
+ ListAppsPluginProvides &
51
+ ListActionsPluginProvides &
52
+ ListInputFieldsPluginProvides &
53
+ ListAuthenticationsPluginProvides &
54
+ ManifestPluginProvides
55
+ >,
56
+ GetContextType<ManifestPluginProvides>,
57
+ AddPluginProvides
58
+ > = ({ sdk, context }) => {
59
+ const add = createFunction(async function add(options: AddOptions) {
60
+ const {
61
+ appKeys,
62
+ authenticationIds,
63
+ configPath,
64
+ typesOutput = await detectTypesOutputDirectory(),
65
+ } = options;
66
+
67
+ const resolvedTypesOutput = resolve(typesOutput);
68
+
69
+ // Ensure types output directory exists
70
+ await mkdir(resolvedTypesOutput, { recursive: true });
71
+
72
+ // Get apps using listApps (which respects existing manifest for version locking)
73
+ console.log(`📦 Looking up ${appKeys.length} app(s)...`);
74
+ const appsIterator = sdk.listApps({ appKeys }).items();
75
+ const apps = [];
76
+ for await (const app of appsIterator) {
77
+ apps.push(app);
78
+ }
79
+
80
+ if (apps.length === 0) {
81
+ console.warn("⚠️ No apps found");
82
+ return;
83
+ }
84
+
85
+ // Fetch authentications if provided
86
+ let authentications = [];
87
+ if (authenticationIds && authenticationIds.length > 0) {
88
+ console.log(
89
+ `🔐 Looking up ${authenticationIds.length} authentication(s)...`,
90
+ );
91
+ const authsIterator = sdk
92
+ .listAuthentications({ authenticationIds })
93
+ .items();
94
+ for await (const auth of authsIterator) {
95
+ authentications.push(auth);
96
+ }
97
+ console.log(`🔐 Found ${authentications.length} authentication(s)`);
98
+ }
99
+
100
+ // Process each app
101
+ for (const app of apps) {
102
+ const appSlugAndKey = app.slug ? `${app.slug} (${app.key})` : app.key;
103
+ console.log(`📦 Adding ${appSlugAndKey}...`);
104
+
105
+ try {
106
+ if (!app.version) {
107
+ console.warn(
108
+ `⚠️ Invalid implementation ID format for '${appSlugAndKey}': ${app.implementation_id}. Expected format: <implementationName>@<version>. Skipping...`,
109
+ );
110
+ continue;
111
+ }
112
+
113
+ // Update manifest using manifest plugin's function
114
+ const [manifestKey] = await context.updateManifestEntry(
115
+ app.key,
116
+ {
117
+ implementationName: app.key,
118
+ version: app.version,
119
+ },
120
+ configPath,
121
+ );
122
+
123
+ console.log(
124
+ `📝 Locked ${appSlugAndKey} to ${app.key}@${app.version} using key '${manifestKey}'`,
125
+ );
126
+
127
+ // Find matching authentication for this app if authentications were provided
128
+ let authenticationId: number | undefined;
129
+ if (authentications.length > 0) {
130
+ // Match authentication by app_key
131
+ const matchingAuth = authentications.find((auth) => {
132
+ return auth.app_key === app.key;
133
+ });
134
+
135
+ if (matchingAuth) {
136
+ authenticationId = matchingAuth.id;
137
+ console.log(
138
+ `🔐 Using authentication ${authenticationId} (${matchingAuth.title}) for ${appSlugAndKey}`,
139
+ );
140
+ } else {
141
+ console.warn(
142
+ `⚠️ No matching authentication found for ${appSlugAndKey}`,
143
+ );
144
+ }
145
+ }
146
+
147
+ // Generate types using the manifest key for consistency
148
+ const typesPath = join(resolvedTypesOutput, `${manifestKey}.d.ts`);
149
+
150
+ try {
151
+ // Use AST-based generator directly
152
+ const generator = new AstTypeGenerator();
153
+ const typeDefinitions = await generator.generateTypes({
154
+ appKey: manifestKey,
155
+ authenticationId,
156
+ sdk,
157
+ });
158
+
159
+ // Write to file
160
+ await writeFile(typesPath, typeDefinitions, "utf8");
161
+ console.log(`🔧 Generated types for ${manifestKey} at ${typesPath}`);
162
+ } catch (error) {
163
+ console.warn(
164
+ `⚠️ Failed to generate types for ${appSlugAndKey}: ${error}`,
165
+ );
166
+ // Continue even if type generation fails
167
+ }
168
+ } catch (error) {
169
+ console.warn(`⚠️ Failed to process ${appSlugAndKey}: ${error}`);
170
+ }
171
+ }
172
+
173
+ console.log(`✅ Added ${apps.length} app(s) to manifest`);
174
+ }, AddSchema);
175
+
176
+ return {
177
+ add,
178
+ context: {
179
+ meta: {
180
+ add: {
181
+ categories: ["utility"],
182
+ inputSchema: AddSchema,
183
+ },
184
+ },
185
+ },
186
+ };
187
+ };
@@ -0,0 +1,26 @@
1
+ import { z } from "zod";
2
+ import { DEFAULT_CONFIG_PATH } from "@zapier/zapier-sdk";
3
+
4
+ export const AddSchema = z.object({
5
+ appKeys: z
6
+ .array(z.string().min(1, "App key cannot be empty"))
7
+ .min(1, "At least one app key is required"),
8
+ authenticationIds: z
9
+ .array(z.string())
10
+ .optional()
11
+ .describe("Authentication IDs to use for type generation"),
12
+ configPath: z
13
+ .string()
14
+ .optional()
15
+ .describe(
16
+ `Path to Zapier config file (defaults to '${DEFAULT_CONFIG_PATH}')`,
17
+ ),
18
+ typesOutput: z
19
+ .string()
20
+ .optional()
21
+ .describe(
22
+ "Directory for TypeScript type files (defaults to (src|lib|.)/zapier/apps/)",
23
+ ),
24
+ });
25
+
26
+ export type AddOptions = z.infer<typeof AddSchema>;
@@ -0,0 +1,45 @@
1
+ import type { Plugin } from "@zapier/zapier-sdk";
2
+ import {
3
+ GetLoginConfigPathSchema,
4
+ type GetLoginConfigPathOptions,
5
+ } from "./schemas";
6
+ import { createFunction } from "@zapier/zapier-sdk";
7
+ import { getConfigPath } from "@zapier/zapier-sdk-cli-login";
8
+
9
+ export interface GetLoginConfigPathPluginProvides {
10
+ getLoginConfigPath: (options?: GetLoginConfigPathOptions) => Promise<string>;
11
+ context: {
12
+ meta: {
13
+ getLoginConfigPath: {
14
+ inputSchema: typeof GetLoginConfigPathSchema;
15
+ };
16
+ };
17
+ };
18
+ }
19
+
20
+ export const getLoginConfigPathPlugin: Plugin<
21
+ {}, // requires no existing SDK methods
22
+ {}, // requires no context
23
+ GetLoginConfigPathPluginProvides
24
+ > = () => {
25
+ const getLoginConfigPathWithSdk = createFunction(
26
+ async function getLoginConfigPathWithSdk(
27
+ _options?: GetLoginConfigPathOptions,
28
+ ): Promise<string> {
29
+ return getConfigPath();
30
+ },
31
+ GetLoginConfigPathSchema,
32
+ );
33
+
34
+ return {
35
+ getLoginConfigPath: getLoginConfigPathWithSdk,
36
+ context: {
37
+ meta: {
38
+ getLoginConfigPath: {
39
+ categories: ["utility"],
40
+ inputSchema: GetLoginConfigPathSchema,
41
+ },
42
+ },
43
+ },
44
+ };
45
+ };
@@ -0,0 +1,10 @@
1
+ import { z } from "zod";
2
+
3
+ // Get login config path schema - simple command with no parameters
4
+ export const GetLoginConfigPathSchema = z
5
+ .object({})
6
+ .describe("Show the path to the login configuration file");
7
+
8
+ export type GetLoginConfigPathOptions = z.infer<
9
+ typeof GetLoginConfigPathSchema
10
+ >;
@@ -1,6 +1,6 @@
1
1
  export { loginPlugin } from "./login";
2
2
  export { logoutPlugin } from "./logout";
3
3
  export { mcpPlugin } from "./mcp";
4
- export { generateTypesPlugin } from "./generateTypes";
5
4
  export { bundleCodePlugin } from "./bundleCode";
6
- export { getConfigPathPlugin } from "./getConfigPath";
5
+ export { getLoginConfigPathPlugin } from "./getLoginConfigPath";
6
+ export { addPlugin } from "./add";
package/src/sdk.ts CHANGED
@@ -7,9 +7,9 @@ import {
7
7
  loginPlugin,
8
8
  logoutPlugin,
9
9
  mcpPlugin,
10
- generateTypesPlugin,
11
10
  bundleCodePlugin,
12
- getConfigPathPlugin,
11
+ getLoginConfigPathPlugin,
12
+ addPlugin,
13
13
  } from "./plugins/index";
14
14
 
15
15
  export interface ZapierCliSdkOptions {
@@ -29,9 +29,9 @@ export function createZapierCliSdk(
29
29
  });
30
30
 
31
31
  // Add CLI-specific plugins before registry
32
- sdk = sdk.addPlugin(generateTypesPlugin);
33
32
  sdk = sdk.addPlugin(bundleCodePlugin);
34
- sdk = sdk.addPlugin(getConfigPathPlugin);
33
+ sdk = sdk.addPlugin(getLoginConfigPathPlugin);
34
+ sdk = sdk.addPlugin(addPlugin);
35
35
  sdk = sdk.addPlugin(mcpPlugin);
36
36
  sdk = sdk.addPlugin(loginPlugin);
37
37
  sdk = sdk.addPlugin(logoutPlugin);
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import { hasResolver, isPositional } from "@zapier/zapier-sdk";
2
+ import { isPositional, type FunctionRegistryEntry } from "@zapier/zapier-sdk";
3
3
 
4
4
  // ============================================================================
5
5
  // Types
@@ -20,14 +20,17 @@ export interface CliParameter {
20
20
  // Schema Analysis
21
21
  // ============================================================================
22
22
 
23
- export function analyzeZodSchema(schema: z.ZodSchema): CliParameter[] {
23
+ export function analyzeZodSchema(
24
+ schema: z.ZodSchema,
25
+ functionInfo?: FunctionRegistryEntry,
26
+ ): CliParameter[] {
24
27
  const parameters: CliParameter[] = [];
25
28
 
26
29
  if (schema instanceof z.ZodObject) {
27
30
  const shape = schema.shape;
28
31
 
29
- for (const [key, fieldSchema] of Object.entries(shape)) {
30
- const param = analyzeZodField(key, fieldSchema as z.ZodSchema);
32
+ for (const [key, fieldSchema] of Object.entries<z.ZodSchema>(shape)) {
33
+ const param = analyzeZodField(key, fieldSchema, functionInfo);
31
34
  if (param) {
32
35
  parameters.push(param);
33
36
  }
@@ -40,6 +43,7 @@ export function analyzeZodSchema(schema: z.ZodSchema): CliParameter[] {
40
43
  function analyzeZodField(
41
44
  name: string,
42
45
  schema: z.ZodSchema,
46
+ functionInfo?: FunctionRegistryEntry,
43
47
  ): CliParameter | null {
44
48
  let baseSchema = schema;
45
49
  let required = true;
@@ -77,6 +81,14 @@ function analyzeZodField(
77
81
  paramType = "string";
78
82
  }
79
83
 
84
+ // Check if this parameter has a resolver
85
+ let paramHasResolver = false;
86
+
87
+ // Check function-specific resolvers first
88
+ if (functionInfo?.resolvers?.[name]) {
89
+ paramHasResolver = true;
90
+ }
91
+
80
92
  // Extract resolver metadata
81
93
  return {
82
94
  name,
@@ -85,7 +97,7 @@ function analyzeZodField(
85
97
  description: schema.description,
86
98
  default: defaultValue,
87
99
  choices,
88
- hasResolver: hasResolver(name),
100
+ hasResolver: paramHasResolver,
89
101
  isPositional: isPositional(schema),
90
102
  };
91
103
  }