@zapier/zapier-sdk 0.0.2 → 0.0.3

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 (41) hide show
  1. package/dist/actions-sdk.d.ts +0 -4
  2. package/dist/actions-sdk.js +43 -1029
  3. package/dist/api.d.ts +62 -0
  4. package/dist/api.js +227 -0
  5. package/dist/functions/bundleCode.d.ts +18 -0
  6. package/dist/functions/bundleCode.js +91 -0
  7. package/dist/functions/generateTypes.d.ts +16 -0
  8. package/dist/functions/generateTypes.js +271 -0
  9. package/dist/functions/getAction.d.ts +16 -0
  10. package/dist/functions/getAction.js +25 -0
  11. package/dist/functions/getApp.d.ts +14 -0
  12. package/dist/functions/getApp.js +41 -0
  13. package/dist/functions/listActions.d.ts +15 -0
  14. package/dist/functions/listActions.js +127 -0
  15. package/dist/functions/listApps.d.ts +16 -0
  16. package/dist/functions/listApps.js +50 -0
  17. package/dist/functions/listAuths.d.ts +18 -0
  18. package/dist/functions/listAuths.js +118 -0
  19. package/dist/functions/listFields.d.ts +18 -0
  20. package/dist/functions/listFields.js +67 -0
  21. package/dist/functions/runAction.d.ts +18 -0
  22. package/dist/functions/runAction.js +156 -0
  23. package/dist/index.d.ts +9 -0
  24. package/dist/index.js +20 -1
  25. package/dist/output-schemas.d.ts +4 -4
  26. package/dist/schemas.d.ts +24 -24
  27. package/dist/types.d.ts +12 -0
  28. package/package.json +1 -1
  29. package/src/actions-sdk.ts +47 -1376
  30. package/src/api.ts +361 -0
  31. package/src/functions/bundleCode.ts +85 -0
  32. package/src/functions/generateTypes.ts +309 -0
  33. package/src/functions/getAction.ts +34 -0
  34. package/src/functions/getApp.ts +47 -0
  35. package/src/functions/listActions.ts +151 -0
  36. package/src/functions/listApps.ts +65 -0
  37. package/src/functions/listAuths.ts +161 -0
  38. package/src/functions/listFields.ts +95 -0
  39. package/src/functions/runAction.ts +256 -0
  40. package/src/index.ts +11 -0
  41. package/src/types.ts +13 -0
