@zapier/zapier-sdk-cli 0.13.1 → 0.13.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.
- package/CHANGELOG.md +9 -0
- package/dist/cli.cjs +72 -67
- package/dist/cli.mjs +73 -68
- package/dist/index.cjs +71 -66
- package/dist/index.mjs +72 -67
- package/dist/package.json +1 -1
- package/dist/src/plugins/add/ast-generator.d.ts +8 -4
- package/dist/src/plugins/add/ast-generator.js +82 -66
- package/dist/src/plugins/add/index.js +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
- package/src/plugins/add/ast-generator.ts +103 -81
- package/src/plugins/add/index.ts +3 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zapier/zapier-sdk-cli",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.2",
|
|
4
4
|
"description": "Command line interface for Zapier SDK",
|
|
5
5
|
"main": "dist/index.cjs",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -42,9 +42,9 @@
|
|
|
42
42
|
"ora": "^8.2.0",
|
|
43
43
|
"pkce-challenge": "^5.0.0",
|
|
44
44
|
"zod": "^3.25.67",
|
|
45
|
-
"@zapier/zapier-sdk": "0.13.
|
|
46
|
-
"@zapier/zapier-sdk-
|
|
47
|
-
"@zapier/zapier-sdk-
|
|
45
|
+
"@zapier/zapier-sdk": "0.13.2",
|
|
46
|
+
"@zapier/zapier-sdk-mcp": "0.3.15",
|
|
47
|
+
"@zapier/zapier-sdk-cli-login": "0.3.2"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"@types/express": "^5.0.3",
|
|
@@ -6,7 +6,9 @@ import type {
|
|
|
6
6
|
ListActionsPluginProvides,
|
|
7
7
|
ListInputFieldsPluginProvides,
|
|
8
8
|
ManifestPluginProvides,
|
|
9
|
+
AppItem,
|
|
9
10
|
} from "@zapier/zapier-sdk";
|
|
11
|
+
import { toSnakeCase } from "@zapier/zapier-sdk";
|
|
10
12
|
|
|
11
13
|
interface ActionWithInputFields extends Omit<Action, "inputFields" | "type"> {
|
|
12
14
|
inputFields: InputFieldItem[];
|
|
@@ -17,7 +19,7 @@ interface ActionWithInputFields extends Omit<Action, "inputFields" | "type"> {
|
|
|
17
19
|
}
|
|
18
20
|
|
|
19
21
|
interface GenerateTypesOptions {
|
|
20
|
-
|
|
22
|
+
app: AppItem;
|
|
21
23
|
authenticationId?: number;
|
|
22
24
|
}
|
|
23
25
|
|
|
@@ -44,22 +46,15 @@ export class AstTypeGenerator {
|
|
|
44
46
|
>;
|
|
45
47
|
},
|
|
46
48
|
): Promise<string> {
|
|
47
|
-
const {
|
|
49
|
+
const { app, authenticationId, sdk } = options;
|
|
48
50
|
|
|
49
|
-
//
|
|
50
|
-
const { app, version } = this.parseAppIdentifier(appKey);
|
|
51
|
-
|
|
52
|
-
// Fetch all actions for the app
|
|
51
|
+
// Fetch all actions for the app using implementation_id for correct versioning
|
|
53
52
|
const actionsResult = await sdk.listActions({
|
|
54
|
-
appKey: app,
|
|
53
|
+
appKey: app.implementation_id,
|
|
55
54
|
});
|
|
56
55
|
|
|
57
56
|
const actions = actionsResult.data;
|
|
58
57
|
|
|
59
|
-
if (actions.length === 0) {
|
|
60
|
-
return this.generateEmptyTypesFile(app, version);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
58
|
// Fetch input fields for each action
|
|
64
59
|
const actionsWithFields: ActionWithInputFields[] = [];
|
|
65
60
|
|
|
@@ -67,7 +62,7 @@ export class AstTypeGenerator {
|
|
|
67
62
|
for (const action of actions) {
|
|
68
63
|
try {
|
|
69
64
|
const fieldsResult = await sdk.listInputFields({
|
|
70
|
-
appKey:
|
|
65
|
+
appKey: app.implementation_id,
|
|
71
66
|
actionKey: action.key,
|
|
72
67
|
actionType: action.action_type,
|
|
73
68
|
authenticationId: authenticationId,
|
|
@@ -102,7 +97,7 @@ export class AstTypeGenerator {
|
|
|
102
97
|
...action,
|
|
103
98
|
inputFields: [],
|
|
104
99
|
name: action.title || action.key,
|
|
105
|
-
app_key: action.app_key ||
|
|
100
|
+
app_key: action.app_key || app.implementation_id,
|
|
106
101
|
action_type: (action.action_type as Action["type"]) || "write",
|
|
107
102
|
title: action.title || action.key,
|
|
108
103
|
type: "action" as const,
|
|
@@ -113,35 +108,23 @@ export class AstTypeGenerator {
|
|
|
113
108
|
}
|
|
114
109
|
|
|
115
110
|
// Generate TypeScript AST nodes
|
|
116
|
-
const sourceFile = this.createSourceFile(app, actionsWithFields
|
|
111
|
+
const sourceFile = this.createSourceFile(app, actionsWithFields);
|
|
117
112
|
|
|
118
113
|
// Print the AST to string
|
|
119
114
|
return this.printer.printFile(sourceFile);
|
|
120
115
|
}
|
|
121
116
|
|
|
122
|
-
private parseAppIdentifier(identifier: string): {
|
|
123
|
-
app: string;
|
|
124
|
-
version?: string;
|
|
125
|
-
} {
|
|
126
|
-
const parts = identifier.split("@");
|
|
127
|
-
return {
|
|
128
|
-
app: parts[0],
|
|
129
|
-
version: parts[1],
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
|
|
133
117
|
private createSourceFile(
|
|
134
|
-
|
|
118
|
+
app: AppItem,
|
|
135
119
|
actions: ActionWithInputFields[],
|
|
136
|
-
version?: string,
|
|
137
120
|
): ts.SourceFile {
|
|
138
|
-
const appName = this.
|
|
139
|
-
const versionComment =
|
|
140
|
-
|
|
141
|
-
|
|
121
|
+
const appName = this.getPreferredAppName(app);
|
|
122
|
+
const versionComment = ` * Generated for ${app.implementation_id}`;
|
|
123
|
+
const preferredKey = this.getPreferredProgrammaticKey(app);
|
|
124
|
+
const myVariableName = `my${appName}`;
|
|
142
125
|
|
|
143
126
|
// Create header comment
|
|
144
|
-
const headerComment = `Auto-generated TypeScript types for Zapier ${
|
|
127
|
+
const headerComment = `Auto-generated TypeScript types for Zapier ${app.key} actions
|
|
145
128
|
${versionComment.slice(3)}
|
|
146
129
|
Generated on: ${new Date().toISOString()}
|
|
147
130
|
|
|
@@ -153,11 +136,11 @@ Usage:
|
|
|
153
136
|
|
|
154
137
|
const zapier = createZapierSdk();
|
|
155
138
|
// Types are automatically available:
|
|
156
|
-
await zapier.apps.${
|
|
139
|
+
await zapier.apps.${preferredKey}.search.user_by_email({ authenticationId: 123, inputs: { email } })
|
|
157
140
|
|
|
158
141
|
// Factory usage (pinned auth):
|
|
159
|
-
const
|
|
160
|
-
await
|
|
142
|
+
const ${myVariableName} = zapier.apps.${preferredKey}({ authenticationId: 123 })
|
|
143
|
+
await ${myVariableName}.search.user_by_email({ inputs: { email } })`;
|
|
161
144
|
|
|
162
145
|
const statements: ts.Statement[] = [
|
|
163
146
|
// Import the SDK to activate module augmentation
|
|
@@ -211,7 +194,8 @@ Usage:
|
|
|
211
194
|
statements.push(appWithFactoryType);
|
|
212
195
|
|
|
213
196
|
// Generate module augmentation for automatic type integration
|
|
214
|
-
const
|
|
197
|
+
const allKeys = this.getAllKeys(app);
|
|
198
|
+
const moduleAugmentation = this.createModuleAugmentation(allKeys, appName);
|
|
215
199
|
statements.push(moduleAugmentation);
|
|
216
200
|
|
|
217
201
|
// Add empty export to make this a module
|
|
@@ -607,11 +591,21 @@ Usage:
|
|
|
607
591
|
}
|
|
608
592
|
|
|
609
593
|
private createModuleAugmentation(
|
|
610
|
-
|
|
594
|
+
appKeys: string[],
|
|
611
595
|
appName: string,
|
|
612
596
|
): ts.ModuleDeclaration {
|
|
613
597
|
// Create: declare module "@zapier/zapier-sdk" { interface ZapierSdkApps { [appKey]: AppWithFactory } }
|
|
614
598
|
// This creates a new interface that we can merge with ZapierSdk
|
|
599
|
+
// Create properties for all keys (main key + other_keys)
|
|
600
|
+
const properties = appKeys.map((appKey) =>
|
|
601
|
+
this.factory.createPropertySignature(
|
|
602
|
+
undefined,
|
|
603
|
+
this.createPropertyName(appKey),
|
|
604
|
+
undefined,
|
|
605
|
+
this.factory.createTypeReferenceNode(`${appName}AppWithFactory`),
|
|
606
|
+
),
|
|
607
|
+
);
|
|
608
|
+
|
|
615
609
|
return this.factory.createModuleDeclaration(
|
|
616
610
|
[this.factory.createToken(ts.SyntaxKind.DeclareKeyword)],
|
|
617
611
|
this.factory.createStringLiteral("@zapier/zapier-sdk"),
|
|
@@ -621,14 +615,7 @@ Usage:
|
|
|
621
615
|
"ZapierSdkApps",
|
|
622
616
|
undefined,
|
|
623
617
|
undefined,
|
|
624
|
-
|
|
625
|
-
this.factory.createPropertySignature(
|
|
626
|
-
undefined,
|
|
627
|
-
appKey,
|
|
628
|
-
undefined,
|
|
629
|
-
this.factory.createTypeReferenceNode(`${appName}AppWithFactory`),
|
|
630
|
-
),
|
|
631
|
-
],
|
|
618
|
+
properties,
|
|
632
619
|
),
|
|
633
620
|
]),
|
|
634
621
|
);
|
|
@@ -673,42 +660,6 @@ Usage:
|
|
|
673
660
|
}
|
|
674
661
|
}
|
|
675
662
|
|
|
676
|
-
private generateEmptyTypesFile(appKey: string, version?: string): string {
|
|
677
|
-
const appName = this.capitalize(appKey);
|
|
678
|
-
const versionComment = version
|
|
679
|
-
? ` * Generated for ${appKey}@${version}`
|
|
680
|
-
: ` * Generated for ${appKey}`;
|
|
681
|
-
|
|
682
|
-
return `/* eslint-disable @typescript-eslint/naming-convention, @typescript-eslint/no-explicit-any */
|
|
683
|
-
/**
|
|
684
|
-
* Auto-generated TypeScript types for Zapier ${appKey} actions
|
|
685
|
-
${versionComment}
|
|
686
|
-
* Generated on: ${new Date().toISOString()}
|
|
687
|
-
*
|
|
688
|
-
* No actions found for this app.
|
|
689
|
-
*/
|
|
690
|
-
|
|
691
|
-
import type { ActionExecutionOptions, ActionExecutionResult, ZapierFetchInitOptions } from '@zapier/zapier-sdk'
|
|
692
|
-
|
|
693
|
-
interface ${appName}AppProxy {
|
|
694
|
-
/** Make authenticated HTTP requests through Zapier's Relay service */
|
|
695
|
-
fetch: (url: string | URL, init?: ZapierFetchInitOptions) => Promise<Response>
|
|
696
|
-
}
|
|
697
|
-
|
|
698
|
-
interface ${appName}AppFactory {
|
|
699
|
-
(options: { authenticationId: number }): ${appName}AppProxy
|
|
700
|
-
}
|
|
701
|
-
|
|
702
|
-
type ${appName}AppWithFactory = ${appName}AppFactory & ${appName}AppProxy
|
|
703
|
-
|
|
704
|
-
declare module "@zapier/zapier-sdk" {
|
|
705
|
-
interface ZapierSdkApps {
|
|
706
|
-
${appKey}: ${appName}AppWithFactory
|
|
707
|
-
}
|
|
708
|
-
}
|
|
709
|
-
`;
|
|
710
|
-
}
|
|
711
|
-
|
|
712
663
|
private capitalize(str: string): string {
|
|
713
664
|
return str.charAt(0).toUpperCase() + str.slice(1).replace(/[-_]/g, "");
|
|
714
665
|
}
|
|
@@ -741,4 +692,75 @@ declare module "@zapier/zapier-sdk" {
|
|
|
741
692
|
// Escape comment text to prevent breaking the JSDoc comment
|
|
742
693
|
return comment.replace(/\*\//g, "*\\/").replace(/\r?\n/g, " ");
|
|
743
694
|
}
|
|
695
|
+
|
|
696
|
+
private createPropertyName(name: string): ts.PropertyName {
|
|
697
|
+
// Check if the name is a valid JavaScript identifier
|
|
698
|
+
if (this.isValidIdentifier(name)) {
|
|
699
|
+
return this.factory.createIdentifier(name);
|
|
700
|
+
} else {
|
|
701
|
+
// Use string literal for invalid identifiers (e.g., contains dashes)
|
|
702
|
+
return this.factory.createStringLiteral(name);
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
private isValidIdentifier(name: string): boolean {
|
|
707
|
+
// JavaScript identifier rules: must start with letter, $, or _,
|
|
708
|
+
// followed by letters, digits, $, or _
|
|
709
|
+
return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
private getPreferredProgrammaticKey(app: AppItem): string {
|
|
713
|
+
// If we have a slug, convert it to snake_case as the preferred programmatic key
|
|
714
|
+
if (app.slug) {
|
|
715
|
+
const snakeCaseSlug = toSnakeCase(app.slug);
|
|
716
|
+
if (this.isValidIdentifier(snakeCaseSlug)) {
|
|
717
|
+
return snakeCaseSlug;
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
// Otherwise, use the main key if it's a valid identifier
|
|
722
|
+
if (this.isValidIdentifier(app.key)) {
|
|
723
|
+
return app.key;
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
// Fallback: sanitize the key to make it a valid identifier
|
|
727
|
+
return this.sanitizeToIdentifier(app.key);
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
private getPreferredAppName(app: AppItem): string {
|
|
731
|
+
const preferredKey = this.getPreferredProgrammaticKey(app);
|
|
732
|
+
|
|
733
|
+
// If it's snake_case, convert to PascalCase
|
|
734
|
+
if (preferredKey.includes("_")) {
|
|
735
|
+
return preferredKey
|
|
736
|
+
.split("_")
|
|
737
|
+
.map((word) => this.capitalize(word.toLowerCase()))
|
|
738
|
+
.join("");
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
// Otherwise, capitalize first letter for PascalCase
|
|
742
|
+
return this.capitalize(preferredKey);
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
private sanitizeToIdentifier(name: string): string {
|
|
746
|
+
// Convert any string to a valid JavaScript identifier
|
|
747
|
+
let sanitized = name.replace(/[^a-zA-Z0-9_$]/g, "_");
|
|
748
|
+
|
|
749
|
+
// If it starts with a number, prepend an underscore
|
|
750
|
+
if (/^[0-9]/.test(sanitized)) {
|
|
751
|
+
sanitized = "_" + sanitized;
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
return sanitized;
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
private getAllKeys(app: AppItem): string[] {
|
|
758
|
+
// Return all possible keys for this app
|
|
759
|
+
const allKeys = new Set([app.key]);
|
|
760
|
+
if (app.slug) {
|
|
761
|
+
allKeys.add(app.slug);
|
|
762
|
+
allKeys.add(toSnakeCase(app.slug));
|
|
763
|
+
}
|
|
764
|
+
return Array.from(allKeys);
|
|
765
|
+
}
|
|
744
766
|
}
|
package/src/plugins/add/index.ts
CHANGED
|
@@ -7,6 +7,7 @@ import type {
|
|
|
7
7
|
ListInputFieldsPluginProvides,
|
|
8
8
|
ListAuthenticationsPluginProvides,
|
|
9
9
|
ManifestPluginProvides,
|
|
10
|
+
AppItem,
|
|
10
11
|
} from "@zapier/zapier-sdk";
|
|
11
12
|
import { createFunction } from "@zapier/zapier-sdk";
|
|
12
13
|
import { AddSchema, type AddOptions } from "./schemas";
|
|
@@ -72,7 +73,7 @@ export const addPlugin: Plugin<
|
|
|
72
73
|
// Get apps using listApps (which respects existing manifest for version locking)
|
|
73
74
|
console.log(`📦 Looking up ${appKeys.length} app(s)...`);
|
|
74
75
|
const appsIterator = sdk.listApps({ appKeys }).items();
|
|
75
|
-
const apps = [];
|
|
76
|
+
const apps: AppItem[] = [];
|
|
76
77
|
for await (const app of appsIterator) {
|
|
77
78
|
apps.push(app);
|
|
78
79
|
}
|
|
@@ -151,7 +152,7 @@ export const addPlugin: Plugin<
|
|
|
151
152
|
// Use AST-based generator directly
|
|
152
153
|
const generator = new AstTypeGenerator();
|
|
153
154
|
const typeDefinitions = await generator.generateTypes({
|
|
154
|
-
|
|
155
|
+
app,
|
|
155
156
|
authenticationId,
|
|
156
157
|
sdk,
|
|
157
158
|
});
|