@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/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createFunction, OutputPropertySchema,
|
|
1
|
+
import { createFunction, OutputPropertySchema, DEFAULT_CONFIG_PATH, createZapierSdkWithoutRegistry, registryPlugin } from '@zapier/zapier-sdk';
|
|
2
2
|
import open from 'open';
|
|
3
3
|
import crypto from 'crypto';
|
|
4
4
|
import express from 'express';
|
|
@@ -8,9 +8,12 @@ import chalk from 'chalk';
|
|
|
8
8
|
import { getLoggedInUser, logout, updateLogin, getConfigPath } from '@zapier/zapier-sdk-cli-login';
|
|
9
9
|
import { z } from 'zod';
|
|
10
10
|
import { startMcpServerAsProcess } from '@zapier/zapier-sdk-mcp';
|
|
11
|
+
import { buildSync } from 'esbuild';
|
|
11
12
|
import * as fs from 'fs';
|
|
12
13
|
import * as path from 'path';
|
|
13
|
-
import {
|
|
14
|
+
import { resolve, join } from 'path';
|
|
15
|
+
import * as ts from 'typescript';
|
|
16
|
+
import { mkdir, writeFile, access } from 'fs/promises';
|
|
14
17
|
|
|
15
18
|
// src/sdk.ts
|
|
16
19
|
|
|
@@ -78,28 +81,28 @@ var client_default = api;
|
|
|
78
81
|
|
|
79
82
|
// src/utils/getCallablePromise.ts
|
|
80
83
|
var getCallablePromise = () => {
|
|
81
|
-
let
|
|
84
|
+
let resolve3 = () => {
|
|
82
85
|
};
|
|
83
86
|
let reject = () => {
|
|
84
87
|
};
|
|
85
88
|
const promise = new Promise((_resolve, _reject) => {
|
|
86
|
-
|
|
89
|
+
resolve3 = _resolve;
|
|
87
90
|
reject = _reject;
|
|
88
91
|
});
|
|
89
92
|
return {
|
|
90
93
|
promise,
|
|
91
|
-
resolve:
|
|
94
|
+
resolve: resolve3,
|
|
92
95
|
reject
|
|
93
96
|
};
|
|
94
97
|
};
|
|
95
98
|
var getCallablePromise_default = getCallablePromise;
|
|
96
99
|
var findAvailablePort = () => {
|
|
97
|
-
return new Promise((
|
|
100
|
+
return new Promise((resolve3, reject) => {
|
|
98
101
|
let portIndex = 0;
|
|
99
102
|
const tryPort = (port) => {
|
|
100
103
|
const server = express().listen(port, () => {
|
|
101
104
|
server.close();
|
|
102
|
-
|
|
105
|
+
resolve3(port);
|
|
103
106
|
});
|
|
104
107
|
server.on("error", (err) => {
|
|
105
108
|
if (err.code === "EADDRINUSE") {
|
|
@@ -189,15 +192,15 @@ var login = async (timeoutMs = LOGIN_TIMEOUT_MS) => {
|
|
|
189
192
|
} finally {
|
|
190
193
|
process.off("SIGINT", cleanup);
|
|
191
194
|
process.off("SIGTERM", cleanup);
|
|
192
|
-
await new Promise((
|
|
195
|
+
await new Promise((resolve3) => {
|
|
193
196
|
const timeout = setTimeout(() => {
|
|
194
197
|
log_default.info("Server close timed out, forcing connection shutdown...");
|
|
195
198
|
connections.forEach((conn) => conn.destroy());
|
|
196
|
-
|
|
199
|
+
resolve3();
|
|
197
200
|
}, 1e3);
|
|
198
201
|
server.close(() => {
|
|
199
202
|
clearTimeout(timeout);
|
|
200
|
-
|
|
203
|
+
resolve3();
|
|
201
204
|
});
|
|
202
205
|
});
|
|
203
206
|
}
|
|
@@ -292,323 +295,6 @@ var mcpPlugin = ({ context }) => {
|
|
|
292
295
|
}
|
|
293
296
|
};
|
|
294
297
|
};
|
|
295
|
-
var GenerateTypesSchema = z.object({
|
|
296
|
-
appKey: AppKeyPropertySchema.describe("App key to generate SDK code for"),
|
|
297
|
-
authenticationId: AuthenticationIdPropertySchema.optional(),
|
|
298
|
-
output: OutputPropertySchema.optional().describe(
|
|
299
|
-
"Output file path (defaults to generated/<appKey>.ts)"
|
|
300
|
-
),
|
|
301
|
-
lockFilePath: z.string().optional().describe("Path to the .zapierrc lock file (defaults to .zapierrc)")
|
|
302
|
-
}).describe("Generate TypeScript SDK code for a specific app");
|
|
303
|
-
var generateTypesPlugin = ({ sdk }) => {
|
|
304
|
-
const generateTypesWithSdk = createFunction(
|
|
305
|
-
async function generateTypesWithSdk2(options) {
|
|
306
|
-
return await generateTypes({ ...options, sdk });
|
|
307
|
-
},
|
|
308
|
-
GenerateTypesSchema
|
|
309
|
-
);
|
|
310
|
-
return {
|
|
311
|
-
generateTypes: generateTypesWithSdk,
|
|
312
|
-
context: {
|
|
313
|
-
meta: {
|
|
314
|
-
generateTypes: {
|
|
315
|
-
categories: ["utility"],
|
|
316
|
-
inputSchema: GenerateTypesSchema
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
};
|
|
321
|
-
};
|
|
322
|
-
function generateFetchMethodSignature() {
|
|
323
|
-
return ` /** Make authenticated HTTP requests through Zapier's Relay service */
|
|
324
|
-
fetch: (options: Omit<z.infer<typeof RelayFetchSchema>, 'authenticationId'>) => Promise<Response>`;
|
|
325
|
-
}
|
|
326
|
-
async function generateTypes(options) {
|
|
327
|
-
const {
|
|
328
|
-
appKey,
|
|
329
|
-
authenticationId,
|
|
330
|
-
output = `./types/${appKey}.d.ts`,
|
|
331
|
-
sdk
|
|
332
|
-
} = options;
|
|
333
|
-
const { app, version } = parseAppIdentifier(appKey);
|
|
334
|
-
const actionsResult = await sdk.listActions({
|
|
335
|
-
appKey: app
|
|
336
|
-
});
|
|
337
|
-
const actions = actionsResult.data;
|
|
338
|
-
if (actions.length === 0) {
|
|
339
|
-
const typeDefinitions2 = generateEmptyTypesFile(app, version);
|
|
340
|
-
if (output) {
|
|
341
|
-
fs.mkdirSync(path.dirname(output), { recursive: true });
|
|
342
|
-
fs.writeFileSync(output, typeDefinitions2, "utf8");
|
|
343
|
-
}
|
|
344
|
-
return typeDefinitions2;
|
|
345
|
-
}
|
|
346
|
-
const actionsWithFields = [];
|
|
347
|
-
if (authenticationId) {
|
|
348
|
-
for (const action of actions) {
|
|
349
|
-
try {
|
|
350
|
-
const manifestEntry = sdk.getContext().getManifestEntry(appKey);
|
|
351
|
-
const fieldsResult = await sdk.listInputFields({
|
|
352
|
-
// 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
|
|
353
|
-
appKey: manifestEntry ? appKey : action.app_key,
|
|
354
|
-
actionKey: action.key,
|
|
355
|
-
actionType: action.action_type,
|
|
356
|
-
authenticationId
|
|
357
|
-
});
|
|
358
|
-
const fields = fieldsResult.data.map((field) => {
|
|
359
|
-
const fieldObj = field;
|
|
360
|
-
return {
|
|
361
|
-
...fieldObj,
|
|
362
|
-
required: fieldObj.is_required || fieldObj.required || false
|
|
363
|
-
};
|
|
364
|
-
});
|
|
365
|
-
actionsWithFields.push({
|
|
366
|
-
...action,
|
|
367
|
-
inputFields: fields,
|
|
368
|
-
name: action.title || action.key
|
|
369
|
-
});
|
|
370
|
-
} catch {
|
|
371
|
-
actionsWithFields.push({
|
|
372
|
-
...action,
|
|
373
|
-
inputFields: [],
|
|
374
|
-
name: action.title || action.key
|
|
375
|
-
});
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
} else {
|
|
379
|
-
actions.forEach((action) => {
|
|
380
|
-
actionsWithFields.push({
|
|
381
|
-
...action,
|
|
382
|
-
inputFields: [],
|
|
383
|
-
name: action.title || action.key
|
|
384
|
-
});
|
|
385
|
-
});
|
|
386
|
-
}
|
|
387
|
-
const typeDefinitions = generateTypeDefinitions(
|
|
388
|
-
app,
|
|
389
|
-
actionsWithFields,
|
|
390
|
-
version
|
|
391
|
-
);
|
|
392
|
-
if (output) {
|
|
393
|
-
fs.mkdirSync(path.dirname(output), { recursive: true });
|
|
394
|
-
fs.writeFileSync(output, typeDefinitions, "utf8");
|
|
395
|
-
}
|
|
396
|
-
return typeDefinitions;
|
|
397
|
-
}
|
|
398
|
-
function parseAppIdentifier(identifier) {
|
|
399
|
-
const parts = identifier.split("@");
|
|
400
|
-
return {
|
|
401
|
-
app: parts[0],
|
|
402
|
-
version: parts[1]
|
|
403
|
-
};
|
|
404
|
-
}
|
|
405
|
-
function generateTypeDefinitions(appKey, actions, version) {
|
|
406
|
-
if (actions.length === 0) {
|
|
407
|
-
return generateEmptyTypesFile(appKey, version);
|
|
408
|
-
}
|
|
409
|
-
const actionsByType = actions.reduce(
|
|
410
|
-
(acc, action) => {
|
|
411
|
-
if (!acc[action.action_type]) {
|
|
412
|
-
acc[action.action_type] = [];
|
|
413
|
-
}
|
|
414
|
-
acc[action.action_type].push(action);
|
|
415
|
-
return acc;
|
|
416
|
-
},
|
|
417
|
-
{}
|
|
418
|
-
);
|
|
419
|
-
const appName = capitalize(appKey);
|
|
420
|
-
const versionComment = version ? ` * Generated for ${appKey}@${version}` : ` * Generated for ${appKey}`;
|
|
421
|
-
let output = `/* eslint-disable @typescript-eslint/naming-convention */
|
|
422
|
-
/**
|
|
423
|
-
* Auto-generated TypeScript types for Zapier ${appKey} actions
|
|
424
|
-
${versionComment}
|
|
425
|
-
* Generated on: ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
426
|
-
*
|
|
427
|
-
* Usage:
|
|
428
|
-
* import type { ${appName}Sdk } from './path/to/this/file'
|
|
429
|
-
* const sdk = createZapierSdk() as unknown as ${appName}Sdk
|
|
430
|
-
*
|
|
431
|
-
* // Direct usage (per-call auth):
|
|
432
|
-
* await sdk.apps.${appKey}.search.user_by_email({ authenticationId: 123, inputs: { email } })
|
|
433
|
-
*
|
|
434
|
-
* // Factory usage (pinned auth):
|
|
435
|
-
* const my${appName} = sdk.apps.${appKey}({ authenticationId: 123 })
|
|
436
|
-
* await my${appName}.search.user_by_email({ inputs: { email } })
|
|
437
|
-
*/
|
|
438
|
-
|
|
439
|
-
import type { ActionExecutionOptions, ActionExecutionResult } from '@zapier/zapier-sdk'
|
|
440
|
-
import { z } from 'zod'
|
|
441
|
-
import { RelayFetchSchema } from '@zapier/zapier-sdk'
|
|
442
|
-
|
|
443
|
-
`;
|
|
444
|
-
actions.forEach((action) => {
|
|
445
|
-
if (action.inputFields.length > 0) {
|
|
446
|
-
const inputTypeName = `${appName}${capitalize(action.action_type)}${capitalize(
|
|
447
|
-
sanitizeActionName(action.key)
|
|
448
|
-
)}Inputs`;
|
|
449
|
-
output += `interface ${inputTypeName} {
|
|
450
|
-
`;
|
|
451
|
-
action.inputFields.forEach((field) => {
|
|
452
|
-
const isOptional = !field.required;
|
|
453
|
-
const fieldType = mapFieldTypeToTypeScript(field);
|
|
454
|
-
const description = field.helpText ? ` /** ${escapeComment(field.helpText)} */
|
|
455
|
-
` : "";
|
|
456
|
-
output += `${description} ${sanitizeFieldName(field.key)}${isOptional ? "?" : ""}: ${fieldType}
|
|
457
|
-
`;
|
|
458
|
-
});
|
|
459
|
-
output += `}
|
|
460
|
-
|
|
461
|
-
`;
|
|
462
|
-
}
|
|
463
|
-
});
|
|
464
|
-
Object.entries(actionsByType).forEach(([actionType, typeActions]) => {
|
|
465
|
-
const typeName = `${appName}${capitalize(actionType)}Actions`;
|
|
466
|
-
output += `interface ${typeName} {
|
|
467
|
-
`;
|
|
468
|
-
typeActions.forEach((action) => {
|
|
469
|
-
const actionName = sanitizeActionName(action.key);
|
|
470
|
-
const description = action.description ? ` /** ${escapeComment(action.description)} */
|
|
471
|
-
` : "";
|
|
472
|
-
if (action.inputFields.length > 0) {
|
|
473
|
-
const inputTypeName = `${appName}${capitalize(action.action_type)}${capitalize(
|
|
474
|
-
sanitizeActionName(action.key)
|
|
475
|
-
)}Inputs`;
|
|
476
|
-
output += `${description} ${actionName}: (options: { inputs: ${inputTypeName} } & Omit<ActionExecutionOptions, 'inputs'>) => Promise<ActionExecutionResult>
|
|
477
|
-
`;
|
|
478
|
-
} else {
|
|
479
|
-
output += `${description} ${actionName}: (options?: { inputs?: Record<string, any> } & ActionExecutionOptions) => Promise<ActionExecutionResult>
|
|
480
|
-
`;
|
|
481
|
-
}
|
|
482
|
-
});
|
|
483
|
-
output += `}
|
|
484
|
-
|
|
485
|
-
`;
|
|
486
|
-
});
|
|
487
|
-
output += `interface ${appName}AppProxy {
|
|
488
|
-
`;
|
|
489
|
-
Object.keys(actionsByType).forEach((actionType) => {
|
|
490
|
-
const typeName = `${appName}${capitalize(actionType)}Actions`;
|
|
491
|
-
output += ` ${actionType}: ${typeName}
|
|
492
|
-
`;
|
|
493
|
-
});
|
|
494
|
-
output += generateFetchMethodSignature() + "\n";
|
|
495
|
-
output += `}
|
|
496
|
-
|
|
497
|
-
`;
|
|
498
|
-
output += `interface ${appName}AppFactory {
|
|
499
|
-
`;
|
|
500
|
-
output += ` (options: { authenticationId: number }): ${appName}AppProxy
|
|
501
|
-
`;
|
|
502
|
-
output += `}
|
|
503
|
-
|
|
504
|
-
`;
|
|
505
|
-
output += `type ${appName}AppWithFactory = ${appName}AppFactory & ${appName}AppProxy
|
|
506
|
-
|
|
507
|
-
`;
|
|
508
|
-
output += `export interface ${appName}Sdk {
|
|
509
|
-
`;
|
|
510
|
-
output += ` apps: {
|
|
511
|
-
`;
|
|
512
|
-
output += ` ${appKey}: ${appName}AppWithFactory
|
|
513
|
-
`;
|
|
514
|
-
output += ` }
|
|
515
|
-
`;
|
|
516
|
-
output += `}
|
|
517
|
-
`;
|
|
518
|
-
return output;
|
|
519
|
-
}
|
|
520
|
-
function generateEmptyTypesFile(appKey, version) {
|
|
521
|
-
const appName = capitalize(appKey);
|
|
522
|
-
const versionComment = version ? ` * Generated for ${appKey}@${version}` : ` * Generated for ${appKey}`;
|
|
523
|
-
return `/* eslint-disable @typescript-eslint/naming-convention */
|
|
524
|
-
/**
|
|
525
|
-
* Auto-generated TypeScript types for Zapier ${appKey} actions
|
|
526
|
-
${versionComment}
|
|
527
|
-
* Generated on: ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
528
|
-
*
|
|
529
|
-
* No actions found for this app.
|
|
530
|
-
*/
|
|
531
|
-
|
|
532
|
-
import type { ActionExecutionOptions, ActionExecutionResult } from '@zapier/zapier-sdk'
|
|
533
|
-
import { z } from 'zod'
|
|
534
|
-
import { RelayFetchSchema } from '@zapier/zapier-sdk'
|
|
535
|
-
|
|
536
|
-
interface ${appName}AppProxy {
|
|
537
|
-
// No actions available
|
|
538
|
-
${generateFetchMethodSignature()}
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
interface ${appName}AppFactory {
|
|
542
|
-
(options: { authenticationId: number }): ${appName}AppProxy
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
type ${appName}AppWithFactory = ${appName}AppFactory & ${appName}AppProxy
|
|
546
|
-
|
|
547
|
-
export interface ${appName}Sdk {
|
|
548
|
-
apps: {
|
|
549
|
-
${appKey}: ${appName}AppWithFactory
|
|
550
|
-
}
|
|
551
|
-
}
|
|
552
|
-
`;
|
|
553
|
-
}
|
|
554
|
-
function capitalize(str) {
|
|
555
|
-
return str.charAt(0).toUpperCase() + str.slice(1).replace(/[-_]/g, "");
|
|
556
|
-
}
|
|
557
|
-
function sanitizeActionName(actionKey) {
|
|
558
|
-
let sanitized = actionKey.replace(/[^a-zA-Z0-9_$]/g, "_");
|
|
559
|
-
if (/^[0-9]/.test(sanitized)) {
|
|
560
|
-
sanitized = "_" + sanitized;
|
|
561
|
-
}
|
|
562
|
-
return sanitized;
|
|
563
|
-
}
|
|
564
|
-
function sanitizeFieldName(fieldKey) {
|
|
565
|
-
let sanitized = fieldKey.replace(/[^a-zA-Z0-9_$]/g, "_");
|
|
566
|
-
if (/^[0-9]/.test(sanitized)) {
|
|
567
|
-
sanitized = "_" + sanitized;
|
|
568
|
-
}
|
|
569
|
-
return sanitized;
|
|
570
|
-
}
|
|
571
|
-
function escapeComment(comment) {
|
|
572
|
-
return comment.replace(/\*\//g, "*\\/").replace(/\r?\n/g, " ");
|
|
573
|
-
}
|
|
574
|
-
function mapFieldTypeToTypeScript(field) {
|
|
575
|
-
if (field.choices && field.choices.length > 0) {
|
|
576
|
-
const choiceValues = field.choices.filter(
|
|
577
|
-
(choice) => choice.value !== void 0 && choice.value !== null && choice.value !== ""
|
|
578
|
-
).map(
|
|
579
|
-
(choice) => typeof choice.value === "string" ? `"${choice.value}"` : choice.value
|
|
580
|
-
);
|
|
581
|
-
if (choiceValues.length > 0) {
|
|
582
|
-
return choiceValues.join(" | ");
|
|
583
|
-
}
|
|
584
|
-
}
|
|
585
|
-
switch (field.type?.toLowerCase()) {
|
|
586
|
-
case "string":
|
|
587
|
-
case "text":
|
|
588
|
-
case "email":
|
|
589
|
-
case "url":
|
|
590
|
-
case "password":
|
|
591
|
-
return "string";
|
|
592
|
-
case "integer":
|
|
593
|
-
case "number":
|
|
594
|
-
return "number";
|
|
595
|
-
case "boolean":
|
|
596
|
-
return "boolean";
|
|
597
|
-
case "datetime":
|
|
598
|
-
case "date":
|
|
599
|
-
return "string";
|
|
600
|
-
// ISO date strings
|
|
601
|
-
case "file":
|
|
602
|
-
return "string";
|
|
603
|
-
// File URL or content
|
|
604
|
-
case "array":
|
|
605
|
-
return "any[]";
|
|
606
|
-
case "object":
|
|
607
|
-
return "Record<string, any>";
|
|
608
|
-
default:
|
|
609
|
-
return "string | number | boolean";
|
|
610
|
-
}
|
|
611
|
-
}
|
|
612
298
|
var BundleCodeSchema = z.object({
|
|
613
299
|
input: z.string().min(1).describe("Input TypeScript file path to bundle"),
|
|
614
300
|
output: OutputPropertySchema.optional().describe(
|
|
@@ -700,21 +386,725 @@ async function bundleCode(options) {
|
|
|
700
386
|
);
|
|
701
387
|
}
|
|
702
388
|
}
|
|
703
|
-
var
|
|
704
|
-
var
|
|
705
|
-
const
|
|
706
|
-
async function
|
|
389
|
+
var GetLoginConfigPathSchema = z.object({}).describe("Show the path to the login configuration file");
|
|
390
|
+
var getLoginConfigPathPlugin = () => {
|
|
391
|
+
const getLoginConfigPathWithSdk = createFunction(
|
|
392
|
+
async function getLoginConfigPathWithSdk2(_options) {
|
|
707
393
|
return getConfigPath();
|
|
708
394
|
},
|
|
709
|
-
|
|
395
|
+
GetLoginConfigPathSchema
|
|
710
396
|
);
|
|
711
397
|
return {
|
|
712
|
-
|
|
398
|
+
getLoginConfigPath: getLoginConfigPathWithSdk,
|
|
399
|
+
context: {
|
|
400
|
+
meta: {
|
|
401
|
+
getLoginConfigPath: {
|
|
402
|
+
categories: ["utility"],
|
|
403
|
+
inputSchema: GetLoginConfigPathSchema
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
};
|
|
408
|
+
};
|
|
409
|
+
var AddSchema = z.object({
|
|
410
|
+
appKeys: z.array(z.string().min(1, "App key cannot be empty")).min(1, "At least one app key is required"),
|
|
411
|
+
authenticationIds: z.array(z.string()).optional().describe("Authentication IDs to use for type generation"),
|
|
412
|
+
configPath: z.string().optional().describe(
|
|
413
|
+
`Path to Zapier config file (defaults to '${DEFAULT_CONFIG_PATH}')`
|
|
414
|
+
),
|
|
415
|
+
typesOutput: z.string().optional().describe(
|
|
416
|
+
"Directory for TypeScript type files (defaults to (src|lib|.)/zapier/apps/)"
|
|
417
|
+
)
|
|
418
|
+
});
|
|
419
|
+
var AstTypeGenerator = class {
|
|
420
|
+
constructor() {
|
|
421
|
+
this.factory = ts.factory;
|
|
422
|
+
this.printer = ts.createPrinter({
|
|
423
|
+
newLine: ts.NewLineKind.LineFeed,
|
|
424
|
+
removeComments: false,
|
|
425
|
+
omitTrailingSemicolon: false
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* Generate TypeScript types using AST for a specific app
|
|
430
|
+
*/
|
|
431
|
+
async generateTypes(options) {
|
|
432
|
+
const { appKey, authenticationId, sdk } = options;
|
|
433
|
+
const { app, version } = this.parseAppIdentifier(appKey);
|
|
434
|
+
const actionsResult = await sdk.listActions({
|
|
435
|
+
appKey: app
|
|
436
|
+
});
|
|
437
|
+
const actions = actionsResult.data;
|
|
438
|
+
if (actions.length === 0) {
|
|
439
|
+
return this.generateEmptyTypesFile(app, version);
|
|
440
|
+
}
|
|
441
|
+
const actionsWithFields = [];
|
|
442
|
+
if (authenticationId) {
|
|
443
|
+
for (const action of actions) {
|
|
444
|
+
try {
|
|
445
|
+
const fieldsResult = await sdk.listInputFields({
|
|
446
|
+
appKey,
|
|
447
|
+
actionKey: action.key,
|
|
448
|
+
actionType: action.action_type,
|
|
449
|
+
authenticationId
|
|
450
|
+
});
|
|
451
|
+
const fields = fieldsResult.data.map(
|
|
452
|
+
(field) => {
|
|
453
|
+
const fieldObj = field;
|
|
454
|
+
return {
|
|
455
|
+
...fieldObj,
|
|
456
|
+
required: fieldObj.is_required || fieldObj.required || false
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
);
|
|
460
|
+
actionsWithFields.push({
|
|
461
|
+
...action,
|
|
462
|
+
inputFields: fields,
|
|
463
|
+
name: action.title || action.key
|
|
464
|
+
});
|
|
465
|
+
} catch {
|
|
466
|
+
actionsWithFields.push({
|
|
467
|
+
...action,
|
|
468
|
+
inputFields: [],
|
|
469
|
+
name: action.title || action.key
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
} else {
|
|
474
|
+
actions.forEach(
|
|
475
|
+
(action) => {
|
|
476
|
+
actionsWithFields.push({
|
|
477
|
+
...action,
|
|
478
|
+
inputFields: [],
|
|
479
|
+
name: action.title || action.key,
|
|
480
|
+
app_key: action.app_key || appKey,
|
|
481
|
+
action_type: action.action_type || "write",
|
|
482
|
+
title: action.title || action.key,
|
|
483
|
+
type: "action",
|
|
484
|
+
description: action.description || ""
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
);
|
|
488
|
+
}
|
|
489
|
+
const sourceFile = this.createSourceFile(app, actionsWithFields, version);
|
|
490
|
+
return this.printer.printFile(sourceFile);
|
|
491
|
+
}
|
|
492
|
+
parseAppIdentifier(identifier) {
|
|
493
|
+
const parts = identifier.split("@");
|
|
494
|
+
return {
|
|
495
|
+
app: parts[0],
|
|
496
|
+
version: parts[1]
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
createSourceFile(appKey, actions, version) {
|
|
500
|
+
const appName = this.capitalize(appKey);
|
|
501
|
+
const versionComment = version ? ` * Generated for ${appKey}@${version}` : ` * Generated for ${appKey}`;
|
|
502
|
+
const headerComment = `Auto-generated TypeScript types for Zapier ${appKey} actions
|
|
503
|
+
${versionComment.slice(3)}
|
|
504
|
+
Generated on: ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
505
|
+
|
|
506
|
+
This file automatically augments the base SDK types when present.
|
|
507
|
+
No manual imports or type casting required.
|
|
508
|
+
|
|
509
|
+
Usage:
|
|
510
|
+
import { createZapierSdk } from "@zapier/zapier-sdk";
|
|
511
|
+
|
|
512
|
+
const zapier = createZapierSdk();
|
|
513
|
+
// Types are automatically available:
|
|
514
|
+
await zapier.apps.${appKey}.search.user_by_email({ authenticationId: 123, inputs: { email } })
|
|
515
|
+
|
|
516
|
+
// Factory usage (pinned auth):
|
|
517
|
+
const my${appName} = zapier.apps.${appKey}({ authenticationId: 123 })
|
|
518
|
+
await my${appName}.search.user_by_email({ inputs: { email } })`;
|
|
519
|
+
const statements = [
|
|
520
|
+
// Import the SDK to activate module augmentation
|
|
521
|
+
this.createImportStatement(["@zapier/zapier-sdk"]),
|
|
522
|
+
// Import types we'll use
|
|
523
|
+
this.createTypeImportStatement(
|
|
524
|
+
[
|
|
525
|
+
"ActionExecutionOptions",
|
|
526
|
+
"ActionExecutionResult",
|
|
527
|
+
"ZapierFetchInitOptions"
|
|
528
|
+
],
|
|
529
|
+
"@zapier/zapier-sdk"
|
|
530
|
+
)
|
|
531
|
+
];
|
|
532
|
+
const actionsByType = this.groupActionsByType(actions);
|
|
533
|
+
actions.forEach((action) => {
|
|
534
|
+
if (action.inputFields.length > 0) {
|
|
535
|
+
const inputInterface = this.createInputInterface(appName, action);
|
|
536
|
+
statements.push(inputInterface);
|
|
537
|
+
}
|
|
538
|
+
});
|
|
539
|
+
Object.entries(actionsByType).forEach(([actionType, typeActions]) => {
|
|
540
|
+
const actionInterface = this.createActionInterface(
|
|
541
|
+
appName,
|
|
542
|
+
actionType,
|
|
543
|
+
typeActions
|
|
544
|
+
);
|
|
545
|
+
statements.push(actionInterface);
|
|
546
|
+
});
|
|
547
|
+
const appProxyInterface = this.createAppProxyInterface(
|
|
548
|
+
appName,
|
|
549
|
+
actionsByType
|
|
550
|
+
);
|
|
551
|
+
statements.push(appProxyInterface);
|
|
552
|
+
const appFactoryInterface = this.createAppFactoryInterface(appName);
|
|
553
|
+
statements.push(appFactoryInterface);
|
|
554
|
+
const appWithFactoryType = this.createAppWithFactoryType(appName);
|
|
555
|
+
statements.push(appWithFactoryType);
|
|
556
|
+
const moduleAugmentation = this.createModuleAugmentation(appKey, appName);
|
|
557
|
+
statements.push(moduleAugmentation);
|
|
558
|
+
statements.push(
|
|
559
|
+
this.factory.createExportDeclaration(
|
|
560
|
+
void 0,
|
|
561
|
+
false,
|
|
562
|
+
this.factory.createNamedExports([])
|
|
563
|
+
)
|
|
564
|
+
);
|
|
565
|
+
const sourceFile = ts.createSourceFile(
|
|
566
|
+
"generated.d.ts",
|
|
567
|
+
"",
|
|
568
|
+
ts.ScriptTarget.Latest,
|
|
569
|
+
false,
|
|
570
|
+
ts.ScriptKind.TS
|
|
571
|
+
);
|
|
572
|
+
if (statements.length > 0) {
|
|
573
|
+
ts.addSyntheticLeadingComment(
|
|
574
|
+
statements[0],
|
|
575
|
+
ts.SyntaxKind.MultiLineCommentTrivia,
|
|
576
|
+
" eslint-disable @typescript-eslint/naming-convention, @typescript-eslint/no-explicit-any ",
|
|
577
|
+
true
|
|
578
|
+
);
|
|
579
|
+
ts.addSyntheticLeadingComment(
|
|
580
|
+
statements[0],
|
|
581
|
+
ts.SyntaxKind.MultiLineCommentTrivia,
|
|
582
|
+
headerComment,
|
|
583
|
+
true
|
|
584
|
+
);
|
|
585
|
+
}
|
|
586
|
+
return this.factory.updateSourceFile(sourceFile, statements);
|
|
587
|
+
}
|
|
588
|
+
createImportStatement(imports, from) {
|
|
589
|
+
if (imports.length === 1 && !from && imports[0].startsWith("@")) {
|
|
590
|
+
return this.factory.createImportDeclaration(
|
|
591
|
+
void 0,
|
|
592
|
+
void 0,
|
|
593
|
+
this.factory.createStringLiteral(imports[0]),
|
|
594
|
+
void 0
|
|
595
|
+
);
|
|
596
|
+
}
|
|
597
|
+
const fromModule = from || imports[0];
|
|
598
|
+
const importNames = from ? imports : [];
|
|
599
|
+
return this.factory.createImportDeclaration(
|
|
600
|
+
void 0,
|
|
601
|
+
importNames.length > 0 ? this.factory.createImportClause(
|
|
602
|
+
false,
|
|
603
|
+
void 0,
|
|
604
|
+
this.factory.createNamedImports(
|
|
605
|
+
importNames.map(
|
|
606
|
+
(name) => this.factory.createImportSpecifier(
|
|
607
|
+
false,
|
|
608
|
+
void 0,
|
|
609
|
+
this.factory.createIdentifier(name)
|
|
610
|
+
)
|
|
611
|
+
)
|
|
612
|
+
)
|
|
613
|
+
) : void 0,
|
|
614
|
+
this.factory.createStringLiteral(fromModule),
|
|
615
|
+
void 0
|
|
616
|
+
);
|
|
617
|
+
}
|
|
618
|
+
createTypeImportStatement(imports, from) {
|
|
619
|
+
return this.factory.createImportDeclaration(
|
|
620
|
+
void 0,
|
|
621
|
+
this.factory.createImportClause(
|
|
622
|
+
true,
|
|
623
|
+
// typeOnly: true
|
|
624
|
+
void 0,
|
|
625
|
+
this.factory.createNamedImports(
|
|
626
|
+
imports.map(
|
|
627
|
+
(name) => this.factory.createImportSpecifier(
|
|
628
|
+
false,
|
|
629
|
+
void 0,
|
|
630
|
+
this.factory.createIdentifier(name)
|
|
631
|
+
)
|
|
632
|
+
)
|
|
633
|
+
)
|
|
634
|
+
),
|
|
635
|
+
this.factory.createStringLiteral(from),
|
|
636
|
+
void 0
|
|
637
|
+
);
|
|
638
|
+
}
|
|
639
|
+
groupActionsByType(actions) {
|
|
640
|
+
return actions.reduce(
|
|
641
|
+
(acc, action) => {
|
|
642
|
+
if (!acc[action.action_type]) {
|
|
643
|
+
acc[action.action_type] = [];
|
|
644
|
+
}
|
|
645
|
+
acc[action.action_type].push(action);
|
|
646
|
+
return acc;
|
|
647
|
+
},
|
|
648
|
+
{}
|
|
649
|
+
);
|
|
650
|
+
}
|
|
651
|
+
createInputInterface(appName, action) {
|
|
652
|
+
const inputTypeName = `${appName}${this.capitalize(action.action_type)}${this.capitalize(
|
|
653
|
+
this.sanitizeActionName(action.key)
|
|
654
|
+
)}Inputs`;
|
|
655
|
+
const properties = action.inputFields.map((field) => {
|
|
656
|
+
const fieldType = this.mapFieldTypeToTypeNode(field);
|
|
657
|
+
const isOptional = !field.required;
|
|
658
|
+
let property = this.factory.createPropertySignature(
|
|
659
|
+
void 0,
|
|
660
|
+
this.sanitizeFieldName(field.key),
|
|
661
|
+
isOptional ? this.factory.createToken(ts.SyntaxKind.QuestionToken) : void 0,
|
|
662
|
+
fieldType
|
|
663
|
+
);
|
|
664
|
+
if (field.helpText) {
|
|
665
|
+
property = ts.addSyntheticLeadingComment(
|
|
666
|
+
property,
|
|
667
|
+
ts.SyntaxKind.MultiLineCommentTrivia,
|
|
668
|
+
`* ${this.escapeComment(field.helpText)} `,
|
|
669
|
+
true
|
|
670
|
+
);
|
|
671
|
+
}
|
|
672
|
+
return property;
|
|
673
|
+
});
|
|
674
|
+
return this.factory.createInterfaceDeclaration(
|
|
675
|
+
void 0,
|
|
676
|
+
inputTypeName,
|
|
677
|
+
void 0,
|
|
678
|
+
void 0,
|
|
679
|
+
properties
|
|
680
|
+
);
|
|
681
|
+
}
|
|
682
|
+
createActionInterface(appName, actionType, typeActions) {
|
|
683
|
+
const typeName = `${appName}${this.capitalize(actionType)}Actions`;
|
|
684
|
+
const methods = typeActions.map((action) => {
|
|
685
|
+
const actionName = this.sanitizeActionName(action.key);
|
|
686
|
+
let methodSignature;
|
|
687
|
+
if (action.inputFields.length > 0) {
|
|
688
|
+
const inputTypeName = `${appName}${this.capitalize(action.action_type)}${this.capitalize(
|
|
689
|
+
this.sanitizeActionName(action.key)
|
|
690
|
+
)}Inputs`;
|
|
691
|
+
const inputsType = this.factory.createTypeLiteralNode([
|
|
692
|
+
this.factory.createPropertySignature(
|
|
693
|
+
void 0,
|
|
694
|
+
"inputs",
|
|
695
|
+
void 0,
|
|
696
|
+
this.factory.createTypeReferenceNode(inputTypeName)
|
|
697
|
+
)
|
|
698
|
+
]);
|
|
699
|
+
const omitType = this.factory.createTypeReferenceNode("Omit", [
|
|
700
|
+
this.factory.createTypeReferenceNode("ActionExecutionOptions"),
|
|
701
|
+
this.factory.createLiteralTypeNode(
|
|
702
|
+
this.factory.createStringLiteral("inputs")
|
|
703
|
+
)
|
|
704
|
+
]);
|
|
705
|
+
const optionsType = this.factory.createIntersectionTypeNode([
|
|
706
|
+
inputsType,
|
|
707
|
+
omitType
|
|
708
|
+
]);
|
|
709
|
+
methodSignature = this.factory.createMethodSignature(
|
|
710
|
+
void 0,
|
|
711
|
+
actionName,
|
|
712
|
+
void 0,
|
|
713
|
+
void 0,
|
|
714
|
+
[
|
|
715
|
+
this.factory.createParameterDeclaration(
|
|
716
|
+
void 0,
|
|
717
|
+
void 0,
|
|
718
|
+
"options",
|
|
719
|
+
void 0,
|
|
720
|
+
optionsType
|
|
721
|
+
)
|
|
722
|
+
],
|
|
723
|
+
this.factory.createTypeReferenceNode("Promise", [
|
|
724
|
+
this.factory.createTypeReferenceNode("ActionExecutionResult")
|
|
725
|
+
])
|
|
726
|
+
);
|
|
727
|
+
} else {
|
|
728
|
+
const genericInputsType = this.factory.createTypeLiteralNode([
|
|
729
|
+
this.factory.createPropertySignature(
|
|
730
|
+
void 0,
|
|
731
|
+
"inputs",
|
|
732
|
+
this.factory.createToken(ts.SyntaxKind.QuestionToken),
|
|
733
|
+
this.factory.createTypeReferenceNode("Record", [
|
|
734
|
+
this.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
|
|
735
|
+
this.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)
|
|
736
|
+
])
|
|
737
|
+
)
|
|
738
|
+
]);
|
|
739
|
+
const intersectionType = this.factory.createIntersectionTypeNode([
|
|
740
|
+
genericInputsType,
|
|
741
|
+
this.factory.createTypeReferenceNode("ActionExecutionOptions")
|
|
742
|
+
]);
|
|
743
|
+
methodSignature = this.factory.createMethodSignature(
|
|
744
|
+
void 0,
|
|
745
|
+
actionName,
|
|
746
|
+
void 0,
|
|
747
|
+
void 0,
|
|
748
|
+
[
|
|
749
|
+
this.factory.createParameterDeclaration(
|
|
750
|
+
void 0,
|
|
751
|
+
void 0,
|
|
752
|
+
"options",
|
|
753
|
+
this.factory.createToken(ts.SyntaxKind.QuestionToken),
|
|
754
|
+
intersectionType
|
|
755
|
+
)
|
|
756
|
+
],
|
|
757
|
+
this.factory.createTypeReferenceNode("Promise", [
|
|
758
|
+
this.factory.createTypeReferenceNode("ActionExecutionResult")
|
|
759
|
+
])
|
|
760
|
+
);
|
|
761
|
+
}
|
|
762
|
+
if (action.description) {
|
|
763
|
+
methodSignature = ts.addSyntheticLeadingComment(
|
|
764
|
+
methodSignature,
|
|
765
|
+
ts.SyntaxKind.MultiLineCommentTrivia,
|
|
766
|
+
`* ${this.escapeComment(action.description)} `,
|
|
767
|
+
true
|
|
768
|
+
);
|
|
769
|
+
}
|
|
770
|
+
return methodSignature;
|
|
771
|
+
});
|
|
772
|
+
return this.factory.createInterfaceDeclaration(
|
|
773
|
+
void 0,
|
|
774
|
+
typeName,
|
|
775
|
+
void 0,
|
|
776
|
+
void 0,
|
|
777
|
+
methods
|
|
778
|
+
);
|
|
779
|
+
}
|
|
780
|
+
createAppProxyInterface(appName, actionsByType) {
|
|
781
|
+
const properties = [
|
|
782
|
+
...Object.keys(actionsByType).map(
|
|
783
|
+
(actionType) => this.factory.createPropertySignature(
|
|
784
|
+
void 0,
|
|
785
|
+
actionType,
|
|
786
|
+
void 0,
|
|
787
|
+
this.factory.createTypeReferenceNode(
|
|
788
|
+
`${appName}${this.capitalize(actionType)}Actions`
|
|
789
|
+
)
|
|
790
|
+
)
|
|
791
|
+
),
|
|
792
|
+
// Always include fetch method for authenticated HTTP requests
|
|
793
|
+
this.createFetchMethodProperty()
|
|
794
|
+
];
|
|
795
|
+
return this.factory.createInterfaceDeclaration(
|
|
796
|
+
void 0,
|
|
797
|
+
`${appName}AppProxy`,
|
|
798
|
+
void 0,
|
|
799
|
+
void 0,
|
|
800
|
+
properties
|
|
801
|
+
);
|
|
802
|
+
}
|
|
803
|
+
createFetchMethodProperty() {
|
|
804
|
+
let property = this.factory.createPropertySignature(
|
|
805
|
+
void 0,
|
|
806
|
+
"fetch",
|
|
807
|
+
void 0,
|
|
808
|
+
this.factory.createFunctionTypeNode(
|
|
809
|
+
void 0,
|
|
810
|
+
[
|
|
811
|
+
this.factory.createParameterDeclaration(
|
|
812
|
+
void 0,
|
|
813
|
+
void 0,
|
|
814
|
+
"url",
|
|
815
|
+
void 0,
|
|
816
|
+
this.factory.createUnionTypeNode([
|
|
817
|
+
this.factory.createTypeReferenceNode("string"),
|
|
818
|
+
this.factory.createTypeReferenceNode("URL")
|
|
819
|
+
])
|
|
820
|
+
),
|
|
821
|
+
this.factory.createParameterDeclaration(
|
|
822
|
+
void 0,
|
|
823
|
+
void 0,
|
|
824
|
+
"init",
|
|
825
|
+
this.factory.createToken(ts.SyntaxKind.QuestionToken),
|
|
826
|
+
this.factory.createTypeReferenceNode("ZapierFetchInitOptions")
|
|
827
|
+
)
|
|
828
|
+
],
|
|
829
|
+
this.factory.createTypeReferenceNode("Promise", [
|
|
830
|
+
this.factory.createTypeReferenceNode("Response")
|
|
831
|
+
])
|
|
832
|
+
)
|
|
833
|
+
);
|
|
834
|
+
property = ts.addSyntheticLeadingComment(
|
|
835
|
+
property,
|
|
836
|
+
ts.SyntaxKind.MultiLineCommentTrivia,
|
|
837
|
+
"* Make authenticated HTTP requests through Zapier's Relay service ",
|
|
838
|
+
true
|
|
839
|
+
);
|
|
840
|
+
return property;
|
|
841
|
+
}
|
|
842
|
+
createAppFactoryInterface(appName) {
|
|
843
|
+
const callSignature = this.factory.createCallSignature(
|
|
844
|
+
void 0,
|
|
845
|
+
[
|
|
846
|
+
this.factory.createParameterDeclaration(
|
|
847
|
+
void 0,
|
|
848
|
+
void 0,
|
|
849
|
+
"options",
|
|
850
|
+
void 0,
|
|
851
|
+
this.factory.createTypeLiteralNode([
|
|
852
|
+
this.factory.createPropertySignature(
|
|
853
|
+
void 0,
|
|
854
|
+
"authenticationId",
|
|
855
|
+
void 0,
|
|
856
|
+
this.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword)
|
|
857
|
+
)
|
|
858
|
+
])
|
|
859
|
+
)
|
|
860
|
+
],
|
|
861
|
+
this.factory.createTypeReferenceNode(`${appName}AppProxy`)
|
|
862
|
+
);
|
|
863
|
+
return this.factory.createInterfaceDeclaration(
|
|
864
|
+
void 0,
|
|
865
|
+
`${appName}AppFactory`,
|
|
866
|
+
void 0,
|
|
867
|
+
void 0,
|
|
868
|
+
[callSignature]
|
|
869
|
+
);
|
|
870
|
+
}
|
|
871
|
+
createAppWithFactoryType(appName) {
|
|
872
|
+
return this.factory.createTypeAliasDeclaration(
|
|
873
|
+
void 0,
|
|
874
|
+
`${appName}AppWithFactory`,
|
|
875
|
+
void 0,
|
|
876
|
+
this.factory.createIntersectionTypeNode([
|
|
877
|
+
this.factory.createTypeReferenceNode(`${appName}AppFactory`),
|
|
878
|
+
this.factory.createTypeReferenceNode(`${appName}AppProxy`)
|
|
879
|
+
])
|
|
880
|
+
);
|
|
881
|
+
}
|
|
882
|
+
createModuleAugmentation(appKey, appName) {
|
|
883
|
+
return this.factory.createModuleDeclaration(
|
|
884
|
+
[this.factory.createToken(ts.SyntaxKind.DeclareKeyword)],
|
|
885
|
+
this.factory.createStringLiteral("@zapier/zapier-sdk"),
|
|
886
|
+
this.factory.createModuleBlock([
|
|
887
|
+
this.factory.createInterfaceDeclaration(
|
|
888
|
+
void 0,
|
|
889
|
+
"ZapierSdkApps",
|
|
890
|
+
void 0,
|
|
891
|
+
void 0,
|
|
892
|
+
[
|
|
893
|
+
this.factory.createPropertySignature(
|
|
894
|
+
void 0,
|
|
895
|
+
appKey,
|
|
896
|
+
void 0,
|
|
897
|
+
this.factory.createTypeReferenceNode(`${appName}AppWithFactory`)
|
|
898
|
+
)
|
|
899
|
+
]
|
|
900
|
+
)
|
|
901
|
+
])
|
|
902
|
+
);
|
|
903
|
+
}
|
|
904
|
+
mapFieldTypeToTypeNode(field) {
|
|
905
|
+
if (field.choices && field.choices.length > 0) {
|
|
906
|
+
const choiceValues = field.choices.filter(
|
|
907
|
+
(choice) => choice.value !== void 0 && choice.value !== null && choice.value !== ""
|
|
908
|
+
).map(
|
|
909
|
+
(choice) => typeof choice.value === "string" ? this.factory.createLiteralTypeNode(
|
|
910
|
+
this.factory.createStringLiteral(choice.value)
|
|
911
|
+
) : this.factory.createLiteralTypeNode(
|
|
912
|
+
this.factory.createNumericLiteral(String(choice.value))
|
|
913
|
+
)
|
|
914
|
+
);
|
|
915
|
+
if (choiceValues.length > 0) {
|
|
916
|
+
return this.factory.createUnionTypeNode(choiceValues);
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
switch (field.type?.toLowerCase()) {
|
|
920
|
+
case "string":
|
|
921
|
+
case "text":
|
|
922
|
+
case "email":
|
|
923
|
+
case "url":
|
|
924
|
+
case "password":
|
|
925
|
+
case "datetime":
|
|
926
|
+
case "date":
|
|
927
|
+
case "file":
|
|
928
|
+
return this.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword);
|
|
929
|
+
case "integer":
|
|
930
|
+
case "number":
|
|
931
|
+
return this.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword);
|
|
932
|
+
case "boolean":
|
|
933
|
+
return this.factory.createKeywordTypeNode(ts.SyntaxKind.BooleanKeyword);
|
|
934
|
+
case "array":
|
|
935
|
+
return this.factory.createArrayTypeNode(
|
|
936
|
+
this.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)
|
|
937
|
+
);
|
|
938
|
+
case "object":
|
|
939
|
+
return this.factory.createTypeReferenceNode("Record", [
|
|
940
|
+
this.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
|
|
941
|
+
this.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)
|
|
942
|
+
]);
|
|
943
|
+
default:
|
|
944
|
+
return this.factory.createUnionTypeNode([
|
|
945
|
+
this.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
|
|
946
|
+
this.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword),
|
|
947
|
+
this.factory.createKeywordTypeNode(ts.SyntaxKind.BooleanKeyword)
|
|
948
|
+
]);
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
generateEmptyTypesFile(appKey, version) {
|
|
952
|
+
const appName = this.capitalize(appKey);
|
|
953
|
+
const versionComment = version ? ` * Generated for ${appKey}@${version}` : ` * Generated for ${appKey}`;
|
|
954
|
+
return `/* eslint-disable @typescript-eslint/naming-convention, @typescript-eslint/no-explicit-any */
|
|
955
|
+
/**
|
|
956
|
+
* Auto-generated TypeScript types for Zapier ${appKey} actions
|
|
957
|
+
${versionComment}
|
|
958
|
+
* Generated on: ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
959
|
+
*
|
|
960
|
+
* No actions found for this app.
|
|
961
|
+
*/
|
|
962
|
+
|
|
963
|
+
import type { ActionExecutionOptions, ActionExecutionResult, ZapierFetchInitOptions } from '@zapier/zapier-sdk'
|
|
964
|
+
|
|
965
|
+
interface ${appName}AppProxy {
|
|
966
|
+
/** Make authenticated HTTP requests through Zapier's Relay service */
|
|
967
|
+
fetch: (url: string | URL, init?: ZapierFetchInitOptions) => Promise<Response>
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
interface ${appName}AppFactory {
|
|
971
|
+
(options: { authenticationId: number }): ${appName}AppProxy
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
type ${appName}AppWithFactory = ${appName}AppFactory & ${appName}AppProxy
|
|
975
|
+
|
|
976
|
+
declare module "@zapier/zapier-sdk" {
|
|
977
|
+
interface ZapierSdkApps {
|
|
978
|
+
${appKey}: ${appName}AppWithFactory
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
`;
|
|
982
|
+
}
|
|
983
|
+
capitalize(str) {
|
|
984
|
+
return str.charAt(0).toUpperCase() + str.slice(1).replace(/[-_]/g, "");
|
|
985
|
+
}
|
|
986
|
+
sanitizeActionName(actionKey) {
|
|
987
|
+
let sanitized = actionKey.replace(/[^a-zA-Z0-9_$]/g, "_");
|
|
988
|
+
if (/^[0-9]/.test(sanitized)) {
|
|
989
|
+
sanitized = "_" + sanitized;
|
|
990
|
+
}
|
|
991
|
+
return sanitized;
|
|
992
|
+
}
|
|
993
|
+
sanitizeFieldName(fieldKey) {
|
|
994
|
+
let sanitized = fieldKey.replace(/[^a-zA-Z0-9_$]/g, "_");
|
|
995
|
+
if (/^[0-9]/.test(sanitized)) {
|
|
996
|
+
sanitized = "_" + sanitized;
|
|
997
|
+
}
|
|
998
|
+
return sanitized;
|
|
999
|
+
}
|
|
1000
|
+
escapeComment(comment) {
|
|
1001
|
+
return comment.replace(/\*\//g, "*\\/").replace(/\r?\n/g, " ");
|
|
1002
|
+
}
|
|
1003
|
+
};
|
|
1004
|
+
async function detectTypesOutputDirectory() {
|
|
1005
|
+
const candidates = ["src", "lib"];
|
|
1006
|
+
for (const candidate of candidates) {
|
|
1007
|
+
try {
|
|
1008
|
+
await access(candidate);
|
|
1009
|
+
return join(candidate, "zapier", "apps");
|
|
1010
|
+
} catch {
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
return "./zapier/apps/";
|
|
1014
|
+
}
|
|
1015
|
+
var addPlugin = ({ sdk, context }) => {
|
|
1016
|
+
const add = createFunction(async function add2(options) {
|
|
1017
|
+
const {
|
|
1018
|
+
appKeys,
|
|
1019
|
+
authenticationIds,
|
|
1020
|
+
configPath,
|
|
1021
|
+
typesOutput = await detectTypesOutputDirectory()
|
|
1022
|
+
} = options;
|
|
1023
|
+
const resolvedTypesOutput = resolve(typesOutput);
|
|
1024
|
+
await mkdir(resolvedTypesOutput, { recursive: true });
|
|
1025
|
+
console.log(`\u{1F4E6} Looking up ${appKeys.length} app(s)...`);
|
|
1026
|
+
const appsIterator = sdk.listApps({ appKeys }).items();
|
|
1027
|
+
const apps = [];
|
|
1028
|
+
for await (const app of appsIterator) {
|
|
1029
|
+
apps.push(app);
|
|
1030
|
+
}
|
|
1031
|
+
if (apps.length === 0) {
|
|
1032
|
+
console.warn("\u26A0\uFE0F No apps found");
|
|
1033
|
+
return;
|
|
1034
|
+
}
|
|
1035
|
+
let authentications = [];
|
|
1036
|
+
if (authenticationIds && authenticationIds.length > 0) {
|
|
1037
|
+
console.log(
|
|
1038
|
+
`\u{1F510} Looking up ${authenticationIds.length} authentication(s)...`
|
|
1039
|
+
);
|
|
1040
|
+
const authsIterator = sdk.listAuthentications({ authenticationIds }).items();
|
|
1041
|
+
for await (const auth of authsIterator) {
|
|
1042
|
+
authentications.push(auth);
|
|
1043
|
+
}
|
|
1044
|
+
console.log(`\u{1F510} Found ${authentications.length} authentication(s)`);
|
|
1045
|
+
}
|
|
1046
|
+
for (const app of apps) {
|
|
1047
|
+
console.log(`\u{1F4E6} Adding ${app.key}...`);
|
|
1048
|
+
try {
|
|
1049
|
+
const currentImplementationId = app.current_implementation_id;
|
|
1050
|
+
const [implementationName, version] = currentImplementationId.split("@");
|
|
1051
|
+
if (!implementationName || !version) {
|
|
1052
|
+
console.warn(
|
|
1053
|
+
`\u26A0\uFE0F Invalid implementation ID format for '${app.key}': ${currentImplementationId}. Expected format: <implementationName>@<version>. Skipping...`
|
|
1054
|
+
);
|
|
1055
|
+
continue;
|
|
1056
|
+
}
|
|
1057
|
+
const [manifestKey] = await context.updateManifestEntry(
|
|
1058
|
+
app.key,
|
|
1059
|
+
{
|
|
1060
|
+
implementationName,
|
|
1061
|
+
version
|
|
1062
|
+
},
|
|
1063
|
+
configPath
|
|
1064
|
+
);
|
|
1065
|
+
console.log(
|
|
1066
|
+
`\u{1F4DD} Locked ${app.key} to ${implementationName}@${version} using key '${manifestKey}'`
|
|
1067
|
+
);
|
|
1068
|
+
let authenticationId;
|
|
1069
|
+
if (authentications.length > 0) {
|
|
1070
|
+
const matchingAuth = authentications.find((auth) => {
|
|
1071
|
+
return auth.app_key === app.key;
|
|
1072
|
+
});
|
|
1073
|
+
if (matchingAuth) {
|
|
1074
|
+
authenticationId = matchingAuth.id;
|
|
1075
|
+
console.log(
|
|
1076
|
+
`\u{1F510} Using authentication ${authenticationId} (${matchingAuth.title}) for ${app.key}`
|
|
1077
|
+
);
|
|
1078
|
+
} else {
|
|
1079
|
+
console.warn(`\u26A0\uFE0F No matching authentication found for ${app.key}`);
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
const typesPath = join(resolvedTypesOutput, `${manifestKey}.d.ts`);
|
|
1083
|
+
try {
|
|
1084
|
+
const generator = new AstTypeGenerator();
|
|
1085
|
+
const typeDefinitions = await generator.generateTypes({
|
|
1086
|
+
appKey: manifestKey,
|
|
1087
|
+
authenticationId,
|
|
1088
|
+
sdk
|
|
1089
|
+
});
|
|
1090
|
+
await writeFile(typesPath, typeDefinitions, "utf8");
|
|
1091
|
+
console.log(`\u{1F527} Generated types for ${manifestKey} at ${typesPath}`);
|
|
1092
|
+
} catch (error) {
|
|
1093
|
+
console.warn(`\u26A0\uFE0F Failed to generate types for ${app.key}: ${error}`);
|
|
1094
|
+
}
|
|
1095
|
+
} catch (error) {
|
|
1096
|
+
console.warn(`\u26A0\uFE0F Failed to process ${app.key}: ${error}`);
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
console.log(`\u2705 Added ${apps.length} app(s) to manifest`);
|
|
1100
|
+
}, AddSchema);
|
|
1101
|
+
return {
|
|
1102
|
+
add,
|
|
713
1103
|
context: {
|
|
714
1104
|
meta: {
|
|
715
|
-
|
|
1105
|
+
add: {
|
|
716
1106
|
categories: ["utility"],
|
|
717
|
-
inputSchema:
|
|
1107
|
+
inputSchema: AddSchema
|
|
718
1108
|
}
|
|
719
1109
|
}
|
|
720
1110
|
}
|
|
@@ -726,9 +1116,9 @@ function createZapierCliSdk(options = {}) {
|
|
|
726
1116
|
let sdk = createZapierSdkWithoutRegistry({
|
|
727
1117
|
debug: options.debug
|
|
728
1118
|
});
|
|
729
|
-
sdk = sdk.addPlugin(generateTypesPlugin);
|
|
730
1119
|
sdk = sdk.addPlugin(bundleCodePlugin);
|
|
731
|
-
sdk = sdk.addPlugin(
|
|
1120
|
+
sdk = sdk.addPlugin(getLoginConfigPathPlugin);
|
|
1121
|
+
sdk = sdk.addPlugin(addPlugin);
|
|
732
1122
|
sdk = sdk.addPlugin(mcpPlugin);
|
|
733
1123
|
sdk = sdk.addPlugin(loginPlugin);
|
|
734
1124
|
sdk = sdk.addPlugin(logoutPlugin);
|