@zapier/zapier-sdk-cli 0.8.4 → 0.10.0

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