zapier-platform-cli 16.5.0 → 17.0.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.
@@ -1,7 +1,20 @@
1
- import type { PerformFunction, Search } from 'zapier-platform-core';
1
+ import {
2
+ defineInputFields,
3
+ defineSearch,
4
+ type SearchPerform,
5
+ type InferInputData,
6
+ } from 'zapier-platform-core';
7
+
8
+ const inputFields = defineInputFields([
9
+ {
10
+ key: 'name',
11
+ required: true,
12
+ helpText: 'Find the <%= NOUN %> with this name.',
13
+ },
14
+ ]);
2
15
 
3
16
  // find a particular <%= LOWER_NOUN %> by name
4
- const perform: PerformFunction = async (z, bundle) => {
17
+ const perform = (async (z, bundle) => {
5
18
  const response = await z.request({
6
19
  url: 'https://jsonplaceholder.typicode.com/posts',
7
20
  params: {
@@ -10,9 +23,9 @@ const perform: PerformFunction = async (z, bundle) => {
10
23
  });
11
24
  // this should return an array of objects (but only the first will be used)
12
25
  return response.data;
13
- };
26
+ }) satisfies SearchPerform<InferInputData<typeof inputFields>>;
14
27
 
15
- export default {
28
+ export default defineSearch({
16
29
  // see here for a full list of available properties:
17
30
  // https://github.com/zapier/zapier-platform/blob/main/packages/schema/docs/build/schema.md#searchschema
18
31
  key: '<%= KEY %>',
@@ -30,13 +43,7 @@ export default {
30
43
  '// `inputFields` defines the fields a user could provide',
31
44
  '// Zapier will pass them in as `bundle.inputData` later. Searches need at least one `inputField`.'
32
45
  ].join('\n ') : '' %>
33
- inputFields: [
34
- {
35
- key: 'name',
36
- required: true,
37
- helpText: 'Find the <%= NOUN %> with this name.',
38
- },
39
- ],
46
+ inputFields,
40
47
 
41
48
  <%= INCLUDE_INTRO_COMMENTS ? [
42
49
  '// In cases where Zapier needs to show an example record to the user, but we are unable to get a live example',
@@ -60,4 +67,4 @@ export default {
60
67
  // {key: 'name', label: 'Person Name'}
61
68
  ],
62
69
  },
63
- } satisfies Search;
70
+ });
@@ -1,7 +1,10 @@
1
- import type { PerformFunction, Trigger } from 'zapier-platform-core';
1
+ import {
2
+ defineTrigger,
3
+ type PollingTriggerPerform,
4
+ } from 'zapier-platform-core';
2
5
 
3
6
  // triggers on a new <%= LOWER_NOUN %> with a certain tag
4
- const perform: PerformFunction = async (z, bundle) => {
7
+ const perform = (async (z, bundle) => {
5
8
  const response = await z.request({
6
9
  url: 'https://jsonplaceholder.typicode.com/posts',
7
10
  params: {
@@ -10,9 +13,9 @@ const perform: PerformFunction = async (z, bundle) => {
10
13
  });
11
14
  // this should return an array of objects
12
15
  return response.data;
13
- };
16
+ }) satisfies PollingTriggerPerform;
14
17
 
15
- export default {
18
+ export default defineTrigger({
16
19
  // see here for a full list of available properties:
17
20
  // https://github.com/zapier/zapier-platform/blob/main/packages/schema/docs/build/schema.md#triggerschema
18
21
  key: '<%= KEY %>' as const,
@@ -55,4 +58,4 @@ export default {
55
58
  // {key: 'name', label: 'Person Name'}
56
59
  ],
57
60
  },
58
- } satisfies Trigger;
61
+ });
@@ -32,6 +32,18 @@ const writeGitignore = (gen) => {
32
32
  };
33
33
 
34
34
  const writeGenericPackageJson = (gen, packageJsonExtension) => {
35
+ const moduleExtension =
36
+ gen.options.module === 'esm'
37
+ ? {
38
+ exports: './index.js',
39
+ type: 'module',
40
+ }
41
+ : {
42
+ main: 'index.js',
43
+ };
44
+
45
+ const fullExtension = merge(moduleExtension, packageJsonExtension);
46
+
35
47
  gen.fs.writeJSON(
36
48
  gen.destinationPath('package.json'),
37
49
  merge(
@@ -39,7 +51,6 @@ const writeGenericPackageJson = (gen, packageJsonExtension) => {
39
51
  name: gen.options.packageName,
40
52
  version: '1.0.0',
41
53
  description: '',
42
- main: 'index.js',
43
54
  scripts: {
44
55
  test: 'jest --testTimeout 10000',
45
56
  },
@@ -51,12 +62,24 @@ const writeGenericPackageJson = (gen, packageJsonExtension) => {
51
62
  },
52
63
  private: true,
53
64
  },
54
- packageJsonExtension,
65
+ fullExtension,
55
66
  ),
56
67
  );
57
68
  };
58
69
 
59
70
  const writeTypeScriptPackageJson = (gen, packageJsonExtension) => {
71
+ const moduleExtension =
72
+ gen.options.module === 'esm'
73
+ ? {
74
+ exports: './dist/index.js',
75
+ type: 'module',
76
+ }
77
+ : {
78
+ main: 'index.js',
79
+ };
80
+
81
+ const fullExtension = merge(moduleExtension, packageJsonExtension);
82
+
60
83
  gen.fs.writeJSON(
61
84
  gen.destinationPath('package.json'),
62
85
  merge(
@@ -64,7 +87,6 @@ const writeTypeScriptPackageJson = (gen, packageJsonExtension) => {
64
87
  name: gen.options.packageName,
65
88
  version: '1.0.0',
66
89
  description: '',
67
- main: 'src/index.js',
68
90
  scripts: {
69
91
  test: 'vitest',
70
92
  },
@@ -76,19 +98,40 @@ const writeTypeScriptPackageJson = (gen, packageJsonExtension) => {
76
98
  },
77
99
  private: true,
78
100
  },
79
- packageJsonExtension,
101
+ fullExtension,
80
102
  ),
81
103
  );
82
104
  };
83
105
 
84
106
  const writeGenericIndex = (gen, hasAuth) => {
107
+ const templatePath =
108
+ gen.options.module === 'esm'
109
+ ? 'index-esm.template.js'
110
+ : 'index.template.js';
85
111
  gen.fs.copyTpl(
86
- gen.templatePath('index.template.js'),
112
+ gen.templatePath(templatePath),
87
113
  gen.destinationPath('index.js'),
88
114
  { corePackageName: PLATFORM_PACKAGE, hasAuth },
89
115
  );
90
116
  };
91
117
 
118
+ const writeTypeScriptIndex = (gen) => {
119
+ const templatePath =
120
+ gen.options.module === 'esm'
121
+ ? 'index-esm.template.ts'
122
+ : 'index.template.ts';
123
+ gen.fs.copyTpl(
124
+ gen.templatePath(templatePath),
125
+ gen.destinationPath('src/index.ts'),
126
+ );
127
+
128
+ // create root directory index.js if it's commonjs
129
+ if (gen.options.module === 'commonjs') {
130
+ const content = `module.exports = require('./dist').default;`;
131
+ gen.fs.write(gen.destinationPath('index.js'), content);
132
+ }
133
+ };
134
+
92
135
  const authTypes = {
93
136
  'basic-auth': 'basic',
94
137
  'custom-auth': 'custom',
@@ -170,7 +213,7 @@ const writeForStandaloneTypeScriptTemplate = (gen) => {
170
213
  const packageJsonExtension = {
171
214
  typescript: {
172
215
  scripts: {
173
- test: 'vitest',
216
+ test: 'vitest --run',
174
217
  clean: 'rimraf ./dist ./build',
175
218
  build: 'npm run clean && tsc',
176
219
  '_zapier-build': 'npm run build',
@@ -189,6 +232,7 @@ const writeForStandaloneTypeScriptTemplate = (gen) => {
189
232
  gen.templatePath(gen.options.template, '**', '*.{js,json,ts}'),
190
233
  gen.destinationPath(),
191
234
  );
235
+ writeTypeScriptIndex(gen);
192
236
  };
193
237
 
194
238
  const TEMPLATE_ROUTES = {
@@ -207,6 +251,8 @@ const TEMPLATE_ROUTES = {
207
251
  typescript: writeForStandaloneTypeScriptTemplate,
208
252
  };
209
253
 
254
+ const ESM_SUPPORTED_TEMPLATES = ['minimal', 'typescript'];
255
+
210
256
  const TEMPLATE_CHOICES = Object.keys(TEMPLATE_ROUTES);
211
257
 
212
258
  class ProjectGenerator extends Generator {
@@ -235,6 +281,31 @@ class ProjectGenerator extends Generator {
235
281
  ]);
236
282
  this.options.template = this.answers.template;
237
283
  }
284
+
285
+ if (
286
+ ESM_SUPPORTED_TEMPLATES.includes(this.options.template) &&
287
+ !this.options.module
288
+ ) {
289
+ this.answers = await this.prompt([
290
+ {
291
+ type: 'list',
292
+ name: 'module',
293
+ choices: ['commonjs', 'esm'],
294
+ message: 'Choose module type:',
295
+ default: 'commonjs',
296
+ },
297
+ ]);
298
+ this.options.module = this.answers.module;
299
+ }
300
+
301
+ if (
302
+ !ESM_SUPPORTED_TEMPLATES.includes(this.options.template) &&
303
+ this.options.module === 'esm'
304
+ ) {
305
+ throw new Error(
306
+ 'ESM is not supported for this template, please use a different template or set the module to commonjs',
307
+ );
308
+ }
238
309
  }
239
310
 
240
311
  writing() {
@@ -0,0 +1,36 @@
1
+ <% if (hasAuth) { %>
2
+ import {
3
+ config as authentication,
4
+ befores = [],
5
+ afters = [],
6
+ } from './authentication';
7
+ <% } %>
8
+
9
+ import packageJson from './package.json' with { type: 'json' };
10
+ import zapier from '<%= corePackageName %>';
11
+
12
+ export default {
13
+ // This is just shorthand to reference the installed dependencies you have.
14
+ // Zapier will need to know these before we can upload.
15
+ version: packageJson.version,
16
+ platformVersion: zapier.version,
17
+
18
+ <% if (hasAuth) { %>
19
+ authentication,
20
+
21
+ beforeRequest: [...befores],
22
+
23
+ afterResponse: [...afters],
24
+ <% } %>
25
+
26
+ // If you want your trigger to show up, you better include it here!
27
+ triggers: {},
28
+
29
+ // If you want your searches to show up, you better include it here!
30
+ searches: {},
31
+
32
+ // If you want your creates to show up, you better include it here!
33
+ creates: {},
34
+
35
+ resources: {},
36
+ };
@@ -0,0 +1,24 @@
1
+ import zapier, { defineApp } from 'zapier-platform-core';
2
+
3
+ import packageJson from '../package.json' with { type: 'json' };
4
+
5
+ import MovieCreate from './creates/movie.js';
6
+ import MovieTrigger from './triggers/movie.js';
7
+ import authentication from './authentication.js';
8
+ import { addBearerHeader } from './middleware.js';
9
+
10
+ export default defineApp({
11
+ version: packageJson.version,
12
+ platformVersion: zapier.version,
13
+
14
+ authentication,
15
+ beforeRequest: [addBearerHeader],
16
+
17
+ triggers: {
18
+ [MovieTrigger.key]: MovieTrigger,
19
+ },
20
+
21
+ creates: {
22
+ [MovieCreate.key]: MovieCreate,
23
+ },
24
+ });
@@ -1,5 +1,4 @@
1
- import type { App } from 'zapier-platform-core';
2
- import { version as platformVersion } from 'zapier-platform-core';
1
+ import { version as platformVersion, defineApp } from 'zapier-platform-core';
3
2
 
4
3
  import packageJson from '../package.json';
5
4
 
@@ -8,7 +7,7 @@ import MovieTrigger from './triggers/movie';
8
7
  import authentication from './authentication';
9
8
  import { addBearerHeader } from './middleware';
10
9
 
11
- export default {
10
+ export default defineApp({
12
11
  version: packageJson.version,
13
12
  platformVersion,
14
13
 
@@ -22,4 +21,4 @@ export default {
22
21
  creates: {
23
22
  [MovieCreate.key]: MovieCreate,
24
23
  },
25
- } satisfies App;
24
+ });
@@ -1,6 +1,6 @@
1
1
  import type { Authentication } from 'zapier-platform-core';
2
2
 
3
- import { API_URL, SCOPES } from './constants';
3
+ import { API_URL, SCOPES } from './constants.js';
4
4
 
5
5
  export default {
6
6
  type: 'oauth2',
@@ -1,7 +1,17 @@
1
- import type { Create, PerformFunction } from 'zapier-platform-core';
2
- import { API_URL } from '../constants';
1
+ import {
2
+ defineInputFields,
3
+ defineCreate,
4
+ type CreatePerform,
5
+ type InferInputData,
6
+ } from 'zapier-platform-core';
7
+ import { API_URL } from '../constants.js';
3
8
 
4
- const perform: PerformFunction = async (z, bundle) => {
9
+ const inputFields = defineInputFields([
10
+ { key: 'title', required: true },
11
+ { key: 'year', type: 'integer' },
12
+ ]);
13
+
14
+ const perform = (async (z, bundle) => {
5
15
  const response = await z.request({
6
16
  method: 'POST',
7
17
  url: `${API_URL}/movies`,
@@ -11,9 +21,9 @@ const perform: PerformFunction = async (z, bundle) => {
11
21
  },
12
22
  });
13
23
  return response.data;
14
- };
24
+ }) satisfies CreatePerform<InferInputData<typeof inputFields>>;
15
25
 
16
- export default {
26
+ export default defineCreate({
17
27
  key: 'movie',
18
28
  noun: 'Movie',
19
29
 
@@ -24,13 +34,10 @@ export default {
24
34
 
25
35
  operation: {
26
36
  perform,
27
- inputFields: [
28
- { key: 'title', required: true },
29
- { key: 'year', type: 'integer' },
30
- ],
37
+ inputFields,
31
38
  sample: {
32
39
  id: '1',
33
40
  title: 'example',
34
41
  },
35
42
  },
36
- } satisfies Create;
43
+ });
@@ -10,7 +10,7 @@ describe('movie', () => {
10
10
  test('create a movie', async () => {
11
11
  const bundle = {
12
12
  inputData: { title: 'hello', year: 2020 },
13
- authData: { access_token: 'a_token' },
13
+ authData: { access_token: 'a_token' },
14
14
  };
15
15
  const result = await appTester(App.creates.movie.operation.perform, bundle);
16
16
  expect(result).toMatchObject({
@@ -1,12 +1,15 @@
1
- import type { PerformFunction, Trigger } from 'zapier-platform-core';
2
- import { API_URL } from '../constants';
1
+ import {
2
+ defineTrigger,
3
+ type PollingTriggerPerform,
4
+ } from 'zapier-platform-core';
5
+ import { API_URL } from '../constants.js';
3
6
 
4
- const perform: PerformFunction = async (z, bundle) => {
7
+ const perform = (async (z, bundle) => {
5
8
  const response = await z.request(`${API_URL}/movies`);
6
9
  return response.data;
7
- };
10
+ }) satisfies PollingTriggerPerform;
8
11
 
9
- export default {
12
+ export default defineTrigger({
10
13
  key: 'movie',
11
14
  noun: 'Movie',
12
15
 
@@ -23,4 +26,4 @@ export default {
23
26
  title: 'example',
24
27
  },
25
28
  },
26
- } satisfies Trigger;
29
+ });
@@ -51,7 +51,7 @@ This command does the following:
51
51
  * Copies all code into the temporary folder
52
52
  * Adds an entry point: \`zapierwrapper.js\`
53
53
  * Generates and validates app definition.
54
- * Detects dependencies via browserify (optional, on by default)
54
+ * Detects dependencies via esbuild (optional, on by default)
55
55
  * Zips up all needed \`.js\` files. If you want to include more files, add a "includeInBuild" property (array with strings of regexp paths) to your \`${CURRENT_APP_FILE}\`.
56
56
  * Moves the zip to \`${BUILD_PATH}\` and \`${SOURCE_PATH}\` and deletes the temp folder
57
57
 
@@ -10,12 +10,12 @@ const { TEMPLATE_CHOICES, ProjectGenerator } = require('../../generators');
10
10
  class InitCommand extends BaseCommand {
11
11
  async perform() {
12
12
  const { path } = this.args;
13
- const { template } = this.flags;
13
+ const { template, module } = this.flags;
14
14
 
15
15
  const env = yeoman.createEnv();
16
16
  env.registerStub(ProjectGenerator, 'zapier:integration');
17
17
 
18
- await env.run('zapier:integration', { path, template });
18
+ await env.run('zapier:integration', { path, template, module });
19
19
 
20
20
  this.log();
21
21
  this.log(`A new integration has been created in directory "${path}".`);
@@ -30,6 +30,12 @@ InitCommand.flags = buildFlags({
30
30
  description: 'The template to start your integration with.',
31
31
  options: TEMPLATE_CHOICES,
32
32
  }),
33
+ module: Flags.string({
34
+ char: 'm',
35
+ description:
36
+ 'Choose module type: CommonJS or ES Modules. Only enabled for Typescript and Minimal templates.',
37
+ options: ['commonjs', 'esm'],
38
+ }),
33
39
  },
34
40
  });
35
41
  InitCommand.args = {
@@ -42,6 +48,7 @@ InitCommand.args = {
42
48
  InitCommand.examples = [
43
49
  'zapier init myapp',
44
50
  'zapier init ./path/myapp --template oauth2',
51
+ 'zapier init ./path/myapp --template minimal --module esm',
45
52
  ];
46
53
  InitCommand.description = `Initialize a new Zapier integration with a project template.
47
54
 
@@ -13,7 +13,7 @@ const { DateTime, IANAZone } = require('luxon');
13
13
 
14
14
  const BaseCommand = require('../ZapierBaseCommand');
15
15
  const { buildFlags } = require('../buildFlags');
16
- const { localAppCommand, getLocalAppHandler } = require('../../utils/local');
16
+ const { localAppCommand } = require('../../utils/local');
17
17
  const { startSpinner, endSpinner } = require('../../utils/display');
18
18
  const {
19
19
  getLinkedAppConfig,
@@ -510,10 +510,6 @@ class InvokeCommand extends BaseCommand {
510
510
  }
511
511
 
512
512
  if (!_.isEmpty(env)) {
513
- // process.env changed, so we need to reload the modules that have loaded
514
- // the old values of process.env
515
- getLocalAppHandler({ reload: true });
516
-
517
513
  // Save envs so the user won't have to re-enter them if the command fails
518
514
  await appendEnv(env);
519
515
  console.warn('CLIENT_ID and CLIENT_SECRET saved to .env file.');
@@ -1,29 +1,10 @@
1
1
  const colors = require('colors/safe');
2
-
2
+ const { Flags } = require('@oclif/core');
3
3
  const BaseCommand = require('../ZapierBaseCommand');
4
4
  const { buildFlags } = require('../buildFlags');
5
5
 
6
6
  const { listVersions } = require('../../utils/api');
7
7
 
8
- const deploymentToLifecycleState = (deployment) => {
9
- switch (deployment) {
10
- case 'non-production':
11
- return 'private';
12
- case 'production':
13
- return 'promoted';
14
- case 'demoted':
15
- return 'available';
16
- case 'legacy':
17
- return 'legacy';
18
- case 'deprecating':
19
- return 'deprecating';
20
- case 'deprecated':
21
- return 'deprecated';
22
- default:
23
- return deployment;
24
- }
25
- };
26
-
27
8
  class VersionCommand extends BaseCommand {
28
9
  async perform() {
29
10
  this.startSpinner('Loading versions');
@@ -31,11 +12,15 @@ class VersionCommand extends BaseCommand {
31
12
  this.stopSpinner();
32
13
  const rows = versions.map((v) => ({
33
14
  ...v,
34
- state: deploymentToLifecycleState(v.lifecycle.status),
15
+ state: v.lifecycle.status,
35
16
  }));
36
17
 
18
+ const visibleVersions = this.flags.all
19
+ ? rows
20
+ : rows.filter((v) => v.state !== 'deprecated');
21
+
37
22
  this.logTable({
38
- rows,
23
+ rows: visibleVersions,
39
24
  headers: [
40
25
  ['Version', 'version'],
41
26
  ['Platform', 'platform_version'],
@@ -81,7 +66,15 @@ class VersionCommand extends BaseCommand {
81
66
  }
82
67
 
83
68
  VersionCommand.skipValidInstallCheck = true;
84
- VersionCommand.flags = buildFlags({ opts: { format: true } });
69
+ VersionCommand.flags = buildFlags({
70
+ commandFlags: {
71
+ all: Flags.boolean({
72
+ char: 'a',
73
+ description: `List all versions, including deprecated versions.`,
74
+ }),
75
+ },
76
+ opts: { format: true },
77
+ });
85
78
  VersionCommand.description = `List the versions of your integration available for use in Zapier automations.`;
86
79
 
87
80
  module.exports = VersionCommand;