package/dist/api.d.ts ADDED
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Zapier API Client Module
3
+ *
4
+ * This module provides a centralized API layer for all HTTP interactions
5
+ * with Zapier's various APIs. It handles authentication, error handling,
6
+ * polling, and provides consistent patterns across all services.
7
+ */
8
+ export interface ApiClientOptions {
9
+ baseUrl: string;
10
+ token?: string;
11
+ debug?: boolean;
12
+ fetch?: typeof globalThis.fetch;
13
+ }
14
+ export interface ApiClient {
15
+ get: (path: string, options?: RequestOptions) => Promise<any>;
16
+ post: (path: string, data?: any, options?: RequestOptions) => Promise<any>;
17
+ put: (path: string, data?: any, options?: RequestOptions) => Promise<any>;
18
+ delete: (path: string, options?: RequestOptions) => Promise<any>;
19
+ poll: (path: string, options?: PollOptions) => Promise<any>;
20
+ }
21
+ export interface RequestOptions {
22
+ headers?: Record<string, string>;
23
+ searchParams?: Record<string, string>;
24
+ authRequired?: boolean;
25
+ customErrorHandler?: (response: Response) => Error | undefined;
26
+ }
27
+ export interface PollOptions extends RequestOptions {
28
+ maxAttempts?: number;
29
+ initialDelay?: number;
30
+ maxDelay?: number;
31
+ successStatus?: number;
32
+ pendingStatus?: number;
33
+ resultExtractor?: (response: any) => any;
34
+ }
35
+ export declare function isJwt(token: string): boolean;
36
+ export declare function getAuthorizationHeader(token: string): string;
37
+ export declare function pollUntilComplete(options: {
38
+ fetch: typeof globalThis.fetch;
39
+ url: string;
40
+ headers?: Record<string, string>;
41
+ maxAttempts?: number;
42
+ initialDelay?: number;
43
+ maxDelay?: number;
44
+ successStatus?: number;
45
+ pendingStatus?: number;
46
+ resultExtractor?: (response: any) => any;
47
+ }): Promise<any>;
48
+ export declare function createZapierApi(options: ApiClientOptions): ApiClient;
49
+ export declare function generateRequestId(): string;
50
+ /**
51
+ * Utility function to get or create an API client for standalone functions
52
+ *
53
+ * @param config - Configuration that may include an existing API client
54
+ * @returns ApiClient instance
55
+ */
56
+ export declare function getOrCreateApiClient(config: {
57
+ baseUrl?: string;
58
+ token?: string;
59
+ api?: ApiClient;
60
+ debug?: boolean;
61
+ fetch?: typeof globalThis.fetch;
62
+ }): ApiClient;
package/dist/api.js ADDED
@@ -0,0 +1,227 @@
1
+ "use strict";
2
+ /**
3
+ * Zapier API Client Module
4
+ *
5
+ * This module provides a centralized API layer for all HTTP interactions
6
+ * with Zapier's various APIs. It handles authentication, error handling,
7
+ * polling, and provides consistent patterns across all services.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.isJwt = isJwt;
11
+ exports.getAuthorizationHeader = getAuthorizationHeader;
12
+ exports.pollUntilComplete = pollUntilComplete;
13
+ exports.createZapierApi = createZapierApi;
14
+ exports.generateRequestId = generateRequestId;
15
+ exports.getOrCreateApiClient = getOrCreateApiClient;
16
+ // ============================================================================
17
+ // Authentication Utilities
18
+ // ============================================================================
19
+ function isJwt(token) {
20
+ // JWT tokens have exactly 3 parts separated by dots
21
+ const parts = token.split(".");
22
+ if (parts.length !== 3) {
23
+ return false;
24
+ }
25
+ // Each part should be base64url encoded (no padding)
26
+ // Basic validation - each part should be non-empty and contain valid base64url characters
27
+ const base64UrlPattern = /^[A-Za-z0-9_-]+$/;
28
+ return parts.every((part) => part.length > 0 && base64UrlPattern.test(part));
29
+ }
30
+ function getAuthorizationHeader(token) {
31
+ // Check if token is a JWT (has 3 parts separated by dots)
32
+ if (isJwt(token)) {
33
+ return `JWT ${token}`;
34
+ }
35
+ // Default to Bearer for other token types
36
+ return `Bearer ${token}`;
37
+ }
38
+ // ============================================================================
39
+ // Debug Logging
40
+ // ============================================================================
41
+ function createDebugLogger(enabled) {
42
+ if (!enabled) {
43
+ return () => { }; // No-op function when debug is disabled
44
+ }
45
+ return (message, data) => {
46
+ console.log(`[Zapier SDK] ${message}`, data || "");
47
+ };
48
+ }
49
+ function createDebugFetch(options) {
50
+ const { originalFetch, debugLog } = options;
51
+ return async (input, options) => {
52
+ const startTime = Date.now();
53
+ // Convert input to URL string for logging
54
+ const url = typeof input === "string" ? input : input.toString();
55
+ const method = options?.method || "GET";
56
+ debugLog(`→ ${method} ${url}`, {
57
+ headers: options?.headers,
58
+ body: options?.body ? JSON.parse(options.body) : undefined,
59
+ });
60
+ try {
61
+ const response = await originalFetch(input, options);
62
+ const duration = Date.now() - startTime;
63
+ debugLog(`← ${response.status} ${response.statusText} (${duration}ms)`, {
64
+ url,
65
+ method,
66
+ status: response.status,
67
+ });
68
+ return response;
69
+ }
70
+ catch (error) {
71
+ const duration = Date.now() - startTime;
72
+ debugLog(`✖ Request failed (${duration}ms)`, {
73
+ url,
74
+ method,
75
+ error: error instanceof Error ? error.message : error,
76
+ });
77
+ throw error;
78
+ }
79
+ };
80
+ }
81
+ // ============================================================================
82
+ // Polling Utilities
83
+ // ============================================================================
84
+ async function pollUntilComplete(options) {
85
+ const { fetch, url, headers = {}, maxAttempts = 30, initialDelay = 50, maxDelay = 1000, successStatus = 200, pendingStatus = 202, resultExtractor = (response) => response, } = options;
86
+ let delay = initialDelay;
87
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
88
+ const response = await fetch(url, { headers });
89
+ if (response.status === successStatus) {
90
+ // Success - extract and return results
91
+ const result = await response.json();
92
+ return resultExtractor(result);
93
+ }
94
+ else if (response.status === pendingStatus) {
95
+ // Still processing - wait and retry
96
+ if (attempt < maxAttempts - 1) {
97
+ await new Promise((resolve) => setTimeout(resolve, delay));
98
+ delay = Math.min(delay * 2, maxDelay); // Exponential backoff
99
+ continue;
100
+ }
101
+ }
102
+ else {
103
+ // Error occurred
104
+ throw new Error(`Request failed: GET ${url} - ${response.status} ${response.statusText}`);
105
+ }
106
+ }
107
+ throw new Error(`Operation timed out after ${maxAttempts} attempts`);
108
+ }
109
+ // ============================================================================
110
+ // API Client Factory
111
+ // ============================================================================
112
+ function createZapierApi(options) {
113
+ const { baseUrl, token, debug = false, fetch: originalFetch = globalThis.fetch, } = options;
114
+ const debugLog = createDebugLogger(debug);
115
+ const fetch = createDebugFetch({ originalFetch, debugLog });
116
+ // Helper to build full URLs
117
+ function buildUrl(path, searchParams) {
118
+ const url = new URL(path, baseUrl);
119
+ if (searchParams) {
120
+ Object.entries(searchParams).forEach(([key, value]) => {
121
+ url.searchParams.set(key, value);
122
+ });
123
+ }
124
+ return url.toString();
125
+ }
126
+ // Helper to build headers
127
+ function buildHeaders(options = {}) {
128
+ const headers = {
129
+ ...options.headers,
130
+ };
131
+ // Add auth header if token provided and not explicitly disabled
132
+ if (token && options.authRequired !== false) {
133
+ headers.Authorization = getAuthorizationHeader(token);
134
+ }
135
+ return headers;
136
+ }
137
+ // Helper to handle responses
138
+ async function handleResponse(response, customErrorHandler) {
139
+ if (!response.ok) {
140
+ // Check for custom error handling first
141
+ if (customErrorHandler) {
142
+ const customError = customErrorHandler(response);
143
+ if (customError) {
144
+ throw customError;
145
+ }
146
+ }
147
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
148
+ }
149
+ // Try to parse JSON, fall back to text if that fails
150
+ try {
151
+ return await response.json();
152
+ }
153
+ catch {
154
+ return await response.text();
155
+ }
156
+ }
157
+ // Helper to perform HTTP requests with JSON handling
158
+ async function fetchJson(method, path, data, options = {}) {
159
+ const url = buildUrl(path, options.searchParams);
160
+ const headers = buildHeaders(options);
161
+ // Add Content-Type for JSON requests with body data
162
+ if (data && typeof data === "object") {
163
+ headers["Content-Type"] = "application/json";
164
+ }
165
+ const response = await fetch(url, {
166
+ method,
167
+ headers,
168
+ body: data ? JSON.stringify(data) : undefined,
169
+ });
170
+ return handleResponse(response, options.customErrorHandler);
171
+ }
172
+ return {
173
+ async get(path, options = {}) {
174
+ return fetchJson("GET", path, undefined, options);
175
+ },
176
+ async post(path, data, options = {}) {
177
+ return fetchJson("POST", path, data, options);
178
+ },
179
+ async put(path, data, options = {}) {
180
+ return fetchJson("PUT", path, data, options);
181
+ },
182
+ async delete(path, options = {}) {
183
+ return fetchJson("DELETE", path, undefined, options);
184
+ },
185
+ async poll(path, options = {}) {
186
+ const url = buildUrl(path, options.searchParams);
187
+ const headers = buildHeaders(options);
188
+ return pollUntilComplete({
189
+ fetch,
190
+ url,
191
+ headers,
192
+ maxAttempts: options.maxAttempts,
193
+ initialDelay: options.initialDelay,
194
+ maxDelay: options.maxDelay,
195
+ successStatus: options.successStatus,
196
+ pendingStatus: options.pendingStatus,
197
+ resultExtractor: options.resultExtractor,
198
+ });
199
+ },
200
+ };
201
+ }
202
+ // ============================================================================
203
+ // Utility Functions
204
+ // ============================================================================
205
+ function generateRequestId() {
206
+ return Math.random().toString(36).substring(2) + Date.now().toString(36);
207
+ }
208
+ // ============================================================================
209
+ // Utility Functions for Standalone Functions
210
+ // ============================================================================
211
+ /**
212
+ * Utility function to get or create an API client for standalone functions
213
+ *
214
+ * @param config - Configuration that may include an existing API client
215
+ * @returns ApiClient instance
216
+ */
217
+ function getOrCreateApiClient(config) {
218
+ const { baseUrl = "https://zapier.com", token = process.env.ZAPIER_TOKEN, api: providedApi, debug = false, fetch: customFetch, } = config;
219
+ // Use provided API client or create a new one
220
+ return (providedApi ||
221
+ createZapierApi({
222
+ baseUrl,
223
+ token,
224
+ debug,
225
+ fetch: customFetch,
226
+ }));
227
+ }
@@ -0,0 +1,18 @@
1
+ export interface BundleCodeOptions {
2
+ input: string;
3
+ output?: string;
4
+ target?: string;
5
+ cjs?: boolean;
6
+ minify?: boolean;
7
+ string?: boolean;
8
+ }
9
+ /**
10
+ * Bundle TypeScript code into executable JavaScript
11
+ *
12
+ * This function can be used standalone without instantiating a full SDK,
13
+ * which enables better tree-shaking in applications that only need this functionality.
14
+ *
15
+ * @param options - Bundling configuration options
16
+ * @returns Promise<string> - Bundled JavaScript code
17
+ */
18
+ export declare function bundleCode(options: BundleCodeOptions): Promise<string>;
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.bundleCode = bundleCode;
37
+ /**
38
+ * Bundle TypeScript code into executable JavaScript
39
+ *
40
+ * This function can be used standalone without instantiating a full SDK,
41
+ * which enables better tree-shaking in applications that only need this functionality.
42
+ *
43
+ * @param options - Bundling configuration options
44
+ * @returns Promise<string> - Bundled JavaScript code
45
+ */
46
+ async function bundleCode(options) {
47
+ const { input, output, target = "es2020", cjs = false, minify = false, string: returnString = false, } = options;
48
+ // Dynamically import esbuild
49
+ const { buildSync } = await Promise.resolve().then(() => __importStar(require("esbuild")));
50
+ const fs = await Promise.resolve().then(() => __importStar(require("fs")));
51
+ const path = await Promise.resolve().then(() => __importStar(require("path")));
52
+ // Resolve input path
53
+ const resolvedInput = path.resolve(process.cwd(), input);
54
+ try {
55
+ // Bundle with esbuild
56
+ const result = buildSync({
57
+ entryPoints: [resolvedInput],
58
+ bundle: true,
59
+ platform: "node",
60
+ target: target,
61
+ format: cjs ? "cjs" : "esm",
62
+ minify: minify,
63
+ write: false,
64
+ external: [], // Bundle everything
65
+ banner: {
66
+ js: "#!/usr/bin/env node",
67
+ },
68
+ });
69
+ if (result.errors.length > 0) {
70
+ throw new Error(`Bundle failed: ${result.errors.map((e) => e.text).join(", ")}`);
71
+ }
72
+ const bundledCode = result.outputFiles?.[0]?.text;
73
+ if (!bundledCode) {
74
+ throw new Error("No output generated");
75
+ }
76
+ let finalOutput = bundledCode;
77
+ if (returnString) {
78
+ // Output as quoted string for node -e using JSON.stringify
79
+ finalOutput = JSON.stringify(bundledCode);
80
+ }
81
+ // Write to file if output path specified
82
+ if (output) {
83
+ fs.mkdirSync(path.dirname(output), { recursive: true });
84
+ fs.writeFileSync(output, finalOutput, "utf8");
85
+ }
86
+ return finalOutput;
87
+ }
88
+ catch (error) {
89
+ throw new Error(`Bundle failed: ${error instanceof Error ? error.message : "Unknown error"}`);
90
+ }
91
+ }
@@ -0,0 +1,16 @@
1
+ import type { FunctionConfig } from "../types";
2
+ export interface GenerateTypesOptions extends FunctionConfig {
3
+ appKey: string;
4
+ authId?: number;
5
+ output?: string;
6
+ }
7
+ /**
8
+ * Generate TypeScript types for a specific app
9
+ *
10
+ * This function can be used standalone without instantiating a full SDK,
11
+ * which enables better tree-shaking in applications that only need this functionality.
12
+ *
13
+ * @param options - App key, auth ID, output path, and API configuration options
14
+ * @returns Promise<string> - Generated TypeScript code
15
+ */
16
+ export declare function generateTypes(options: GenerateTypesOptions): Promise<string>;
@@ -0,0 +1,271 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.generateTypes = generateTypes;
37
+ const listActions_1 = require("./listActions");
38
+ const listFields_1 = require("./listFields");
39
+ /**
40
+ * Generate TypeScript types for a specific app
41
+ *
42
+ * This function can be used standalone without instantiating a full SDK,
43
+ * which enables better tree-shaking in applications that only need this functionality.
44
+ *
45
+ * @param options - App key, auth ID, output path, and API configuration options
46
+ * @returns Promise<string> - Generated TypeScript code
47
+ */
48
+ async function generateTypes(options) {
49
+ const { appKey, authId, output = `./types/${appKey}.d.ts` } = options;
50
+ // Parse app identifier (support app@version format)
51
+ const { app, version } = parseAppIdentifier(appKey);
52
+ // Fetch all actions for the app
53
+ const actions = await (0, listActions_1.listActions)({
54
+ ...options,
55
+ appKey: app,
56
+ });
57
+ if (actions.length === 0) {
58
+ const typeDefinitions = generateEmptyTypesFile(app, version);
59
+ if (output) {
60
+ const fs = await Promise.resolve().then(() => __importStar(require("fs")));
61
+ const path = await Promise.resolve().then(() => __importStar(require("path")));
62
+ fs.mkdirSync(path.dirname(output), { recursive: true });
63
+ fs.writeFileSync(output, typeDefinitions, "utf8");
64
+ }
65
+ return typeDefinitions;
66
+ }
67
+ // Fetch input fields for each action
68
+ const actionsWithFields = [];
69
+ if (authId) {
70
+ for (const action of actions) {
71
+ try {
72
+ const fields = await (0, listFields_1.listFields)({
73
+ ...options,
74
+ app: action.appKey,
75
+ action: action.key,
76
+ type: action.type,
77
+ authId: authId,
78
+ });
79
+ actionsWithFields.push({ ...action, inputFields: fields });
80
+ }
81
+ catch {
82
+ // If we can't get fields for an action, include it without fields
83
+ actionsWithFields.push({ ...action, inputFields: [] });
84
+ }
85
+ }
86
+ }
87
+ else {
88
+ // Convert actions to have empty input fields (will generate generic types)
89
+ actions.forEach((action) => {
90
+ actionsWithFields.push({ ...action, inputFields: [] });
91
+ });
92
+ }
93
+ // Generate TypeScript types
94
+ const typeDefinitions = generateTypeDefinitions(app, actionsWithFields, version);
95
+ // Write to file if output path specified
96
+ if (output) {
97
+ const fs = await Promise.resolve().then(() => __importStar(require("fs")));
98
+ const path = await Promise.resolve().then(() => __importStar(require("path")));
99
+ fs.mkdirSync(path.dirname(output), { recursive: true });
100
+ fs.writeFileSync(output, typeDefinitions, "utf8");
101
+ }
102
+ return typeDefinitions;
103
+ }
104
+ function parseAppIdentifier(identifier) {
105
+ const parts = identifier.split("@");
106
+ return {
107
+ app: parts[0],
108
+ version: parts[1],
109
+ };
110
+ }
111
+ function generateTypeDefinitions(appKey, actions, version) {
112
+ // Handle empty actions
113
+ if (actions.length === 0) {
114
+ return generateEmptyTypesFile(appKey, version);
115
+ }
116
+ // Group actions by type
117
+ const actionsByType = actions.reduce((acc, action) => {
118
+ if (!acc[action.type]) {
119
+ acc[action.type] = [];
120
+ }
121
+ acc[action.type].push(action);
122
+ return acc;
123
+ }, {});
124
+ const appName = capitalize(appKey);
125
+ const versionComment = version
126
+ ? ` * Generated for ${appKey}@${version}`
127
+ : ` * Generated for ${appKey}`;
128
+ let output = `/* eslint-disable @typescript-eslint/naming-convention */
129
+ /**
130
+ * Auto-generated TypeScript types for Zapier ${appKey} actions
131
+ ${versionComment}
132
+ * Generated on: ${new Date().toISOString()}
133
+ *
134
+ * Usage:
135
+ * import type { ${appName}Actions } from './path/to/this/file'
136
+ * const sdk: ActionsSdk & { actions: ${appName}Actions } = createActionsSdk(...)
137
+ */
138
+
139
+ import type { ActionExecutionOptions, ActionExecutionResult } from '@zapier/zapier-sdk'
140
+
141
+ `;
142
+ // Generate input types for each action
143
+ actions.forEach((action) => {
144
+ if (action.inputFields.length > 0) {
145
+ const inputTypeName = `${appName}${capitalize(action.type)}${capitalize(sanitizeActionName(action.key))}Inputs`;
146
+ output += `interface ${inputTypeName} {\n`;
147
+ action.inputFields.forEach((field) => {
148
+ const isOptional = !field.required;
149
+ const fieldType = mapFieldTypeToTypeScript(field);
150
+ const description = field.helpText
151
+ ? ` /** ${escapeComment(field.helpText)} */\n`
152
+ : "";
153
+ output += `${description} ${sanitizeFieldName(field.key)}${isOptional ? "?" : ""}: ${fieldType}\n`;
154
+ });
155
+ output += `}\n\n`;
156
+ }
157
+ });
158
+ // Generate action type interfaces for each action type
159
+ Object.entries(actionsByType).forEach(([actionType, typeActions]) => {
160
+ const typeName = `${appName}${capitalize(actionType)}Actions`;
161
+ output += `interface ${typeName} {\n`;
162
+ typeActions.forEach((action) => {
163
+ const actionName = sanitizeActionName(action.key);
164
+ const description = action.description
165
+ ? ` /** ${escapeComment(action.description)} */\n`
166
+ : "";
167
+ // Generate type-safe action method signature
168
+ if (action.inputFields.length > 0) {
169
+ const inputTypeName = `${appName}${capitalize(action.type)}${capitalize(sanitizeActionName(action.key))}Inputs`;
170
+ output += `${description} ${actionName}: (options: { inputs: ${inputTypeName} } & Omit<ActionExecutionOptions, 'inputs'>) => Promise<ActionExecutionResult>\n`;
171
+ }
172
+ else {
173
+ // No specific input fields available - use generic Record<string, any> for inputs
174
+ output += `${description} ${actionName}: (options?: { inputs?: Record<string, any> } & ActionExecutionOptions) => Promise<ActionExecutionResult>\n`;
175
+ }
176
+ });
177
+ output += `}\n\n`;
178
+ });
179
+ // Generate the main app actions interface
180
+ output += `export interface ${appName}Actions {\n`;
181
+ output += ` run: {\n`;
182
+ output += ` ${appKey}: {\n`;
183
+ Object.keys(actionsByType).forEach((actionType) => {
184
+ const typeName = `${appName}${capitalize(actionType)}Actions`;
185
+ output += ` ${actionType}: ${typeName}\n`;
186
+ });
187
+ output += ` }\n`;
188
+ output += ` }\n`;
189
+ output += `}\n`;
190
+ return output;
191
+ }
192
+ function generateEmptyTypesFile(appKey, version) {
193
+ const appName = capitalize(appKey);
194
+ const versionComment = version
195
+ ? ` * Generated for ${appKey}@${version}`
196
+ : ` * Generated for ${appKey}`;
197
+ return `/* eslint-disable @typescript-eslint/naming-convention */
198
+ /**
199
+ * Auto-generated TypeScript types for Zapier ${appKey} actions
200
+ ${versionComment}
201
+ * Generated on: ${new Date().toISOString()}
202
+ *
203
+ * No actions found for this app.
204
+ */
205
+
206
+ import type { ActionExecutionOptions, ActionExecutionResult } from '@zapier/zapier-sdk'
207
+
208
+ export interface ${appName}Actions {
209
+ run: {
210
+ ${appKey}: {
211
+ // No actions available
212
+ }
213
+ }
214
+ }
215
+ `;
216
+ }
217
+ function capitalize(str) {
218
+ return str.charAt(0).toUpperCase() + str.slice(1).replace(/[-_]/g, "");
219
+ }
220
+ function sanitizeActionName(actionKey) {
221
+ // Ensure the action name is a valid TypeScript identifier
222
+ return actionKey.replace(/[^a-zA-Z0-9_$]/g, "_");
223
+ }
224
+ function sanitizeFieldName(fieldKey) {
225
+ // Ensure the field name is a valid TypeScript identifier
226
+ return fieldKey.replace(/[^a-zA-Z0-9_$]/g, "_");
227
+ }
228
+ function escapeComment(comment) {
229
+ // Escape comment text to prevent breaking the JSDoc comment
230
+ return comment.replace(/\*\//g, "*\\/").replace(/\r?\n/g, " ");
231
+ }
232
+ function mapFieldTypeToTypeScript(field) {
233
+ // Handle choices (enum-like fields)
234
+ if (field.choices && field.choices.length > 0) {
235
+ const choiceValues = field.choices
236
+ .filter((choice) => choice.value !== undefined &&
237
+ choice.value !== null &&
238
+ choice.value !== "")
239
+ .map((choice) => typeof choice.value === "string" ? `"${choice.value}"` : choice.value);
240
+ if (choiceValues.length > 0) {
241
+ return choiceValues.join(" | ");
242
+ }
243
+ // If all choices were filtered out, fall through to default type handling
244
+ }
245
+ // Map Zapier field types to TypeScript types
246
+ switch (field.type?.toLowerCase()) {
247
+ case "string":
248
+ case "text":
249
+ case "email":
250
+ case "url":
251
+ case "password":
252
+ return "string";
253
+ case "integer":
254
+ case "number":
255
+ return "number";
256
+ case "boolean":
257
+ return "boolean";
258
+ case "datetime":
259
+ case "date":
260
+ return "string"; // ISO date strings
261
+ case "file":
262
+ return "string"; // File URL or content
263
+ case "array":
264
+ return "any[]";
265
+ case "object":
266
+ return "Record<string, any>";
267
+ default:
268
+ // Default to string for unknown types, with union for common cases
269
+ return "string | number | boolean";
270
+ }
271
+ }