@zapier/zapier-sdk-cli 0.8.3 → 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.
Files changed (45) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +35 -51
  3. package/dist/cli.cjs +750 -346
  4. package/dist/cli.mjs +751 -347
  5. package/dist/index.cjs +726 -336
  6. package/dist/index.mjs +727 -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 +122 -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.js +15 -0
  22. package/dist/tsconfig.tsbuildinfo +1 -1
  23. package/package.json +3 -3
  24. package/src/plugins/add/ast-generator.ts +777 -0
  25. package/src/plugins/add/index.test.ts +58 -0
  26. package/src/plugins/add/index.ts +187 -0
  27. package/src/plugins/add/schemas.ts +26 -0
  28. package/src/plugins/getLoginConfigPath/index.ts +45 -0
  29. package/src/plugins/getLoginConfigPath/schemas.ts +10 -0
  30. package/src/plugins/index.ts +2 -2
  31. package/src/sdk.ts +4 -4
  32. package/src/utils/cli-generator.ts +22 -0
  33. package/tsup.config.ts +1 -1
  34. package/dist/src/plugins/generateTypes/index.d.ts +0 -21
  35. package/dist/src/plugins/generateTypes/index.js +0 -312
  36. package/dist/src/plugins/generateTypes/schemas.d.ts +0 -18
  37. package/dist/src/plugins/generateTypes/schemas.js +0 -14
  38. package/dist/src/plugins/getConfigPath/index.d.ts +0 -15
  39. package/dist/src/plugins/getConfigPath/index.js +0 -19
  40. package/dist/src/plugins/getConfigPath/schemas.d.ts +0 -3
  41. package/dist/src/plugins/getConfigPath/schemas.js +0 -5
  42. package/src/plugins/generateTypes/index.ts +0 -444
  43. package/src/plugins/generateTypes/schemas.ts +0 -23
  44. package/src/plugins/getConfigPath/index.ts +0 -42
  45. package/src/plugins/getConfigPath/schemas.ts +0 -8
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { createFunction, OutputPropertySchema, AuthenticationIdPropertySchema, AppKeyPropertySchema, createZapierSdkWithoutRegistry, registryPlugin } from '@zapier/zapier-sdk';
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 { buildSync } from 'esbuild';
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 resolve2 = () => {
84
+ let resolve3 = () => {
82
85
  };
83
86
  let reject = () => {
84
87
  };
85
88
  const promise = new Promise((_resolve, _reject) => {
86
- resolve2 = _resolve;
89
+ resolve3 = _resolve;
87
90
  reject = _reject;
88
91
  });
89
92
  return {
90
93
  promise,
91
- resolve: resolve2,
94
+ resolve: resolve3,
92
95
  reject
93
96
  };
94
97
  };
95
98
  var getCallablePromise_default = getCallablePromise;
96
99
  var findAvailablePort = () => {
97
- return new Promise((resolve2, reject) => {
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
- resolve2(port);
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((resolve2) => {
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
- resolve2();
199
+ resolve3();
197
200
  }, 1e3);
198
201
  server.close(() => {
199
202
  clearTimeout(timeout);
200
- resolve2();
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 GetConfigPathSchema = z.object({}).describe("Show the path to the configuration file");
704
- var getConfigPathPlugin = () => {
705
- const getConfigPathWithSdk = createFunction(
706
- async function getConfigPathWithSdk2(_options) {
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
- GetConfigPathSchema
395
+ GetLoginConfigPathSchema
710
396
  );
711
397
  return {
712
- getConfigPath: getConfigPathWithSdk,
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
- getConfigPath: {
1105
+ add: {
716
1106
  categories: ["utility"],
717
- inputSchema: GetConfigPathSchema
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(getConfigPathPlugin);
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);