@zapier/zapier-sdk-cli 0.8.4 → 0.9.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.
- package/CHANGELOG.md +12 -0
- package/README.md +35 -51
- package/dist/cli.cjs +750 -346
- package/dist/cli.mjs +751 -347
- package/dist/index.cjs +726 -336
- package/dist/index.mjs +727 -337
- package/dist/package.json +1 -1
- package/dist/src/plugins/add/ast-generator.d.ts +37 -0
- package/dist/src/plugins/add/ast-generator.js +403 -0
- package/dist/src/plugins/add/index.d.ts +13 -0
- package/dist/src/plugins/add/index.js +122 -0
- package/dist/src/plugins/add/schemas.d.ts +18 -0
- package/dist/src/plugins/add/schemas.js +19 -0
- package/dist/src/plugins/getLoginConfigPath/index.d.ts +15 -0
- package/dist/src/plugins/getLoginConfigPath/index.js +19 -0
- package/dist/src/plugins/getLoginConfigPath/schemas.d.ts +3 -0
- package/dist/src/plugins/getLoginConfigPath/schemas.js +5 -0
- package/dist/src/plugins/index.d.ts +2 -2
- package/dist/src/plugins/index.js +2 -2
- package/dist/src/sdk.js +3 -3
- package/dist/src/utils/cli-generator.js +15 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
- package/src/plugins/add/ast-generator.ts +777 -0
- package/src/plugins/add/index.test.ts +58 -0
- package/src/plugins/add/index.ts +187 -0
- package/src/plugins/add/schemas.ts +26 -0
- package/src/plugins/getLoginConfigPath/index.ts +45 -0
- package/src/plugins/getLoginConfigPath/schemas.ts +10 -0
- package/src/plugins/index.ts +2 -2
- package/src/sdk.ts +4 -4
- package/src/utils/cli-generator.ts +22 -0
- package/tsup.config.ts +1 -1
- package/dist/src/plugins/generateTypes/index.d.ts +0 -21
- package/dist/src/plugins/generateTypes/index.js +0 -312
- package/dist/src/plugins/generateTypes/schemas.d.ts +0 -18
- package/dist/src/plugins/generateTypes/schemas.js +0 -14
- package/dist/src/plugins/getConfigPath/index.d.ts +0 -15
- package/dist/src/plugins/getConfigPath/index.js +0 -19
- package/dist/src/plugins/getConfigPath/schemas.d.ts +0 -3
- package/dist/src/plugins/getConfigPath/schemas.js +0 -5
- package/src/plugins/generateTypes/index.ts +0 -444
- package/src/plugins/generateTypes/schemas.ts +0 -23
- package/src/plugins/getConfigPath/index.ts +0 -42
- package/src/plugins/getConfigPath/schemas.ts +0 -8
package/dist/cli.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from 'commander';
|
|
3
3
|
import { z } from 'zod';
|
|
4
|
-
import { createFunction, OutputPropertySchema,
|
|
4
|
+
import { createFunction, OutputPropertySchema, DEFAULT_CONFIG_PATH, createZapierSdkWithoutRegistry, registryPlugin, ZapierError, formatErrorMessage, isPositional, hasResolver, getResolutionOrderForParams, getResolver } from '@zapier/zapier-sdk';
|
|
5
5
|
import inquirer from 'inquirer';
|
|
6
6
|
import chalk3 from 'chalk';
|
|
7
7
|
import util from 'util';
|
|
@@ -12,9 +12,12 @@ import pkceChallenge from 'pkce-challenge';
|
|
|
12
12
|
import ora from 'ora';
|
|
13
13
|
import { getLoggedInUser, logout, updateLogin, getConfigPath } from '@zapier/zapier-sdk-cli-login';
|
|
14
14
|
import { startMcpServerAsProcess } from '@zapier/zapier-sdk-mcp';
|
|
15
|
+
import { buildSync } from 'esbuild';
|
|
15
16
|
import * as fs from 'fs';
|
|
16
17
|
import * as path from 'path';
|
|
17
|
-
import {
|
|
18
|
+
import { resolve, join } from 'path';
|
|
19
|
+
import * as ts from 'typescript';
|
|
20
|
+
import { mkdir, writeFile, access } from 'fs/promises';
|
|
18
21
|
|
|
19
22
|
var SchemaParameterResolver = class {
|
|
20
23
|
async resolveParameters(schema, providedParams, sdk2) {
|
|
@@ -181,12 +184,12 @@ var SchemaParameterResolver = class {
|
|
|
181
184
|
}
|
|
182
185
|
return this.createResolvableParameter([fieldName], baseSchema, isRequired);
|
|
183
186
|
}
|
|
184
|
-
createResolvableParameter(
|
|
185
|
-
if (
|
|
186
|
-
const name =
|
|
187
|
+
createResolvableParameter(path2, schema, isRequired) {
|
|
188
|
+
if (path2.length === 0) return null;
|
|
189
|
+
const name = path2[path2.length - 1];
|
|
187
190
|
return {
|
|
188
191
|
name,
|
|
189
|
-
path:
|
|
192
|
+
path: path2,
|
|
190
193
|
schema,
|
|
191
194
|
description: schema.description,
|
|
192
195
|
isRequired
|
|
@@ -346,15 +349,15 @@ Optional fields:`));
|
|
|
346
349
|
}
|
|
347
350
|
return inputs;
|
|
348
351
|
}
|
|
349
|
-
getNestedValue(obj,
|
|
350
|
-
return
|
|
352
|
+
getNestedValue(obj, path2) {
|
|
353
|
+
return path2.reduce(
|
|
351
354
|
(current, key) => current?.[key],
|
|
352
355
|
obj
|
|
353
356
|
);
|
|
354
357
|
}
|
|
355
|
-
setNestedValue(obj,
|
|
356
|
-
const lastKey =
|
|
357
|
-
const parent =
|
|
358
|
+
setNestedValue(obj, path2, value) {
|
|
359
|
+
const lastKey = path2[path2.length - 1];
|
|
360
|
+
const parent = path2.slice(0, -1).reduce((current, key) => {
|
|
358
361
|
const currentObj = current;
|
|
359
362
|
if (!(key in currentObj)) {
|
|
360
363
|
currentObj[key] = {};
|
|
@@ -730,6 +733,7 @@ function createCommandConfig(cliCommandName, sdkMethodName, schema, sdk2) {
|
|
|
730
733
|
}
|
|
731
734
|
function addCommand(program2, commandName, config) {
|
|
732
735
|
const command = program2.command(commandName).description(config.description);
|
|
736
|
+
let hasPositionalArray = false;
|
|
733
737
|
config.parameters.forEach((param) => {
|
|
734
738
|
const kebabName = param.name.replace(/([A-Z])/g, "-$1").toLowerCase();
|
|
735
739
|
if (param.hasResolver && param.required) {
|
|
@@ -737,6 +741,19 @@ function addCommand(program2, commandName, config) {
|
|
|
737
741
|
`[${kebabName}]`,
|
|
738
742
|
param.description || `${kebabName} parameter`
|
|
739
743
|
);
|
|
744
|
+
} else if (param.required && param.type === "array" && !hasPositionalArray) {
|
|
745
|
+
hasPositionalArray = true;
|
|
746
|
+
command.argument(
|
|
747
|
+
`<${kebabName}...>`,
|
|
748
|
+
param.description || `${kebabName} parameter`
|
|
749
|
+
);
|
|
750
|
+
} else if (param.required && param.type === "array") {
|
|
751
|
+
const flags = [`--${kebabName}`];
|
|
752
|
+
const flagSignature = flags.join(", ") + ` <values...>`;
|
|
753
|
+
command.requiredOption(
|
|
754
|
+
flagSignature,
|
|
755
|
+
param.description || `${kebabName} parameter (required)`
|
|
756
|
+
);
|
|
740
757
|
} else if (param.required) {
|
|
741
758
|
command.argument(
|
|
742
759
|
`<${kebabName}>`,
|
|
@@ -1018,28 +1035,28 @@ var client_default = api;
|
|
|
1018
1035
|
|
|
1019
1036
|
// src/utils/getCallablePromise.ts
|
|
1020
1037
|
var getCallablePromise = () => {
|
|
1021
|
-
let
|
|
1038
|
+
let resolve3 = () => {
|
|
1022
1039
|
};
|
|
1023
1040
|
let reject = () => {
|
|
1024
1041
|
};
|
|
1025
1042
|
const promise = new Promise((_resolve, _reject) => {
|
|
1026
|
-
|
|
1043
|
+
resolve3 = _resolve;
|
|
1027
1044
|
reject = _reject;
|
|
1028
1045
|
});
|
|
1029
1046
|
return {
|
|
1030
1047
|
promise,
|
|
1031
|
-
resolve:
|
|
1048
|
+
resolve: resolve3,
|
|
1032
1049
|
reject
|
|
1033
1050
|
};
|
|
1034
1051
|
};
|
|
1035
1052
|
var getCallablePromise_default = getCallablePromise;
|
|
1036
1053
|
var findAvailablePort = () => {
|
|
1037
|
-
return new Promise((
|
|
1054
|
+
return new Promise((resolve3, reject) => {
|
|
1038
1055
|
let portIndex = 0;
|
|
1039
1056
|
const tryPort = (port) => {
|
|
1040
1057
|
const server = express().listen(port, () => {
|
|
1041
1058
|
server.close();
|
|
1042
|
-
|
|
1059
|
+
resolve3(port);
|
|
1043
1060
|
});
|
|
1044
1061
|
server.on("error", (err) => {
|
|
1045
1062
|
if (err.code === "EADDRINUSE") {
|
|
@@ -1129,15 +1146,15 @@ var login = async (timeoutMs = LOGIN_TIMEOUT_MS) => {
|
|
|
1129
1146
|
} finally {
|
|
1130
1147
|
process.off("SIGINT", cleanup);
|
|
1131
1148
|
process.off("SIGTERM", cleanup);
|
|
1132
|
-
await new Promise((
|
|
1149
|
+
await new Promise((resolve3) => {
|
|
1133
1150
|
const timeout = setTimeout(() => {
|
|
1134
1151
|
log_default.info("Server close timed out, forcing connection shutdown...");
|
|
1135
1152
|
connections.forEach((conn) => conn.destroy());
|
|
1136
|
-
|
|
1153
|
+
resolve3();
|
|
1137
1154
|
}, 1e3);
|
|
1138
1155
|
server.close(() => {
|
|
1139
1156
|
clearTimeout(timeout);
|
|
1140
|
-
|
|
1157
|
+
resolve3();
|
|
1141
1158
|
});
|
|
1142
1159
|
});
|
|
1143
1160
|
}
|
|
@@ -1232,323 +1249,6 @@ var mcpPlugin = ({ context }) => {
|
|
|
1232
1249
|
}
|
|
1233
1250
|
};
|
|
1234
1251
|
};
|
|
1235
|
-
var GenerateTypesSchema = z.object({
|
|
1236
|
-
appKey: AppKeyPropertySchema.describe("App key to generate SDK code for"),
|
|
1237
|
-
authenticationId: AuthenticationIdPropertySchema.optional(),
|
|
1238
|
-
output: OutputPropertySchema.optional().describe(
|
|
1239
|
-
"Output file path (defaults to generated/<appKey>.ts)"
|
|
1240
|
-
),
|
|
1241
|
-
lockFilePath: z.string().optional().describe("Path to the .zapierrc lock file (defaults to .zapierrc)")
|
|
1242
|
-
}).describe("Generate TypeScript SDK code for a specific app");
|
|
1243
|
-
var generateTypesPlugin = ({ sdk: sdk2 }) => {
|
|
1244
|
-
const generateTypesWithSdk = createFunction(
|
|
1245
|
-
async function generateTypesWithSdk2(options) {
|
|
1246
|
-
return await generateTypes({ ...options, sdk: sdk2 });
|
|
1247
|
-
},
|
|
1248
|
-
GenerateTypesSchema
|
|
1249
|
-
);
|
|
1250
|
-
return {
|
|
1251
|
-
generateTypes: generateTypesWithSdk,
|
|
1252
|
-
context: {
|
|
1253
|
-
meta: {
|
|
1254
|
-
generateTypes: {
|
|
1255
|
-
categories: ["utility"],
|
|
1256
|
-
inputSchema: GenerateTypesSchema
|
|
1257
|
-
}
|
|
1258
|
-
}
|
|
1259
|
-
}
|
|
1260
|
-
};
|
|
1261
|
-
};
|
|
1262
|
-
function generateFetchMethodSignature() {
|
|
1263
|
-
return ` /** Make authenticated HTTP requests through Zapier's Relay service */
|
|
1264
|
-
fetch: (options: Omit<z.infer<typeof RelayFetchSchema>, 'authenticationId'>) => Promise<Response>`;
|
|
1265
|
-
}
|
|
1266
|
-
async function generateTypes(options) {
|
|
1267
|
-
const {
|
|
1268
|
-
appKey,
|
|
1269
|
-
authenticationId,
|
|
1270
|
-
output = `./types/${appKey}.d.ts`,
|
|
1271
|
-
sdk: sdk2
|
|
1272
|
-
} = options;
|
|
1273
|
-
const { app, version } = parseAppIdentifier(appKey);
|
|
1274
|
-
const actionsResult = await sdk2.listActions({
|
|
1275
|
-
appKey: app
|
|
1276
|
-
});
|
|
1277
|
-
const actions = actionsResult.data;
|
|
1278
|
-
if (actions.length === 0) {
|
|
1279
|
-
const typeDefinitions2 = generateEmptyTypesFile(app, version);
|
|
1280
|
-
if (output) {
|
|
1281
|
-
fs.mkdirSync(path.dirname(output), { recursive: true });
|
|
1282
|
-
fs.writeFileSync(output, typeDefinitions2, "utf8");
|
|
1283
|
-
}
|
|
1284
|
-
return typeDefinitions2;
|
|
1285
|
-
}
|
|
1286
|
-
const actionsWithFields = [];
|
|
1287
|
-
if (authenticationId) {
|
|
1288
|
-
for (const action of actions) {
|
|
1289
|
-
try {
|
|
1290
|
-
const manifestEntry = sdk2.getContext().getManifestEntry(appKey);
|
|
1291
|
-
const fieldsResult = await sdk2.listInputFields({
|
|
1292
|
-
// 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
|
|
1293
|
-
appKey: manifestEntry ? appKey : action.app_key,
|
|
1294
|
-
actionKey: action.key,
|
|
1295
|
-
actionType: action.action_type,
|
|
1296
|
-
authenticationId
|
|
1297
|
-
});
|
|
1298
|
-
const fields = fieldsResult.data.map((field) => {
|
|
1299
|
-
const fieldObj = field;
|
|
1300
|
-
return {
|
|
1301
|
-
...fieldObj,
|
|
1302
|
-
required: fieldObj.is_required || fieldObj.required || false
|
|
1303
|
-
};
|
|
1304
|
-
});
|
|
1305
|
-
actionsWithFields.push({
|
|
1306
|
-
...action,
|
|
1307
|
-
inputFields: fields,
|
|
1308
|
-
name: action.title || action.key
|
|
1309
|
-
});
|
|
1310
|
-
} catch {
|
|
1311
|
-
actionsWithFields.push({
|
|
1312
|
-
...action,
|
|
1313
|
-
inputFields: [],
|
|
1314
|
-
name: action.title || action.key
|
|
1315
|
-
});
|
|
1316
|
-
}
|
|
1317
|
-
}
|
|
1318
|
-
} else {
|
|
1319
|
-
actions.forEach((action) => {
|
|
1320
|
-
actionsWithFields.push({
|
|
1321
|
-
...action,
|
|
1322
|
-
inputFields: [],
|
|
1323
|
-
name: action.title || action.key
|
|
1324
|
-
});
|
|
1325
|
-
});
|
|
1326
|
-
}
|
|
1327
|
-
const typeDefinitions = generateTypeDefinitions(
|
|
1328
|
-
app,
|
|
1329
|
-
actionsWithFields,
|
|
1330
|
-
version
|
|
1331
|
-
);
|
|
1332
|
-
if (output) {
|
|
1333
|
-
fs.mkdirSync(path.dirname(output), { recursive: true });
|
|
1334
|
-
fs.writeFileSync(output, typeDefinitions, "utf8");
|
|
1335
|
-
}
|
|
1336
|
-
return typeDefinitions;
|
|
1337
|
-
}
|
|
1338
|
-
function parseAppIdentifier(identifier) {
|
|
1339
|
-
const parts = identifier.split("@");
|
|
1340
|
-
return {
|
|
1341
|
-
app: parts[0],
|
|
1342
|
-
version: parts[1]
|
|
1343
|
-
};
|
|
1344
|
-
}
|
|
1345
|
-
function generateTypeDefinitions(appKey, actions, version) {
|
|
1346
|
-
if (actions.length === 0) {
|
|
1347
|
-
return generateEmptyTypesFile(appKey, version);
|
|
1348
|
-
}
|
|
1349
|
-
const actionsByType = actions.reduce(
|
|
1350
|
-
(acc, action) => {
|
|
1351
|
-
if (!acc[action.action_type]) {
|
|
1352
|
-
acc[action.action_type] = [];
|
|
1353
|
-
}
|
|
1354
|
-
acc[action.action_type].push(action);
|
|
1355
|
-
return acc;
|
|
1356
|
-
},
|
|
1357
|
-
{}
|
|
1358
|
-
);
|
|
1359
|
-
const appName = capitalize(appKey);
|
|
1360
|
-
const versionComment = version ? ` * Generated for ${appKey}@${version}` : ` * Generated for ${appKey}`;
|
|
1361
|
-
let output = `/* eslint-disable @typescript-eslint/naming-convention */
|
|
1362
|
-
/**
|
|
1363
|
-
* Auto-generated TypeScript types for Zapier ${appKey} actions
|
|
1364
|
-
${versionComment}
|
|
1365
|
-
* Generated on: ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
1366
|
-
*
|
|
1367
|
-
* Usage:
|
|
1368
|
-
* import type { ${appName}Sdk } from './path/to/this/file'
|
|
1369
|
-
* const sdk = createZapierSdk() as unknown as ${appName}Sdk
|
|
1370
|
-
*
|
|
1371
|
-
* // Direct usage (per-call auth):
|
|
1372
|
-
* await sdk.apps.${appKey}.search.user_by_email({ authenticationId: 123, inputs: { email } })
|
|
1373
|
-
*
|
|
1374
|
-
* // Factory usage (pinned auth):
|
|
1375
|
-
* const my${appName} = sdk.apps.${appKey}({ authenticationId: 123 })
|
|
1376
|
-
* await my${appName}.search.user_by_email({ inputs: { email } })
|
|
1377
|
-
*/
|
|
1378
|
-
|
|
1379
|
-
import type { ActionExecutionOptions, ActionExecutionResult } from '@zapier/zapier-sdk'
|
|
1380
|
-
import { z } from 'zod'
|
|
1381
|
-
import { RelayFetchSchema } from '@zapier/zapier-sdk'
|
|
1382
|
-
|
|
1383
|
-
`;
|
|
1384
|
-
actions.forEach((action) => {
|
|
1385
|
-
if (action.inputFields.length > 0) {
|
|
1386
|
-
const inputTypeName = `${appName}${capitalize(action.action_type)}${capitalize(
|
|
1387
|
-
sanitizeActionName(action.key)
|
|
1388
|
-
)}Inputs`;
|
|
1389
|
-
output += `interface ${inputTypeName} {
|
|
1390
|
-
`;
|
|
1391
|
-
action.inputFields.forEach((field) => {
|
|
1392
|
-
const isOptional = !field.required;
|
|
1393
|
-
const fieldType = mapFieldTypeToTypeScript(field);
|
|
1394
|
-
const description = field.helpText ? ` /** ${escapeComment(field.helpText)} */
|
|
1395
|
-
` : "";
|
|
1396
|
-
output += `${description} ${sanitizeFieldName(field.key)}${isOptional ? "?" : ""}: ${fieldType}
|
|
1397
|
-
`;
|
|
1398
|
-
});
|
|
1399
|
-
output += `}
|
|
1400
|
-
|
|
1401
|
-
`;
|
|
1402
|
-
}
|
|
1403
|
-
});
|
|
1404
|
-
Object.entries(actionsByType).forEach(([actionType, typeActions]) => {
|
|
1405
|
-
const typeName = `${appName}${capitalize(actionType)}Actions`;
|
|
1406
|
-
output += `interface ${typeName} {
|
|
1407
|
-
`;
|
|
1408
|
-
typeActions.forEach((action) => {
|
|
1409
|
-
const actionName = sanitizeActionName(action.key);
|
|
1410
|
-
const description = action.description ? ` /** ${escapeComment(action.description)} */
|
|
1411
|
-
` : "";
|
|
1412
|
-
if (action.inputFields.length > 0) {
|
|
1413
|
-
const inputTypeName = `${appName}${capitalize(action.action_type)}${capitalize(
|
|
1414
|
-
sanitizeActionName(action.key)
|
|
1415
|
-
)}Inputs`;
|
|
1416
|
-
output += `${description} ${actionName}: (options: { inputs: ${inputTypeName} } & Omit<ActionExecutionOptions, 'inputs'>) => Promise<ActionExecutionResult>
|
|
1417
|
-
`;
|
|
1418
|
-
} else {
|
|
1419
|
-
output += `${description} ${actionName}: (options?: { inputs?: Record<string, any> } & ActionExecutionOptions) => Promise<ActionExecutionResult>
|
|
1420
|
-
`;
|
|
1421
|
-
}
|
|
1422
|
-
});
|
|
1423
|
-
output += `}
|
|
1424
|
-
|
|
1425
|
-
`;
|
|
1426
|
-
});
|
|
1427
|
-
output += `interface ${appName}AppProxy {
|
|
1428
|
-
`;
|
|
1429
|
-
Object.keys(actionsByType).forEach((actionType) => {
|
|
1430
|
-
const typeName = `${appName}${capitalize(actionType)}Actions`;
|
|
1431
|
-
output += ` ${actionType}: ${typeName}
|
|
1432
|
-
`;
|
|
1433
|
-
});
|
|
1434
|
-
output += generateFetchMethodSignature() + "\n";
|
|
1435
|
-
output += `}
|
|
1436
|
-
|
|
1437
|
-
`;
|
|
1438
|
-
output += `interface ${appName}AppFactory {
|
|
1439
|
-
`;
|
|
1440
|
-
output += ` (options: { authenticationId: number }): ${appName}AppProxy
|
|
1441
|
-
`;
|
|
1442
|
-
output += `}
|
|
1443
|
-
|
|
1444
|
-
`;
|
|
1445
|
-
output += `type ${appName}AppWithFactory = ${appName}AppFactory & ${appName}AppProxy
|
|
1446
|
-
|
|
1447
|
-
`;
|
|
1448
|
-
output += `export interface ${appName}Sdk {
|
|
1449
|
-
`;
|
|
1450
|
-
output += ` apps: {
|
|
1451
|
-
`;
|
|
1452
|
-
output += ` ${appKey}: ${appName}AppWithFactory
|
|
1453
|
-
`;
|
|
1454
|
-
output += ` }
|
|
1455
|
-
`;
|
|
1456
|
-
output += `}
|
|
1457
|
-
`;
|
|
1458
|
-
return output;
|
|
1459
|
-
}
|
|
1460
|
-
function generateEmptyTypesFile(appKey, version) {
|
|
1461
|
-
const appName = capitalize(appKey);
|
|
1462
|
-
const versionComment = version ? ` * Generated for ${appKey}@${version}` : ` * Generated for ${appKey}`;
|
|
1463
|
-
return `/* eslint-disable @typescript-eslint/naming-convention */
|
|
1464
|
-
/**
|
|
1465
|
-
* Auto-generated TypeScript types for Zapier ${appKey} actions
|
|
1466
|
-
${versionComment}
|
|
1467
|
-
* Generated on: ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
1468
|
-
*
|
|
1469
|
-
* No actions found for this app.
|
|
1470
|
-
*/
|
|
1471
|
-
|
|
1472
|
-
import type { ActionExecutionOptions, ActionExecutionResult } from '@zapier/zapier-sdk'
|
|
1473
|
-
import { z } from 'zod'
|
|
1474
|
-
import { RelayFetchSchema } from '@zapier/zapier-sdk'
|
|
1475
|
-
|
|
1476
|
-
interface ${appName}AppProxy {
|
|
1477
|
-
// No actions available
|
|
1478
|
-
${generateFetchMethodSignature()}
|
|
1479
|
-
}
|
|
1480
|
-
|
|
1481
|
-
interface ${appName}AppFactory {
|
|
1482
|
-
(options: { authenticationId: number }): ${appName}AppProxy
|
|
1483
|
-
}
|
|
1484
|
-
|
|
1485
|
-
type ${appName}AppWithFactory = ${appName}AppFactory & ${appName}AppProxy
|
|
1486
|
-
|
|
1487
|
-
export interface ${appName}Sdk {
|
|
1488
|
-
apps: {
|
|
1489
|
-
${appKey}: ${appName}AppWithFactory
|
|
1490
|
-
}
|
|
1491
|
-
}
|
|
1492
|
-
`;
|
|
1493
|
-
}
|
|
1494
|
-
function capitalize(str) {
|
|
1495
|
-
return str.charAt(0).toUpperCase() + str.slice(1).replace(/[-_]/g, "");
|
|
1496
|
-
}
|
|
1497
|
-
function sanitizeActionName(actionKey) {
|
|
1498
|
-
let sanitized = actionKey.replace(/[^a-zA-Z0-9_$]/g, "_");
|
|
1499
|
-
if (/^[0-9]/.test(sanitized)) {
|
|
1500
|
-
sanitized = "_" + sanitized;
|
|
1501
|
-
}
|
|
1502
|
-
return sanitized;
|
|
1503
|
-
}
|
|
1504
|
-
function sanitizeFieldName(fieldKey) {
|
|
1505
|
-
let sanitized = fieldKey.replace(/[^a-zA-Z0-9_$]/g, "_");
|
|
1506
|
-
if (/^[0-9]/.test(sanitized)) {
|
|
1507
|
-
sanitized = "_" + sanitized;
|
|
1508
|
-
}
|
|
1509
|
-
return sanitized;
|
|
1510
|
-
}
|
|
1511
|
-
function escapeComment(comment) {
|
|
1512
|
-
return comment.replace(/\*\//g, "*\\/").replace(/\r?\n/g, " ");
|
|
1513
|
-
}
|
|
1514
|
-
function mapFieldTypeToTypeScript(field) {
|
|
1515
|
-
if (field.choices && field.choices.length > 0) {
|
|
1516
|
-
const choiceValues = field.choices.filter(
|
|
1517
|
-
(choice) => choice.value !== void 0 && choice.value !== null && choice.value !== ""
|
|
1518
|
-
).map(
|
|
1519
|
-
(choice) => typeof choice.value === "string" ? `"${choice.value}"` : choice.value
|
|
1520
|
-
);
|
|
1521
|
-
if (choiceValues.length > 0) {
|
|
1522
|
-
return choiceValues.join(" | ");
|
|
1523
|
-
}
|
|
1524
|
-
}
|
|
1525
|
-
switch (field.type?.toLowerCase()) {
|
|
1526
|
-
case "string":
|
|
1527
|
-
case "text":
|
|
1528
|
-
case "email":
|
|
1529
|
-
case "url":
|
|
1530
|
-
case "password":
|
|
1531
|
-
return "string";
|
|
1532
|
-
case "integer":
|
|
1533
|
-
case "number":
|
|
1534
|
-
return "number";
|
|
1535
|
-
case "boolean":
|
|
1536
|
-
return "boolean";
|
|
1537
|
-
case "datetime":
|
|
1538
|
-
case "date":
|
|
1539
|
-
return "string";
|
|
1540
|
-
// ISO date strings
|
|
1541
|
-
case "file":
|
|
1542
|
-
return "string";
|
|
1543
|
-
// File URL or content
|
|
1544
|
-
case "array":
|
|
1545
|
-
return "any[]";
|
|
1546
|
-
case "object":
|
|
1547
|
-
return "Record<string, any>";
|
|
1548
|
-
default:
|
|
1549
|
-
return "string | number | boolean";
|
|
1550
|
-
}
|
|
1551
|
-
}
|
|
1552
1252
|
var BundleCodeSchema = z.object({
|
|
1553
1253
|
input: z.string().min(1).describe("Input TypeScript file path to bundle"),
|
|
1554
1254
|
output: OutputPropertySchema.optional().describe(
|
|
@@ -1640,21 +1340,725 @@ async function bundleCode(options) {
|
|
|
1640
1340
|
);
|
|
1641
1341
|
}
|
|
1642
1342
|
}
|
|
1643
|
-
var
|
|
1644
|
-
var
|
|
1645
|
-
const
|
|
1646
|
-
async function
|
|
1343
|
+
var GetLoginConfigPathSchema = z.object({}).describe("Show the path to the login configuration file");
|
|
1344
|
+
var getLoginConfigPathPlugin = () => {
|
|
1345
|
+
const getLoginConfigPathWithSdk = createFunction(
|
|
1346
|
+
async function getLoginConfigPathWithSdk2(_options) {
|
|
1647
1347
|
return getConfigPath();
|
|
1648
1348
|
},
|
|
1649
|
-
|
|
1349
|
+
GetLoginConfigPathSchema
|
|
1650
1350
|
);
|
|
1651
1351
|
return {
|
|
1652
|
-
|
|
1352
|
+
getLoginConfigPath: getLoginConfigPathWithSdk,
|
|
1353
|
+
context: {
|
|
1354
|
+
meta: {
|
|
1355
|
+
getLoginConfigPath: {
|
|
1356
|
+
categories: ["utility"],
|
|
1357
|
+
inputSchema: GetLoginConfigPathSchema
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1360
|
+
}
|
|
1361
|
+
};
|
|
1362
|
+
};
|
|
1363
|
+
var AddSchema = z.object({
|
|
1364
|
+
appKeys: z.array(z.string().min(1, "App key cannot be empty")).min(1, "At least one app key is required"),
|
|
1365
|
+
authenticationIds: z.array(z.string()).optional().describe("Authentication IDs to use for type generation"),
|
|
1366
|
+
configPath: z.string().optional().describe(
|
|
1367
|
+
`Path to Zapier config file (defaults to '${DEFAULT_CONFIG_PATH}')`
|
|
1368
|
+
),
|
|
1369
|
+
typesOutput: z.string().optional().describe(
|
|
1370
|
+
"Directory for TypeScript type files (defaults to (src|lib|.)/zapier/apps/)"
|
|
1371
|
+
)
|
|
1372
|
+
});
|
|
1373
|
+
var AstTypeGenerator = class {
|
|
1374
|
+
constructor() {
|
|
1375
|
+
this.factory = ts.factory;
|
|
1376
|
+
this.printer = ts.createPrinter({
|
|
1377
|
+
newLine: ts.NewLineKind.LineFeed,
|
|
1378
|
+
removeComments: false,
|
|
1379
|
+
omitTrailingSemicolon: false
|
|
1380
|
+
});
|
|
1381
|
+
}
|
|
1382
|
+
/**
|
|
1383
|
+
* Generate TypeScript types using AST for a specific app
|
|
1384
|
+
*/
|
|
1385
|
+
async generateTypes(options) {
|
|
1386
|
+
const { appKey, authenticationId, sdk: sdk2 } = options;
|
|
1387
|
+
const { app, version } = this.parseAppIdentifier(appKey);
|
|
1388
|
+
const actionsResult = await sdk2.listActions({
|
|
1389
|
+
appKey: app
|
|
1390
|
+
});
|
|
1391
|
+
const actions = actionsResult.data;
|
|
1392
|
+
if (actions.length === 0) {
|
|
1393
|
+
return this.generateEmptyTypesFile(app, version);
|
|
1394
|
+
}
|
|
1395
|
+
const actionsWithFields = [];
|
|
1396
|
+
if (authenticationId) {
|
|
1397
|
+
for (const action of actions) {
|
|
1398
|
+
try {
|
|
1399
|
+
const fieldsResult = await sdk2.listInputFields({
|
|
1400
|
+
appKey,
|
|
1401
|
+
actionKey: action.key,
|
|
1402
|
+
actionType: action.action_type,
|
|
1403
|
+
authenticationId
|
|
1404
|
+
});
|
|
1405
|
+
const fields = fieldsResult.data.map(
|
|
1406
|
+
(field) => {
|
|
1407
|
+
const fieldObj = field;
|
|
1408
|
+
return {
|
|
1409
|
+
...fieldObj,
|
|
1410
|
+
required: fieldObj.is_required || fieldObj.required || false
|
|
1411
|
+
};
|
|
1412
|
+
}
|
|
1413
|
+
);
|
|
1414
|
+
actionsWithFields.push({
|
|
1415
|
+
...action,
|
|
1416
|
+
inputFields: fields,
|
|
1417
|
+
name: action.title || action.key
|
|
1418
|
+
});
|
|
1419
|
+
} catch {
|
|
1420
|
+
actionsWithFields.push({
|
|
1421
|
+
...action,
|
|
1422
|
+
inputFields: [],
|
|
1423
|
+
name: action.title || action.key
|
|
1424
|
+
});
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1427
|
+
} else {
|
|
1428
|
+
actions.forEach(
|
|
1429
|
+
(action) => {
|
|
1430
|
+
actionsWithFields.push({
|
|
1431
|
+
...action,
|
|
1432
|
+
inputFields: [],
|
|
1433
|
+
name: action.title || action.key,
|
|
1434
|
+
app_key: action.app_key || appKey,
|
|
1435
|
+
action_type: action.action_type || "write",
|
|
1436
|
+
title: action.title || action.key,
|
|
1437
|
+
type: "action",
|
|
1438
|
+
description: action.description || ""
|
|
1439
|
+
});
|
|
1440
|
+
}
|
|
1441
|
+
);
|
|
1442
|
+
}
|
|
1443
|
+
const sourceFile = this.createSourceFile(app, actionsWithFields, version);
|
|
1444
|
+
return this.printer.printFile(sourceFile);
|
|
1445
|
+
}
|
|
1446
|
+
parseAppIdentifier(identifier) {
|
|
1447
|
+
const parts = identifier.split("@");
|
|
1448
|
+
return {
|
|
1449
|
+
app: parts[0],
|
|
1450
|
+
version: parts[1]
|
|
1451
|
+
};
|
|
1452
|
+
}
|
|
1453
|
+
createSourceFile(appKey, actions, version) {
|
|
1454
|
+
const appName = this.capitalize(appKey);
|
|
1455
|
+
const versionComment = version ? ` * Generated for ${appKey}@${version}` : ` * Generated for ${appKey}`;
|
|
1456
|
+
const headerComment = `Auto-generated TypeScript types for Zapier ${appKey} actions
|
|
1457
|
+
${versionComment.slice(3)}
|
|
1458
|
+
Generated on: ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
1459
|
+
|
|
1460
|
+
This file automatically augments the base SDK types when present.
|
|
1461
|
+
No manual imports or type casting required.
|
|
1462
|
+
|
|
1463
|
+
Usage:
|
|
1464
|
+
import { createZapierSdk } from "@zapier/zapier-sdk";
|
|
1465
|
+
|
|
1466
|
+
const zapier = createZapierSdk();
|
|
1467
|
+
// Types are automatically available:
|
|
1468
|
+
await zapier.apps.${appKey}.search.user_by_email({ authenticationId: 123, inputs: { email } })
|
|
1469
|
+
|
|
1470
|
+
// Factory usage (pinned auth):
|
|
1471
|
+
const my${appName} = zapier.apps.${appKey}({ authenticationId: 123 })
|
|
1472
|
+
await my${appName}.search.user_by_email({ inputs: { email } })`;
|
|
1473
|
+
const statements = [
|
|
1474
|
+
// Import the SDK to activate module augmentation
|
|
1475
|
+
this.createImportStatement(["@zapier/zapier-sdk"]),
|
|
1476
|
+
// Import types we'll use
|
|
1477
|
+
this.createTypeImportStatement(
|
|
1478
|
+
[
|
|
1479
|
+
"ActionExecutionOptions",
|
|
1480
|
+
"ActionExecutionResult",
|
|
1481
|
+
"ZapierFetchInitOptions"
|
|
1482
|
+
],
|
|
1483
|
+
"@zapier/zapier-sdk"
|
|
1484
|
+
)
|
|
1485
|
+
];
|
|
1486
|
+
const actionsByType = this.groupActionsByType(actions);
|
|
1487
|
+
actions.forEach((action) => {
|
|
1488
|
+
if (action.inputFields.length > 0) {
|
|
1489
|
+
const inputInterface = this.createInputInterface(appName, action);
|
|
1490
|
+
statements.push(inputInterface);
|
|
1491
|
+
}
|
|
1492
|
+
});
|
|
1493
|
+
Object.entries(actionsByType).forEach(([actionType, typeActions]) => {
|
|
1494
|
+
const actionInterface = this.createActionInterface(
|
|
1495
|
+
appName,
|
|
1496
|
+
actionType,
|
|
1497
|
+
typeActions
|
|
1498
|
+
);
|
|
1499
|
+
statements.push(actionInterface);
|
|
1500
|
+
});
|
|
1501
|
+
const appProxyInterface = this.createAppProxyInterface(
|
|
1502
|
+
appName,
|
|
1503
|
+
actionsByType
|
|
1504
|
+
);
|
|
1505
|
+
statements.push(appProxyInterface);
|
|
1506
|
+
const appFactoryInterface = this.createAppFactoryInterface(appName);
|
|
1507
|
+
statements.push(appFactoryInterface);
|
|
1508
|
+
const appWithFactoryType = this.createAppWithFactoryType(appName);
|
|
1509
|
+
statements.push(appWithFactoryType);
|
|
1510
|
+
const moduleAugmentation = this.createModuleAugmentation(appKey, appName);
|
|
1511
|
+
statements.push(moduleAugmentation);
|
|
1512
|
+
statements.push(
|
|
1513
|
+
this.factory.createExportDeclaration(
|
|
1514
|
+
void 0,
|
|
1515
|
+
false,
|
|
1516
|
+
this.factory.createNamedExports([])
|
|
1517
|
+
)
|
|
1518
|
+
);
|
|
1519
|
+
const sourceFile = ts.createSourceFile(
|
|
1520
|
+
"generated.d.ts",
|
|
1521
|
+
"",
|
|
1522
|
+
ts.ScriptTarget.Latest,
|
|
1523
|
+
false,
|
|
1524
|
+
ts.ScriptKind.TS
|
|
1525
|
+
);
|
|
1526
|
+
if (statements.length > 0) {
|
|
1527
|
+
ts.addSyntheticLeadingComment(
|
|
1528
|
+
statements[0],
|
|
1529
|
+
ts.SyntaxKind.MultiLineCommentTrivia,
|
|
1530
|
+
" eslint-disable @typescript-eslint/naming-convention, @typescript-eslint/no-explicit-any ",
|
|
1531
|
+
true
|
|
1532
|
+
);
|
|
1533
|
+
ts.addSyntheticLeadingComment(
|
|
1534
|
+
statements[0],
|
|
1535
|
+
ts.SyntaxKind.MultiLineCommentTrivia,
|
|
1536
|
+
headerComment,
|
|
1537
|
+
true
|
|
1538
|
+
);
|
|
1539
|
+
}
|
|
1540
|
+
return this.factory.updateSourceFile(sourceFile, statements);
|
|
1541
|
+
}
|
|
1542
|
+
createImportStatement(imports, from) {
|
|
1543
|
+
if (imports.length === 1 && !from && imports[0].startsWith("@")) {
|
|
1544
|
+
return this.factory.createImportDeclaration(
|
|
1545
|
+
void 0,
|
|
1546
|
+
void 0,
|
|
1547
|
+
this.factory.createStringLiteral(imports[0]),
|
|
1548
|
+
void 0
|
|
1549
|
+
);
|
|
1550
|
+
}
|
|
1551
|
+
const fromModule = from || imports[0];
|
|
1552
|
+
const importNames = from ? imports : [];
|
|
1553
|
+
return this.factory.createImportDeclaration(
|
|
1554
|
+
void 0,
|
|
1555
|
+
importNames.length > 0 ? this.factory.createImportClause(
|
|
1556
|
+
false,
|
|
1557
|
+
void 0,
|
|
1558
|
+
this.factory.createNamedImports(
|
|
1559
|
+
importNames.map(
|
|
1560
|
+
(name) => this.factory.createImportSpecifier(
|
|
1561
|
+
false,
|
|
1562
|
+
void 0,
|
|
1563
|
+
this.factory.createIdentifier(name)
|
|
1564
|
+
)
|
|
1565
|
+
)
|
|
1566
|
+
)
|
|
1567
|
+
) : void 0,
|
|
1568
|
+
this.factory.createStringLiteral(fromModule),
|
|
1569
|
+
void 0
|
|
1570
|
+
);
|
|
1571
|
+
}
|
|
1572
|
+
createTypeImportStatement(imports, from) {
|
|
1573
|
+
return this.factory.createImportDeclaration(
|
|
1574
|
+
void 0,
|
|
1575
|
+
this.factory.createImportClause(
|
|
1576
|
+
true,
|
|
1577
|
+
// typeOnly: true
|
|
1578
|
+
void 0,
|
|
1579
|
+
this.factory.createNamedImports(
|
|
1580
|
+
imports.map(
|
|
1581
|
+
(name) => this.factory.createImportSpecifier(
|
|
1582
|
+
false,
|
|
1583
|
+
void 0,
|
|
1584
|
+
this.factory.createIdentifier(name)
|
|
1585
|
+
)
|
|
1586
|
+
)
|
|
1587
|
+
)
|
|
1588
|
+
),
|
|
1589
|
+
this.factory.createStringLiteral(from),
|
|
1590
|
+
void 0
|
|
1591
|
+
);
|
|
1592
|
+
}
|
|
1593
|
+
groupActionsByType(actions) {
|
|
1594
|
+
return actions.reduce(
|
|
1595
|
+
(acc, action) => {
|
|
1596
|
+
if (!acc[action.action_type]) {
|
|
1597
|
+
acc[action.action_type] = [];
|
|
1598
|
+
}
|
|
1599
|
+
acc[action.action_type].push(action);
|
|
1600
|
+
return acc;
|
|
1601
|
+
},
|
|
1602
|
+
{}
|
|
1603
|
+
);
|
|
1604
|
+
}
|
|
1605
|
+
createInputInterface(appName, action) {
|
|
1606
|
+
const inputTypeName = `${appName}${this.capitalize(action.action_type)}${this.capitalize(
|
|
1607
|
+
this.sanitizeActionName(action.key)
|
|
1608
|
+
)}Inputs`;
|
|
1609
|
+
const properties = action.inputFields.map((field) => {
|
|
1610
|
+
const fieldType = this.mapFieldTypeToTypeNode(field);
|
|
1611
|
+
const isOptional = !field.required;
|
|
1612
|
+
let property = this.factory.createPropertySignature(
|
|
1613
|
+
void 0,
|
|
1614
|
+
this.sanitizeFieldName(field.key),
|
|
1615
|
+
isOptional ? this.factory.createToken(ts.SyntaxKind.QuestionToken) : void 0,
|
|
1616
|
+
fieldType
|
|
1617
|
+
);
|
|
1618
|
+
if (field.helpText) {
|
|
1619
|
+
property = ts.addSyntheticLeadingComment(
|
|
1620
|
+
property,
|
|
1621
|
+
ts.SyntaxKind.MultiLineCommentTrivia,
|
|
1622
|
+
`* ${this.escapeComment(field.helpText)} `,
|
|
1623
|
+
true
|
|
1624
|
+
);
|
|
1625
|
+
}
|
|
1626
|
+
return property;
|
|
1627
|
+
});
|
|
1628
|
+
return this.factory.createInterfaceDeclaration(
|
|
1629
|
+
void 0,
|
|
1630
|
+
inputTypeName,
|
|
1631
|
+
void 0,
|
|
1632
|
+
void 0,
|
|
1633
|
+
properties
|
|
1634
|
+
);
|
|
1635
|
+
}
|
|
1636
|
+
createActionInterface(appName, actionType, typeActions) {
|
|
1637
|
+
const typeName = `${appName}${this.capitalize(actionType)}Actions`;
|
|
1638
|
+
const methods = typeActions.map((action) => {
|
|
1639
|
+
const actionName = this.sanitizeActionName(action.key);
|
|
1640
|
+
let methodSignature;
|
|
1641
|
+
if (action.inputFields.length > 0) {
|
|
1642
|
+
const inputTypeName = `${appName}${this.capitalize(action.action_type)}${this.capitalize(
|
|
1643
|
+
this.sanitizeActionName(action.key)
|
|
1644
|
+
)}Inputs`;
|
|
1645
|
+
const inputsType = this.factory.createTypeLiteralNode([
|
|
1646
|
+
this.factory.createPropertySignature(
|
|
1647
|
+
void 0,
|
|
1648
|
+
"inputs",
|
|
1649
|
+
void 0,
|
|
1650
|
+
this.factory.createTypeReferenceNode(inputTypeName)
|
|
1651
|
+
)
|
|
1652
|
+
]);
|
|
1653
|
+
const omitType = this.factory.createTypeReferenceNode("Omit", [
|
|
1654
|
+
this.factory.createTypeReferenceNode("ActionExecutionOptions"),
|
|
1655
|
+
this.factory.createLiteralTypeNode(
|
|
1656
|
+
this.factory.createStringLiteral("inputs")
|
|
1657
|
+
)
|
|
1658
|
+
]);
|
|
1659
|
+
const optionsType = this.factory.createIntersectionTypeNode([
|
|
1660
|
+
inputsType,
|
|
1661
|
+
omitType
|
|
1662
|
+
]);
|
|
1663
|
+
methodSignature = this.factory.createMethodSignature(
|
|
1664
|
+
void 0,
|
|
1665
|
+
actionName,
|
|
1666
|
+
void 0,
|
|
1667
|
+
void 0,
|
|
1668
|
+
[
|
|
1669
|
+
this.factory.createParameterDeclaration(
|
|
1670
|
+
void 0,
|
|
1671
|
+
void 0,
|
|
1672
|
+
"options",
|
|
1673
|
+
void 0,
|
|
1674
|
+
optionsType
|
|
1675
|
+
)
|
|
1676
|
+
],
|
|
1677
|
+
this.factory.createTypeReferenceNode("Promise", [
|
|
1678
|
+
this.factory.createTypeReferenceNode("ActionExecutionResult")
|
|
1679
|
+
])
|
|
1680
|
+
);
|
|
1681
|
+
} else {
|
|
1682
|
+
const genericInputsType = this.factory.createTypeLiteralNode([
|
|
1683
|
+
this.factory.createPropertySignature(
|
|
1684
|
+
void 0,
|
|
1685
|
+
"inputs",
|
|
1686
|
+
this.factory.createToken(ts.SyntaxKind.QuestionToken),
|
|
1687
|
+
this.factory.createTypeReferenceNode("Record", [
|
|
1688
|
+
this.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
|
|
1689
|
+
this.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)
|
|
1690
|
+
])
|
|
1691
|
+
)
|
|
1692
|
+
]);
|
|
1693
|
+
const intersectionType = this.factory.createIntersectionTypeNode([
|
|
1694
|
+
genericInputsType,
|
|
1695
|
+
this.factory.createTypeReferenceNode("ActionExecutionOptions")
|
|
1696
|
+
]);
|
|
1697
|
+
methodSignature = this.factory.createMethodSignature(
|
|
1698
|
+
void 0,
|
|
1699
|
+
actionName,
|
|
1700
|
+
void 0,
|
|
1701
|
+
void 0,
|
|
1702
|
+
[
|
|
1703
|
+
this.factory.createParameterDeclaration(
|
|
1704
|
+
void 0,
|
|
1705
|
+
void 0,
|
|
1706
|
+
"options",
|
|
1707
|
+
this.factory.createToken(ts.SyntaxKind.QuestionToken),
|
|
1708
|
+
intersectionType
|
|
1709
|
+
)
|
|
1710
|
+
],
|
|
1711
|
+
this.factory.createTypeReferenceNode("Promise", [
|
|
1712
|
+
this.factory.createTypeReferenceNode("ActionExecutionResult")
|
|
1713
|
+
])
|
|
1714
|
+
);
|
|
1715
|
+
}
|
|
1716
|
+
if (action.description) {
|
|
1717
|
+
methodSignature = ts.addSyntheticLeadingComment(
|
|
1718
|
+
methodSignature,
|
|
1719
|
+
ts.SyntaxKind.MultiLineCommentTrivia,
|
|
1720
|
+
`* ${this.escapeComment(action.description)} `,
|
|
1721
|
+
true
|
|
1722
|
+
);
|
|
1723
|
+
}
|
|
1724
|
+
return methodSignature;
|
|
1725
|
+
});
|
|
1726
|
+
return this.factory.createInterfaceDeclaration(
|
|
1727
|
+
void 0,
|
|
1728
|
+
typeName,
|
|
1729
|
+
void 0,
|
|
1730
|
+
void 0,
|
|
1731
|
+
methods
|
|
1732
|
+
);
|
|
1733
|
+
}
|
|
1734
|
+
createAppProxyInterface(appName, actionsByType) {
|
|
1735
|
+
const properties = [
|
|
1736
|
+
...Object.keys(actionsByType).map(
|
|
1737
|
+
(actionType) => this.factory.createPropertySignature(
|
|
1738
|
+
void 0,
|
|
1739
|
+
actionType,
|
|
1740
|
+
void 0,
|
|
1741
|
+
this.factory.createTypeReferenceNode(
|
|
1742
|
+
`${appName}${this.capitalize(actionType)}Actions`
|
|
1743
|
+
)
|
|
1744
|
+
)
|
|
1745
|
+
),
|
|
1746
|
+
// Always include fetch method for authenticated HTTP requests
|
|
1747
|
+
this.createFetchMethodProperty()
|
|
1748
|
+
];
|
|
1749
|
+
return this.factory.createInterfaceDeclaration(
|
|
1750
|
+
void 0,
|
|
1751
|
+
`${appName}AppProxy`,
|
|
1752
|
+
void 0,
|
|
1753
|
+
void 0,
|
|
1754
|
+
properties
|
|
1755
|
+
);
|
|
1756
|
+
}
|
|
1757
|
+
createFetchMethodProperty() {
|
|
1758
|
+
let property = this.factory.createPropertySignature(
|
|
1759
|
+
void 0,
|
|
1760
|
+
"fetch",
|
|
1761
|
+
void 0,
|
|
1762
|
+
this.factory.createFunctionTypeNode(
|
|
1763
|
+
void 0,
|
|
1764
|
+
[
|
|
1765
|
+
this.factory.createParameterDeclaration(
|
|
1766
|
+
void 0,
|
|
1767
|
+
void 0,
|
|
1768
|
+
"url",
|
|
1769
|
+
void 0,
|
|
1770
|
+
this.factory.createUnionTypeNode([
|
|
1771
|
+
this.factory.createTypeReferenceNode("string"),
|
|
1772
|
+
this.factory.createTypeReferenceNode("URL")
|
|
1773
|
+
])
|
|
1774
|
+
),
|
|
1775
|
+
this.factory.createParameterDeclaration(
|
|
1776
|
+
void 0,
|
|
1777
|
+
void 0,
|
|
1778
|
+
"init",
|
|
1779
|
+
this.factory.createToken(ts.SyntaxKind.QuestionToken),
|
|
1780
|
+
this.factory.createTypeReferenceNode("ZapierFetchInitOptions")
|
|
1781
|
+
)
|
|
1782
|
+
],
|
|
1783
|
+
this.factory.createTypeReferenceNode("Promise", [
|
|
1784
|
+
this.factory.createTypeReferenceNode("Response")
|
|
1785
|
+
])
|
|
1786
|
+
)
|
|
1787
|
+
);
|
|
1788
|
+
property = ts.addSyntheticLeadingComment(
|
|
1789
|
+
property,
|
|
1790
|
+
ts.SyntaxKind.MultiLineCommentTrivia,
|
|
1791
|
+
"* Make authenticated HTTP requests through Zapier's Relay service ",
|
|
1792
|
+
true
|
|
1793
|
+
);
|
|
1794
|
+
return property;
|
|
1795
|
+
}
|
|
1796
|
+
createAppFactoryInterface(appName) {
|
|
1797
|
+
const callSignature = this.factory.createCallSignature(
|
|
1798
|
+
void 0,
|
|
1799
|
+
[
|
|
1800
|
+
this.factory.createParameterDeclaration(
|
|
1801
|
+
void 0,
|
|
1802
|
+
void 0,
|
|
1803
|
+
"options",
|
|
1804
|
+
void 0,
|
|
1805
|
+
this.factory.createTypeLiteralNode([
|
|
1806
|
+
this.factory.createPropertySignature(
|
|
1807
|
+
void 0,
|
|
1808
|
+
"authenticationId",
|
|
1809
|
+
void 0,
|
|
1810
|
+
this.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword)
|
|
1811
|
+
)
|
|
1812
|
+
])
|
|
1813
|
+
)
|
|
1814
|
+
],
|
|
1815
|
+
this.factory.createTypeReferenceNode(`${appName}AppProxy`)
|
|
1816
|
+
);
|
|
1817
|
+
return this.factory.createInterfaceDeclaration(
|
|
1818
|
+
void 0,
|
|
1819
|
+
`${appName}AppFactory`,
|
|
1820
|
+
void 0,
|
|
1821
|
+
void 0,
|
|
1822
|
+
[callSignature]
|
|
1823
|
+
);
|
|
1824
|
+
}
|
|
1825
|
+
createAppWithFactoryType(appName) {
|
|
1826
|
+
return this.factory.createTypeAliasDeclaration(
|
|
1827
|
+
void 0,
|
|
1828
|
+
`${appName}AppWithFactory`,
|
|
1829
|
+
void 0,
|
|
1830
|
+
this.factory.createIntersectionTypeNode([
|
|
1831
|
+
this.factory.createTypeReferenceNode(`${appName}AppFactory`),
|
|
1832
|
+
this.factory.createTypeReferenceNode(`${appName}AppProxy`)
|
|
1833
|
+
])
|
|
1834
|
+
);
|
|
1835
|
+
}
|
|
1836
|
+
createModuleAugmentation(appKey, appName) {
|
|
1837
|
+
return this.factory.createModuleDeclaration(
|
|
1838
|
+
[this.factory.createToken(ts.SyntaxKind.DeclareKeyword)],
|
|
1839
|
+
this.factory.createStringLiteral("@zapier/zapier-sdk"),
|
|
1840
|
+
this.factory.createModuleBlock([
|
|
1841
|
+
this.factory.createInterfaceDeclaration(
|
|
1842
|
+
void 0,
|
|
1843
|
+
"ZapierSdkApps",
|
|
1844
|
+
void 0,
|
|
1845
|
+
void 0,
|
|
1846
|
+
[
|
|
1847
|
+
this.factory.createPropertySignature(
|
|
1848
|
+
void 0,
|
|
1849
|
+
appKey,
|
|
1850
|
+
void 0,
|
|
1851
|
+
this.factory.createTypeReferenceNode(`${appName}AppWithFactory`)
|
|
1852
|
+
)
|
|
1853
|
+
]
|
|
1854
|
+
)
|
|
1855
|
+
])
|
|
1856
|
+
);
|
|
1857
|
+
}
|
|
1858
|
+
mapFieldTypeToTypeNode(field) {
|
|
1859
|
+
if (field.choices && field.choices.length > 0) {
|
|
1860
|
+
const choiceValues = field.choices.filter(
|
|
1861
|
+
(choice) => choice.value !== void 0 && choice.value !== null && choice.value !== ""
|
|
1862
|
+
).map(
|
|
1863
|
+
(choice) => typeof choice.value === "string" ? this.factory.createLiteralTypeNode(
|
|
1864
|
+
this.factory.createStringLiteral(choice.value)
|
|
1865
|
+
) : this.factory.createLiteralTypeNode(
|
|
1866
|
+
this.factory.createNumericLiteral(String(choice.value))
|
|
1867
|
+
)
|
|
1868
|
+
);
|
|
1869
|
+
if (choiceValues.length > 0) {
|
|
1870
|
+
return this.factory.createUnionTypeNode(choiceValues);
|
|
1871
|
+
}
|
|
1872
|
+
}
|
|
1873
|
+
switch (field.type?.toLowerCase()) {
|
|
1874
|
+
case "string":
|
|
1875
|
+
case "text":
|
|
1876
|
+
case "email":
|
|
1877
|
+
case "url":
|
|
1878
|
+
case "password":
|
|
1879
|
+
case "datetime":
|
|
1880
|
+
case "date":
|
|
1881
|
+
case "file":
|
|
1882
|
+
return this.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword);
|
|
1883
|
+
case "integer":
|
|
1884
|
+
case "number":
|
|
1885
|
+
return this.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword);
|
|
1886
|
+
case "boolean":
|
|
1887
|
+
return this.factory.createKeywordTypeNode(ts.SyntaxKind.BooleanKeyword);
|
|
1888
|
+
case "array":
|
|
1889
|
+
return this.factory.createArrayTypeNode(
|
|
1890
|
+
this.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)
|
|
1891
|
+
);
|
|
1892
|
+
case "object":
|
|
1893
|
+
return this.factory.createTypeReferenceNode("Record", [
|
|
1894
|
+
this.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
|
|
1895
|
+
this.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)
|
|
1896
|
+
]);
|
|
1897
|
+
default:
|
|
1898
|
+
return this.factory.createUnionTypeNode([
|
|
1899
|
+
this.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
|
|
1900
|
+
this.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword),
|
|
1901
|
+
this.factory.createKeywordTypeNode(ts.SyntaxKind.BooleanKeyword)
|
|
1902
|
+
]);
|
|
1903
|
+
}
|
|
1904
|
+
}
|
|
1905
|
+
generateEmptyTypesFile(appKey, version) {
|
|
1906
|
+
const appName = this.capitalize(appKey);
|
|
1907
|
+
const versionComment = version ? ` * Generated for ${appKey}@${version}` : ` * Generated for ${appKey}`;
|
|
1908
|
+
return `/* eslint-disable @typescript-eslint/naming-convention, @typescript-eslint/no-explicit-any */
|
|
1909
|
+
/**
|
|
1910
|
+
* Auto-generated TypeScript types for Zapier ${appKey} actions
|
|
1911
|
+
${versionComment}
|
|
1912
|
+
* Generated on: ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
1913
|
+
*
|
|
1914
|
+
* No actions found for this app.
|
|
1915
|
+
*/
|
|
1916
|
+
|
|
1917
|
+
import type { ActionExecutionOptions, ActionExecutionResult, ZapierFetchInitOptions } from '@zapier/zapier-sdk'
|
|
1918
|
+
|
|
1919
|
+
interface ${appName}AppProxy {
|
|
1920
|
+
/** Make authenticated HTTP requests through Zapier's Relay service */
|
|
1921
|
+
fetch: (url: string | URL, init?: ZapierFetchInitOptions) => Promise<Response>
|
|
1922
|
+
}
|
|
1923
|
+
|
|
1924
|
+
interface ${appName}AppFactory {
|
|
1925
|
+
(options: { authenticationId: number }): ${appName}AppProxy
|
|
1926
|
+
}
|
|
1927
|
+
|
|
1928
|
+
type ${appName}AppWithFactory = ${appName}AppFactory & ${appName}AppProxy
|
|
1929
|
+
|
|
1930
|
+
declare module "@zapier/zapier-sdk" {
|
|
1931
|
+
interface ZapierSdkApps {
|
|
1932
|
+
${appKey}: ${appName}AppWithFactory
|
|
1933
|
+
}
|
|
1934
|
+
}
|
|
1935
|
+
`;
|
|
1936
|
+
}
|
|
1937
|
+
capitalize(str) {
|
|
1938
|
+
return str.charAt(0).toUpperCase() + str.slice(1).replace(/[-_]/g, "");
|
|
1939
|
+
}
|
|
1940
|
+
sanitizeActionName(actionKey) {
|
|
1941
|
+
let sanitized = actionKey.replace(/[^a-zA-Z0-9_$]/g, "_");
|
|
1942
|
+
if (/^[0-9]/.test(sanitized)) {
|
|
1943
|
+
sanitized = "_" + sanitized;
|
|
1944
|
+
}
|
|
1945
|
+
return sanitized;
|
|
1946
|
+
}
|
|
1947
|
+
sanitizeFieldName(fieldKey) {
|
|
1948
|
+
let sanitized = fieldKey.replace(/[^a-zA-Z0-9_$]/g, "_");
|
|
1949
|
+
if (/^[0-9]/.test(sanitized)) {
|
|
1950
|
+
sanitized = "_" + sanitized;
|
|
1951
|
+
}
|
|
1952
|
+
return sanitized;
|
|
1953
|
+
}
|
|
1954
|
+
escapeComment(comment) {
|
|
1955
|
+
return comment.replace(/\*\//g, "*\\/").replace(/\r?\n/g, " ");
|
|
1956
|
+
}
|
|
1957
|
+
};
|
|
1958
|
+
async function detectTypesOutputDirectory() {
|
|
1959
|
+
const candidates = ["src", "lib"];
|
|
1960
|
+
for (const candidate of candidates) {
|
|
1961
|
+
try {
|
|
1962
|
+
await access(candidate);
|
|
1963
|
+
return join(candidate, "zapier", "apps");
|
|
1964
|
+
} catch {
|
|
1965
|
+
}
|
|
1966
|
+
}
|
|
1967
|
+
return "./zapier/apps/";
|
|
1968
|
+
}
|
|
1969
|
+
var addPlugin = ({ sdk: sdk2, context }) => {
|
|
1970
|
+
const add = createFunction(async function add2(options) {
|
|
1971
|
+
const {
|
|
1972
|
+
appKeys,
|
|
1973
|
+
authenticationIds,
|
|
1974
|
+
configPath,
|
|
1975
|
+
typesOutput = await detectTypesOutputDirectory()
|
|
1976
|
+
} = options;
|
|
1977
|
+
const resolvedTypesOutput = resolve(typesOutput);
|
|
1978
|
+
await mkdir(resolvedTypesOutput, { recursive: true });
|
|
1979
|
+
console.log(`\u{1F4E6} Looking up ${appKeys.length} app(s)...`);
|
|
1980
|
+
const appsIterator = sdk2.listApps({ appKeys }).items();
|
|
1981
|
+
const apps = [];
|
|
1982
|
+
for await (const app of appsIterator) {
|
|
1983
|
+
apps.push(app);
|
|
1984
|
+
}
|
|
1985
|
+
if (apps.length === 0) {
|
|
1986
|
+
console.warn("\u26A0\uFE0F No apps found");
|
|
1987
|
+
return;
|
|
1988
|
+
}
|
|
1989
|
+
let authentications = [];
|
|
1990
|
+
if (authenticationIds && authenticationIds.length > 0) {
|
|
1991
|
+
console.log(
|
|
1992
|
+
`\u{1F510} Looking up ${authenticationIds.length} authentication(s)...`
|
|
1993
|
+
);
|
|
1994
|
+
const authsIterator = sdk2.listAuthentications({ authenticationIds }).items();
|
|
1995
|
+
for await (const auth of authsIterator) {
|
|
1996
|
+
authentications.push(auth);
|
|
1997
|
+
}
|
|
1998
|
+
console.log(`\u{1F510} Found ${authentications.length} authentication(s)`);
|
|
1999
|
+
}
|
|
2000
|
+
for (const app of apps) {
|
|
2001
|
+
console.log(`\u{1F4E6} Adding ${app.key}...`);
|
|
2002
|
+
try {
|
|
2003
|
+
const currentImplementationId = app.current_implementation_id;
|
|
2004
|
+
const [implementationName, version] = currentImplementationId.split("@");
|
|
2005
|
+
if (!implementationName || !version) {
|
|
2006
|
+
console.warn(
|
|
2007
|
+
`\u26A0\uFE0F Invalid implementation ID format for '${app.key}': ${currentImplementationId}. Expected format: <implementationName>@<version>. Skipping...`
|
|
2008
|
+
);
|
|
2009
|
+
continue;
|
|
2010
|
+
}
|
|
2011
|
+
const [manifestKey] = await context.updateManifestEntry(
|
|
2012
|
+
app.key,
|
|
2013
|
+
{
|
|
2014
|
+
implementationName,
|
|
2015
|
+
version
|
|
2016
|
+
},
|
|
2017
|
+
configPath
|
|
2018
|
+
);
|
|
2019
|
+
console.log(
|
|
2020
|
+
`\u{1F4DD} Locked ${app.key} to ${implementationName}@${version} using key '${manifestKey}'`
|
|
2021
|
+
);
|
|
2022
|
+
let authenticationId;
|
|
2023
|
+
if (authentications.length > 0) {
|
|
2024
|
+
const matchingAuth = authentications.find((auth) => {
|
|
2025
|
+
return auth.app_key === app.key;
|
|
2026
|
+
});
|
|
2027
|
+
if (matchingAuth) {
|
|
2028
|
+
authenticationId = matchingAuth.id;
|
|
2029
|
+
console.log(
|
|
2030
|
+
`\u{1F510} Using authentication ${authenticationId} (${matchingAuth.title}) for ${app.key}`
|
|
2031
|
+
);
|
|
2032
|
+
} else {
|
|
2033
|
+
console.warn(`\u26A0\uFE0F No matching authentication found for ${app.key}`);
|
|
2034
|
+
}
|
|
2035
|
+
}
|
|
2036
|
+
const typesPath = join(resolvedTypesOutput, `${manifestKey}.d.ts`);
|
|
2037
|
+
try {
|
|
2038
|
+
const generator = new AstTypeGenerator();
|
|
2039
|
+
const typeDefinitions = await generator.generateTypes({
|
|
2040
|
+
appKey: manifestKey,
|
|
2041
|
+
authenticationId,
|
|
2042
|
+
sdk: sdk2
|
|
2043
|
+
});
|
|
2044
|
+
await writeFile(typesPath, typeDefinitions, "utf8");
|
|
2045
|
+
console.log(`\u{1F527} Generated types for ${manifestKey} at ${typesPath}`);
|
|
2046
|
+
} catch (error) {
|
|
2047
|
+
console.warn(`\u26A0\uFE0F Failed to generate types for ${app.key}: ${error}`);
|
|
2048
|
+
}
|
|
2049
|
+
} catch (error) {
|
|
2050
|
+
console.warn(`\u26A0\uFE0F Failed to process ${app.key}: ${error}`);
|
|
2051
|
+
}
|
|
2052
|
+
}
|
|
2053
|
+
console.log(`\u2705 Added ${apps.length} app(s) to manifest`);
|
|
2054
|
+
}, AddSchema);
|
|
2055
|
+
return {
|
|
2056
|
+
add,
|
|
1653
2057
|
context: {
|
|
1654
2058
|
meta: {
|
|
1655
|
-
|
|
2059
|
+
add: {
|
|
1656
2060
|
categories: ["utility"],
|
|
1657
|
-
inputSchema:
|
|
2061
|
+
inputSchema: AddSchema
|
|
1658
2062
|
}
|
|
1659
2063
|
}
|
|
1660
2064
|
}
|
|
@@ -1666,9 +2070,9 @@ function createZapierCliSdk(options = {}) {
|
|
|
1666
2070
|
let sdk2 = createZapierSdkWithoutRegistry({
|
|
1667
2071
|
debug: options.debug
|
|
1668
2072
|
});
|
|
1669
|
-
sdk2 = sdk2.addPlugin(generateTypesPlugin);
|
|
1670
2073
|
sdk2 = sdk2.addPlugin(bundleCodePlugin);
|
|
1671
|
-
sdk2 = sdk2.addPlugin(
|
|
2074
|
+
sdk2 = sdk2.addPlugin(getLoginConfigPathPlugin);
|
|
2075
|
+
sdk2 = sdk2.addPlugin(addPlugin);
|
|
1672
2076
|
sdk2 = sdk2.addPlugin(mcpPlugin);
|
|
1673
2077
|
sdk2 = sdk2.addPlugin(loginPlugin);
|
|
1674
2078
|
sdk2 = sdk2.addPlugin(logoutPlugin);
|
|
@@ -1678,7 +2082,7 @@ function createZapierCliSdk(options = {}) {
|
|
|
1678
2082
|
|
|
1679
2083
|
// package.json
|
|
1680
2084
|
var package_default = {
|
|
1681
|
-
version: "0.
|
|
2085
|
+
version: "0.9.0"};
|
|
1682
2086
|
|
|
1683
2087
|
// src/cli.ts
|
|
1684
2088
|
var program = new Command();
|