@zapier/zapier-sdk-cli 0.13.0 → 0.13.2

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.
@@ -1,4 +1,5 @@
1
1
  import * as ts from "typescript";
2
+ import { toSnakeCase } from "@zapier/zapier-sdk";
2
3
  /**
3
4
  * AST-based TypeScript type generator using the TypeScript Compiler API
4
5
  */
@@ -15,24 +16,19 @@ export class AstTypeGenerator {
15
16
  * Generate TypeScript types using AST for a specific app
16
17
  */
17
18
  async generateTypes(options) {
18
- const { appKey, authenticationId, sdk } = options;
19
- // Parse app identifier (support app@version format)
20
- const { app, version } = this.parseAppIdentifier(appKey);
21
- // Fetch all actions for the app
19
+ const { app, authenticationId, sdk } = options;
20
+ // Fetch all actions for the app using implementation_id for correct versioning
22
21
  const actionsResult = await sdk.listActions({
23
- appKey: app,
22
+ appKey: app.implementation_id,
24
23
  });
25
24
  const actions = actionsResult.data;
26
- if (actions.length === 0) {
27
- return this.generateEmptyTypesFile(app, version);
28
- }
29
25
  // Fetch input fields for each action
30
26
  const actionsWithFields = [];
31
27
  if (authenticationId) {
32
28
  for (const action of actions) {
33
29
  try {
34
30
  const fieldsResult = await sdk.listInputFields({
35
- appKey: appKey,
31
+ appKey: app.implementation_id,
36
32
  actionKey: action.key,
37
33
  actionType: action.action_type,
38
34
  authenticationId: authenticationId,
@@ -61,7 +57,7 @@ export class AstTypeGenerator {
61
57
  ...action,
62
58
  inputFields: [],
63
59
  name: action.title || action.key,
64
- app_key: action.app_key || appKey,
60
+ app_key: action.app_key || app.implementation_id,
65
61
  action_type: action.action_type || "write",
66
62
  title: action.title || action.key,
67
63
  type: "action",
@@ -70,24 +66,17 @@ export class AstTypeGenerator {
70
66
  });
71
67
  }
72
68
  // Generate TypeScript AST nodes
73
- const sourceFile = this.createSourceFile(app, actionsWithFields, version);
69
+ const sourceFile = this.createSourceFile(app, actionsWithFields);
74
70
  // Print the AST to string
75
71
  return this.printer.printFile(sourceFile);
76
72
  }
77
- parseAppIdentifier(identifier) {
78
- const parts = identifier.split("@");
79
- return {
80
- app: parts[0],
81
- version: parts[1],
82
- };
83
- }
84
- createSourceFile(appKey, actions, version) {
85
- const appName = this.capitalize(appKey);
86
- const versionComment = version
87
- ? ` * Generated for ${appKey}@${version}`
88
- : ` * Generated for ${appKey}`;
73
+ createSourceFile(app, actions) {
74
+ const appName = this.getPreferredAppName(app);
75
+ const versionComment = ` * Generated for ${app.implementation_id}`;
76
+ const preferredKey = this.getPreferredProgrammaticKey(app);
77
+ const myVariableName = `my${appName}`;
89
78
  // Create header comment
90
- const headerComment = `Auto-generated TypeScript types for Zapier ${appKey} actions
79
+ const headerComment = `Auto-generated TypeScript types for Zapier ${app.key} actions
91
80
  ${versionComment.slice(3)}
92
81
  Generated on: ${new Date().toISOString()}
93
82
 
@@ -99,11 +88,11 @@ Usage:
99
88
 
100
89
  const zapier = createZapierSdk();
101
90
  // Types are automatically available:
102
- await zapier.apps.${appKey}.search.user_by_email({ authenticationId: 123, inputs: { email } })
91
+ await zapier.apps.${preferredKey}.search.user_by_email({ authenticationId: 123, inputs: { email } })
103
92
 
104
93
  // Factory usage (pinned auth):
105
- const my${appName} = zapier.apps.${appKey}({ authenticationId: 123 })
106
- await my${appName}.search.user_by_email({ inputs: { email } })`;
94
+ const ${myVariableName} = zapier.apps.${preferredKey}({ authenticationId: 123 })
95
+ await ${myVariableName}.search.user_by_email({ inputs: { email } })`;
107
96
  const statements = [
108
97
  // Import the SDK to activate module augmentation
109
98
  this.createImportStatement(["@zapier/zapier-sdk"]),
@@ -138,7 +127,8 @@ Usage:
138
127
  const appWithFactoryType = this.createAppWithFactoryType(appName);
139
128
  statements.push(appWithFactoryType);
140
129
  // Generate module augmentation for automatic type integration
141
- const moduleAugmentation = this.createModuleAugmentation(appKey, appName);
130
+ const allKeys = this.getAllKeys(app);
131
+ const moduleAugmentation = this.createModuleAugmentation(allKeys, appName);
142
132
  statements.push(moduleAugmentation);
143
133
  // Add empty export to make this a module
144
134
  statements.push(this.factory.createExportDeclaration(undefined, false, this.factory.createNamedExports([])));
@@ -280,13 +270,13 @@ Usage:
280
270
  this.factory.createTypeReferenceNode(`${appName}AppProxy`),
281
271
  ]));
282
272
  }
283
- createModuleAugmentation(appKey, appName) {
273
+ createModuleAugmentation(appKeys, appName) {
284
274
  // Create: declare module "@zapier/zapier-sdk" { interface ZapierSdkApps { [appKey]: AppWithFactory } }
285
275
  // This creates a new interface that we can merge with ZapierSdk
276
+ // Create properties for all keys (main key + other_keys)
277
+ const properties = appKeys.map((appKey) => this.factory.createPropertySignature(undefined, this.createPropertyName(appKey), undefined, this.factory.createTypeReferenceNode(`${appName}AppWithFactory`)));
286
278
  return this.factory.createModuleDeclaration([this.factory.createToken(ts.SyntaxKind.DeclareKeyword)], this.factory.createStringLiteral("@zapier/zapier-sdk"), this.factory.createModuleBlock([
287
- this.factory.createInterfaceDeclaration(undefined, "ZapierSdkApps", undefined, undefined, [
288
- this.factory.createPropertySignature(undefined, appKey, undefined, this.factory.createTypeReferenceNode(`${appName}AppWithFactory`)),
289
- ]),
279
+ this.factory.createInterfaceDeclaration(undefined, "ZapierSdkApps", undefined, undefined, properties),
290
280
  ]));
291
281
  }
292
282
  mapFieldTypeToTypeNode(field) {
@@ -324,40 +314,6 @@ Usage:
324
314
  ]);
325
315
  }
326
316
  }
327
- generateEmptyTypesFile(appKey, version) {
328
- const appName = this.capitalize(appKey);
329
- const versionComment = version
330
- ? ` * Generated for ${appKey}@${version}`
331
- : ` * Generated for ${appKey}`;
332
- return `/* eslint-disable @typescript-eslint/naming-convention, @typescript-eslint/no-explicit-any */
333
- /**
334
- * Auto-generated TypeScript types for Zapier ${appKey} actions
335
- ${versionComment}
336
- * Generated on: ${new Date().toISOString()}
337
- *
338
- * No actions found for this app.
339
- */
340
-
341
- import type { ActionExecutionOptions, ActionExecutionResult, ZapierFetchInitOptions } from '@zapier/zapier-sdk'
342
-
343
- interface ${appName}AppProxy {
344
- /** Make authenticated HTTP requests through Zapier's Relay service */
345
- fetch: (url: string | URL, init?: ZapierFetchInitOptions) => Promise<Response>
346
- }
347
-
348
- interface ${appName}AppFactory {
349
- (options: { authenticationId: number }): ${appName}AppProxy
350
- }
351
-
352
- type ${appName}AppWithFactory = ${appName}AppFactory & ${appName}AppProxy
353
-
354
- declare module "@zapier/zapier-sdk" {
355
- interface ZapierSdkApps {
356
- ${appKey}: ${appName}AppWithFactory
357
- }
358
- }
359
- `;
360
- }
361
317
  capitalize(str) {
362
318
  return str.charAt(0).toUpperCase() + str.slice(1).replace(/[-_]/g, "");
363
319
  }
@@ -383,4 +339,64 @@ declare module "@zapier/zapier-sdk" {
383
339
  // Escape comment text to prevent breaking the JSDoc comment
384
340
  return comment.replace(/\*\//g, "*\\/").replace(/\r?\n/g, " ");
385
341
  }
342
+ createPropertyName(name) {
343
+ // Check if the name is a valid JavaScript identifier
344
+ if (this.isValidIdentifier(name)) {
345
+ return this.factory.createIdentifier(name);
346
+ }
347
+ else {
348
+ // Use string literal for invalid identifiers (e.g., contains dashes)
349
+ return this.factory.createStringLiteral(name);
350
+ }
351
+ }
352
+ isValidIdentifier(name) {
353
+ // JavaScript identifier rules: must start with letter, $, or _,
354
+ // followed by letters, digits, $, or _
355
+ return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
356
+ }
357
+ getPreferredProgrammaticKey(app) {
358
+ // If we have a slug, convert it to snake_case as the preferred programmatic key
359
+ if (app.slug) {
360
+ const snakeCaseSlug = toSnakeCase(app.slug);
361
+ if (this.isValidIdentifier(snakeCaseSlug)) {
362
+ return snakeCaseSlug;
363
+ }
364
+ }
365
+ // Otherwise, use the main key if it's a valid identifier
366
+ if (this.isValidIdentifier(app.key)) {
367
+ return app.key;
368
+ }
369
+ // Fallback: sanitize the key to make it a valid identifier
370
+ return this.sanitizeToIdentifier(app.key);
371
+ }
372
+ getPreferredAppName(app) {
373
+ const preferredKey = this.getPreferredProgrammaticKey(app);
374
+ // If it's snake_case, convert to PascalCase
375
+ if (preferredKey.includes("_")) {
376
+ return preferredKey
377
+ .split("_")
378
+ .map((word) => this.capitalize(word.toLowerCase()))
379
+ .join("");
380
+ }
381
+ // Otherwise, capitalize first letter for PascalCase
382
+ return this.capitalize(preferredKey);
383
+ }
384
+ sanitizeToIdentifier(name) {
385
+ // Convert any string to a valid JavaScript identifier
386
+ let sanitized = name.replace(/[^a-zA-Z0-9_$]/g, "_");
387
+ // If it starts with a number, prepend an underscore
388
+ if (/^[0-9]/.test(sanitized)) {
389
+ sanitized = "_" + sanitized;
390
+ }
391
+ return sanitized;
392
+ }
393
+ getAllKeys(app) {
394
+ // Return all possible keys for this app
395
+ const allKeys = new Set([app.key]);
396
+ if (app.slug) {
397
+ allKeys.add(app.slug);
398
+ allKeys.add(toSnakeCase(app.slug));
399
+ }
400
+ return Array.from(allKeys);
401
+ }
386
402
  }
@@ -87,7 +87,7 @@ export const addPlugin = ({ sdk, context }) => {
87
87
  // Use AST-based generator directly
88
88
  const generator = new AstTypeGenerator();
89
89
  const typeDefinitions = await generator.generateTypes({
90
- appKey: manifestKey,
90
+ app,
91
91
  authenticationId,
92
92
  sdk,
93
93
  });