zapier-platform-cli 17.9.0 → 18.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.
@@ -2555,5 +2555,5 @@
2555
2555
  ]
2556
2556
  }
2557
2557
  },
2558
- "version": "17.9.0"
2558
+ "version": "18.0.0"
2559
2559
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zapier-platform-cli",
3
- "version": "17.9.0",
3
+ "version": "18.0.0",
4
4
  "description": "The CLI for managing integrations in Zapier Developer Platform.",
5
5
  "repository": "zapier/zapier-platform",
6
6
  "homepage": "https://platform.zapier.com/",
@@ -40,58 +40,59 @@
40
40
  "validate": "yarn test && yarn smoke-test && yarn lint"
41
41
  },
42
42
  "dependencies": {
43
- "@oclif/core": "4.3.0",
44
- "@oclif/plugin-autocomplete": "3.2.28",
45
- "@oclif/plugin-help": "6.2.28",
46
- "@oclif/plugin-not-found": "3.2.51",
47
- "@oclif/plugin-version": "2.2.28",
43
+ "@oclif/core": "4.5.2",
44
+ "@oclif/plugin-autocomplete": "3.2.34",
45
+ "@oclif/plugin-help": "6.2.32",
46
+ "@oclif/plugin-not-found": "3.2.62",
47
+ "@oclif/plugin-version": "2.2.32",
48
48
  "adm-zip": "0.5.16",
49
49
  "archiver": "7.0.1",
50
- "chrono-node": "2.8.0",
50
+ "chrono-node": "2.8.3",
51
51
  "cli-table3": "0.6.5",
52
52
  "colors": "1.4.0",
53
- "debug": "4.4.0",
53
+ "debug": "4.4.1",
54
54
  "decompress": "4.2.1",
55
- "dotenv": "16.5.0",
56
- "esbuild": "0.25.4",
57
- "fs-extra": "11.2.0",
55
+ "dotenv": "17.2.1",
56
+ "esbuild": "0.25.8",
57
+ "fs-extra": "11.3.1",
58
58
  "gulp-filter": "7.0.0",
59
59
  "gulp-prettier": "5.0.0",
60
- "ignore": "5.2.4",
60
+ "ignore": "7.0.5",
61
61
  "inquirer": "8.2.5",
62
62
  "jscodeshift": "^17.3.0",
63
63
  "lodash": "4.17.21",
64
- "luxon": "3.6.1",
65
- "marked": "14.1.4",
66
- "marked-terminal": "7.2.1",
67
- "open": "10.1.2",
64
+ "luxon": "3.7.1",
65
+ "marked": "15.0.12",
66
+ "marked-terminal": "7.3.0",
67
+ "open": "10.2.0",
68
68
  "ora": "5.4.0",
69
69
  "parse-gitignore": "0.5.1",
70
- "prettier": "3.5.3",
70
+ "prettier": "3.6.2",
71
71
  "read": "4.1.0",
72
- "semver": "7.7.1",
72
+ "semver": "7.7.2",
73
73
  "string-length": "4.0.2",
74
74
  "through2": "4.0.2",
75
75
  "tmp": "0.2.4",
76
76
  "traverse": "0.6.11",
77
- "update-notifier": "5.1.0",
78
- "yeoman-environment": "3.19.3",
79
- "yeoman-generator": "5.9.0"
77
+ "update-notifier": "7.3.1",
78
+ "yeoman-environment": "4.4.3",
79
+ "yeoman-generator": "7.5.1"
80
80
  },
81
81
  "devDependencies": {
82
- "@oclif/test": "^4.1.12",
82
+ "@oclif/test": "^4.1.13",
83
83
  "@types/jscodeshift": "^0.12.0",
84
84
  "@types/mocha": "^10.0.9",
85
85
  "chai": "^4.3.7",
86
86
  "mock-fs": "^5.5.0",
87
- "nock": "^14.0.4",
88
- "oclif": "^4.17.46",
87
+ "nock": "^14.0.7",
88
+ "oclif": "^4.22.5",
89
89
  "rimraf": "^5.0.10",
90
90
  "typescript": "^5.8.3",
91
91
  "yamljs": "0.3.0"
92
92
  },
93
93
  "bin": {
94
- "zapier": "./src/bin/run"
94
+ "zapier": "./src/bin/run-deprecated",
95
+ "zapier-platform": "./src/bin/run"
95
96
  },
96
97
  "oclif": {
97
98
  "commands": "src/oclif/commands",
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env node
2
+
3
+ const path = require('node:path');
4
+
5
+ (async () => {
6
+ const oclif = await import('@oclif/core');
7
+ await oclif.execute({ development: false, dir: __dirname });
8
+
9
+ console.warn(
10
+ '[DEPRECATION WARNING] ' +
11
+ 'The executable name "zapier" is deprecated and will be removed in a future version. ' +
12
+ 'Please use "zapier-platform" instead.',
13
+ );
14
+ })();
package/src/constants.js CHANGED
@@ -20,7 +20,7 @@ const BUILD_PATH = `${BUILD_DIR}/build.zip`;
20
20
  const SOURCE_PATH = `${BUILD_DIR}/source.zip`;
21
21
  const NODE_VERSION = versionStore[versionStore.length - 1].nodeVersion;
22
22
  const LAMBDA_VERSION = `v${NODE_VERSION}`;
23
- const NODE_VERSION_CLI_REQUIRES = '>=18'; // should be the oldest non-ETL version
23
+ const NODE_VERSION_CLI_REQUIRES = '>=22'; // should be the oldest non-ETL version
24
24
  const AUTH_KEY = 'deployKey';
25
25
  const ANALYTICS_KEY = 'analyticsMode';
26
26
  const ANALYTICS_MODES = {
@@ -2,12 +2,12 @@ const path = require('path');
2
2
 
3
3
  const { merge } = require('lodash');
4
4
  const filter = require('gulp-filter');
5
- const Generator = require('yeoman-generator');
5
+ const { createGeneratorClass } = require('../utils/esm-wrapper');
6
6
  const prettier = require('gulp-prettier');
7
7
 
8
8
  const { PACKAGE_VERSION, PLATFORM_PACKAGE } = require('../constants');
9
9
  const authFilesCodegen = require('../utils/auth-files-codegen');
10
- const { PullGenerator } = require('./pull');
10
+ const PullGeneratorPromise = require('./pull');
11
11
 
12
12
  const writeGenericReadme = (gen) => {
13
13
  gen.fs.copyTpl(
@@ -133,6 +133,7 @@ const writeGenericAuth = (gen) => {
133
133
  const content = authFilesCodegen[authType](gen.options.language);
134
134
  const destPath = (key) =>
135
135
  gen.options.language === 'typescript' ? `src/${key}.ts` : `${key}.js`;
136
+
136
137
  Object.entries(content).forEach(([key, value]) => {
137
138
  gen.fs.write(gen.destinationPath(destPath(key)), value);
138
139
  });
@@ -238,104 +239,107 @@ const TS_SUPPORTED_TEMPLATES = [
238
239
 
239
240
  const TEMPLATE_CHOICES = Object.keys(TEMPLATE_ROUTES);
240
241
 
241
- class ProjectGenerator extends Generator {
242
- initializing() {
243
- this.sourceRoot(path.resolve(__dirname, 'templates'));
244
- this.destinationRoot(path.resolve(this.options.path));
245
-
246
- const jsFilter = filter(['*.js', '*.json', '*.ts'], { restore: true });
247
- this.queueTransformStream([
248
- jsFilter,
249
- prettier({ singleQuote: true }),
250
- jsFilter.restore,
251
- ]);
252
- }
253
-
254
- async prompting() {
255
- if (!this.options.template) {
256
- // Filter template choices based on language and module type
257
- let templateChoices = TEMPLATE_CHOICES;
258
- let defaultTemplate = 'minimal';
259
-
260
- // TypeScript filtering takes precedence over ESM filtering
261
- if (this.options.language === 'typescript') {
262
- templateChoices = TS_SUPPORTED_TEMPLATES;
263
- defaultTemplate = 'basic-auth';
264
- } else if (this.options.module === 'esm') {
265
- templateChoices = ESM_SUPPORTED_TEMPLATES;
266
- defaultTemplate = 'minimal'; // minimal is the only ESM template
267
- }
268
-
269
- this.answers = await this.prompt([
270
- {
271
- type: 'list',
272
- name: 'template',
273
- choices: templateChoices,
274
- message: 'Choose a project template to start with:',
275
- default: defaultTemplate,
276
- },
242
+ const ProjectGeneratorPromise = createGeneratorClass((Generator) => {
243
+ return class ProjectGenerator extends Generator {
244
+ initializing() {
245
+ this.sourceRoot(path.resolve(__dirname, 'templates'));
246
+ this.destinationRoot(path.resolve(this.options.path));
247
+
248
+ const jsFilter = filter(['*.js', '*.json', '*.ts'], { restore: true });
249
+ this.queueTransformStream([
250
+ { disabled: true },
251
+ jsFilter,
252
+ prettier({ singleQuote: true }),
253
+ jsFilter.restore,
277
254
  ]);
278
- this.options.template = this.answers.template;
279
255
  }
280
256
 
281
- if (
282
- ESM_SUPPORTED_TEMPLATES.includes(this.options.template) &&
283
- !this.options.module
284
- ) {
285
- this.answers = await this.prompt([
286
- {
287
- type: 'list',
288
- name: 'module',
289
- choices: ['esm', 'commonjs'],
290
- message: 'Choose module type:',
291
- default: 'esm',
292
- },
293
- ]);
294
- this.options.module = this.answers.module;
295
- }
257
+ async prompting() {
258
+ if (!this.options.template) {
259
+ // Filter template choices based on language and module type
260
+ let templateChoices = TEMPLATE_CHOICES;
261
+ let defaultTemplate = 'minimal';
262
+
263
+ // TypeScript filtering takes precedence over ESM filtering
264
+ if (this.options.language === 'typescript') {
265
+ templateChoices = TS_SUPPORTED_TEMPLATES;
266
+ defaultTemplate = 'basic-auth';
267
+ } else if (this.options.module === 'esm') {
268
+ templateChoices = ESM_SUPPORTED_TEMPLATES;
269
+ defaultTemplate = 'minimal'; // minimal is the only ESM template
270
+ }
296
271
 
297
- if (this.options.language) {
298
- if (this.options.language === 'typescript') {
299
- // check if the template supports typescript
300
- if (!TS_SUPPORTED_TEMPLATES.includes(this.options.template)) {
301
- throw new Error(
302
- 'Typescript is not supported for this template, please use a different template or set the language to javascript. Supported templates: ' +
303
- TS_SUPPORTED_TEMPLATES.join(', '),
304
- );
272
+ this.answers = await this.prompt([
273
+ {
274
+ type: 'list',
275
+ name: 'template',
276
+ choices: templateChoices,
277
+ message: 'Choose a project template to start with:',
278
+ default: defaultTemplate,
279
+ },
280
+ ]);
281
+ this.options.template = this.answers.template;
282
+ }
283
+
284
+ if (
285
+ ESM_SUPPORTED_TEMPLATES.includes(this.options.template) &&
286
+ !this.options.module
287
+ ) {
288
+ this.answers = await this.prompt([
289
+ {
290
+ type: 'list',
291
+ name: 'module',
292
+ choices: ['esm', 'commonjs'],
293
+ message: 'Choose module type:',
294
+ default: 'esm',
295
+ },
296
+ ]);
297
+ this.options.module = this.answers.module;
298
+ }
299
+
300
+ if (this.options.language) {
301
+ if (this.options.language === 'typescript') {
302
+ // check if the template supports typescript
303
+ if (!TS_SUPPORTED_TEMPLATES.includes(this.options.template)) {
304
+ throw new Error(
305
+ 'Typescript is not supported for this template, please use a different template or set the language to javascript. Supported templates: ' +
306
+ TS_SUPPORTED_TEMPLATES.join(', '),
307
+ );
308
+ }
309
+ // if they try to combine typescript with commonjs, throw an error
310
+ if (this.options.module === 'commonjs') {
311
+ throw new Error('Typescript is not supported for commonjs');
312
+ } // esm is supported for typescript templates
305
313
  }
306
- // if they try to combine typescript with commonjs, throw an error
307
- if (this.options.module === 'commonjs') {
308
- throw new Error('Typescript is not supported for commonjs');
309
- } // esm is supported for typescript templates
314
+ } else {
315
+ // default to javascript for the language if it's not set
316
+ this.options.language = 'javascript';
310
317
  }
311
- } else {
312
- // default to javascript for the language if it's not set
313
- this.options.language = 'javascript';
314
- }
315
318
 
316
- if (
317
- !ESM_SUPPORTED_TEMPLATES.includes(this.options.template) &&
318
- this.options.module === 'esm' &&
319
- this.options.language === 'javascript'
320
- ) {
321
- throw new Error(
322
- 'ESM is not supported for this template, please use a different template, set the module to commonjs, or try setting the language to Typescript',
323
- );
319
+ if (
320
+ !ESM_SUPPORTED_TEMPLATES.includes(this.options.template) &&
321
+ this.options.module === 'esm' &&
322
+ this.options.language === 'javascript'
323
+ ) {
324
+ throw new Error(
325
+ 'ESM is not supported for this template, please use a different template, set the module to commonjs, or try setting the language to Typescript',
326
+ );
327
+ }
324
328
  }
325
- }
326
329
 
327
- writing() {
328
- this.options.packageName = path.basename(this.options.path);
330
+ writing() {
331
+ this.options.packageName = path.basename(this.options.path);
329
332
 
330
- const writeFunc = TEMPLATE_ROUTES[this.options.template];
331
- writeFunc(this);
332
- }
333
- }
333
+ const writeFunc = TEMPLATE_ROUTES[this.options.template];
334
+ writeFunc(this);
335
+ }
336
+ };
337
+ });
334
338
 
335
339
  module.exports = {
336
340
  TEMPLATE_CHOICES,
337
341
  ESM_SUPPORTED_TEMPLATES,
338
342
  TS_SUPPORTED_TEMPLATES,
339
- PullGenerator,
340
- ProjectGenerator,
343
+ PullGenerator: PullGeneratorPromise,
344
+ ProjectGenerator: ProjectGeneratorPromise,
341
345
  };
@@ -2,7 +2,7 @@ const colors = require('colors/safe');
2
2
  const debug = require('debug')('zapier:pull');
3
3
  const inquirer = require('inquirer');
4
4
  const path = require('path');
5
- const Generator = require('yeoman-generator');
5
+ const { createGeneratorClass } = require('../utils/esm-wrapper');
6
6
 
7
7
  const maybeOverwriteFiles = async (gen) => {
8
8
  const dstDir = gen.options.dstDir;
@@ -12,17 +12,19 @@ const maybeOverwriteFiles = async (gen) => {
12
12
  }
13
13
  };
14
14
 
15
- module.exports = class PullGenerator extends Generator {
16
- initializing() {
17
- debug('SRC', this.options.sourceFiles);
18
- }
15
+ // Export a factory function that creates the PullGenerator class
16
+ module.exports = createGeneratorClass((Generator) => {
17
+ return class PullGenerator extends Generator {
18
+ initializing() {
19
+ debug('SRC', this.options.sourceFiles);
20
+ }
19
21
 
20
- prompting() {
21
- const prompts = [
22
- {
23
- type: 'confirm',
24
- name: 'confirm',
25
- message: `Warning: You are about to overwrite existing files.
22
+ prompting() {
23
+ const prompts = [
24
+ {
25
+ type: 'confirm',
26
+ name: 'confirm',
27
+ message: `Warning: You are about to overwrite existing files.
26
28
 
27
29
  Before proceeding, please make sure you have saved your work. Consider creating a backup or saving your current state in a git branch.
28
30
 
@@ -30,23 +32,24 @@ If presented with a series of options ('ynarxdeiH'), you may
30
32
  press Enter to view more details about each option. For example, 'x' will abort the process.
31
33
 
32
34
  Do you want to continue?`,
33
- default: false,
34
- },
35
- ];
36
-
37
- return inquirer.prompt(prompts).then((answers) => {
38
- if (!answers.confirm) {
39
- this.log(colors.green('zapier pull cancelled'));
40
- process.exit(1);
41
- }
42
- });
43
- }
44
-
45
- writing() {
46
- maybeOverwriteFiles(this);
47
- }
48
-
49
- end() {
50
- this.log(colors.green('zapier pull completed successfully'));
51
- }
52
- };
35
+ default: false,
36
+ },
37
+ ];
38
+
39
+ return inquirer.prompt(prompts).then((answers) => {
40
+ if (!answers.confirm) {
41
+ this.log(colors.green('zapier pull cancelled'));
42
+ process.exit(1);
43
+ }
44
+ });
45
+ }
46
+
47
+ writing() {
48
+ maybeOverwriteFiles(this);
49
+ }
50
+
51
+ end() {
52
+ this.log(colors.green('zapier pull completed successfully'));
53
+ }
54
+ };
55
+ });
@@ -8,6 +8,7 @@ const { recordAnalytics } = require('../utils/analytics');
8
8
  const { getWritableApp } = require('../utils/api');
9
9
 
10
10
  const inquirer = require('inquirer');
11
+ const { throwForInvalidVersion } = require('../utils/version');
11
12
 
12
13
  const DATA_FORMATS = ['json', 'raw'];
13
14
 
@@ -90,16 +91,7 @@ class ZapierBaseCommand extends Command {
90
91
 
91
92
  // validate that user input looks like a semver version
92
93
  throwForInvalidVersion(version) {
93
- if (
94
- !version.match(
95
- // this is mirrored in schemas/VersionSchema.js and developer_cli/constants.py
96
- /^(?:0|[1-9]\d{0,2})\.(?:0|[1-9]\d{0,2})\.(?:0|[1-9]\d{0,2})(?:-(?=.{1,12}$)[A-Za-z0-9]+(?:-[A-Za-z0-9]+)*)?$/g,
97
- )
98
- ) {
99
- throw new Error(
100
- `${version} is an invalid version str. Try something like \`1.2.3\` or \`0.0.0-TICKET\``,
101
- );
102
- }
94
+ return throwForInvalidVersion(version);
103
95
  }
104
96
 
105
97
  async getWritableApp() {
@@ -1,18 +1,22 @@
1
1
  const { join } = require('path');
2
2
 
3
3
  const { Args, Flags } = require('@oclif/core');
4
- const yeoman = require('yeoman-environment');
4
+ const { createEnv } = require('../../utils/esm-wrapper');
5
5
 
6
6
  const BaseCommand = require('../ZapierBaseCommand');
7
7
  const { buildFlags } = require('../buildFlags');
8
- const { TEMPLATE_CHOICES, ProjectGenerator } = require('../../generators');
8
+ const {
9
+ TEMPLATE_CHOICES,
10
+ ProjectGenerator: ProjectGeneratorPromise,
11
+ } = require('../../generators');
9
12
 
10
13
  class InitCommand extends BaseCommand {
11
14
  async perform() {
12
15
  const { path } = this.args;
13
16
  const { template, module, language } = this.flags;
14
17
 
15
- const env = yeoman.createEnv();
18
+ const env = await createEnv(); // await needed because createEnv() uses dynamic import() for ESM-only yeoman-environment
19
+ const ProjectGenerator = await ProjectGeneratorPromise; // await needed because generator classes are now created via ESM dynamic import
16
20
  env.registerStub(ProjectGenerator, 'zapier:integration');
17
21
 
18
22
  await env.run('zapier:integration', { path, template, module, language });
@@ -1086,7 +1086,7 @@ class InvokeCommand extends BaseCommand {
1086
1086
  async perform() {
1087
1087
  let authId = this.flags['authentication-id'];
1088
1088
 
1089
- const dotenvResult = dotenv.config({ override: true });
1089
+ const dotenvResult = dotenv.config({ override: true, quiet: true });
1090
1090
  if (!authId && _.isEmpty(dotenvResult.parsed)) {
1091
1091
  console.warn(
1092
1092
  'The .env file does not exist or is empty. ' +
@@ -1,14 +1,14 @@
1
1
  const AdmZip = require('adm-zip');
2
2
  const { ensureFileSync } = require('fs-extra');
3
3
  const path = require('path');
4
- const yeoman = require('yeoman-environment');
4
+ const { createEnv } = require('../../utils/esm-wrapper');
5
5
 
6
6
  const ZapierBaseCommand = require('../ZapierBaseCommand');
7
7
  const { downloadSourceZip } = require('../../utils/api');
8
8
  const { ensureDir, makeTempDir, removeDirSync } = require('../../utils/files');
9
9
  const { walkDirWithPresetBlocklist } = require('../../utils/build');
10
10
  const { buildFlags } = require('../buildFlags');
11
- const PullGenerator = require('../../generators/pull');
11
+ const PullGeneratorPromise = require('../../generators/pull');
12
12
 
13
13
  const listFiles = (dir) => {
14
14
  const relPaths = [];
@@ -38,7 +38,8 @@ class PullCommand extends ZapierBaseCommand {
38
38
  const currentDir = process.cwd();
39
39
  const sourceFiles = listFiles(srcDst);
40
40
 
41
- const env = yeoman.createEnv();
41
+ const env = await createEnv(); // await needed because createEnv() uses dynamic import() for ESM-only yeoman-environment
42
+ const PullGenerator = await PullGeneratorPromise; // await needed because generator classes are now created via ESM dynamic import
42
43
  const namespace = 'zapier:pull';
43
44
  env.registerStub(PullGenerator, namespace);
44
45
  await env.run(namespace, {
@@ -6,21 +6,18 @@ const colors = require('colors/safe');
6
6
  const BuildCommand = require('./build');
7
7
 
8
8
  const { buildAndOrUpload } = require('../../utils/build');
9
- const { localAppCommand } = require('../../utils/local');
10
-
11
9
  class PushCommand extends ZapierBaseCommand {
12
10
  async perform() {
13
11
  const skipNpmInstall = this.flags['skip-npm-install'];
14
- const definition = await localAppCommand({ command: 'definition' });
15
12
 
16
13
  const snapshotLabel = this.flags.snapshot;
17
14
  if (snapshotLabel && snapshotLabel.length > 12) {
18
15
  throw new Error('Snapshot label cannot exceed 12 characters');
19
16
  }
20
- const version = snapshotLabel
17
+
18
+ const snapshotVersion = snapshotLabel
21
19
  ? `0.0.0-${snapshotLabel}`
22
- : definition.version;
23
- this.throwForInvalidVersion(version);
20
+ : undefined;
24
21
 
25
22
  await buildAndOrUpload(
26
23
  { build: true, upload: true },
@@ -30,7 +27,7 @@ class PushCommand extends ZapierBaseCommand {
30
27
  skipValidation: this.flags['skip-validation'],
31
28
  overwritePartnerChanges: this.flags['overwrite-partner-changes'],
32
29
  },
33
- version,
30
+ snapshotVersion,
34
31
  );
35
32
  this.log(
36
33
  `\nPush complete! Built ${BUILD_PATH} and ${SOURCE_PATH} and uploaded them to Zapier.`,
@@ -1,10 +1,12 @@
1
- const updateNotifier = require('update-notifier');
1
+ const { createUpdateNotifier } = require('../../utils/esm-wrapper');
2
2
  const pkg = require('../../../package.json');
3
3
  const { UPDATE_NOTIFICATION_INTERVAL } = require('../../constants');
4
4
 
5
5
  // can't be fat arrow because it inherits `this` from commands
6
- module.exports = function (options) {
7
- const notifier = updateNotifier({
6
+ // Made async because createUpdateNotifier() uses dynamic import() to load ESM-only update-notifier package
7
+ module.exports = async function (options) {
8
+ const notifier = await createUpdateNotifier({
9
+ // await needed for ESM dynamic import
8
10
  pkg,
9
11
  updateCheckInterval: UPDATE_NOTIFICATION_INTERVAL,
10
12
  });
package/src/utils/api.js CHANGED
@@ -428,7 +428,7 @@ const downloadSourceZip = async (dst) => {
428
428
  const upload = async (
429
429
  app,
430
430
  { skipValidation = false, overwritePartnerChanges = false } = {},
431
- versionOverride,
431
+ snapshotVersion,
432
432
  ) => {
433
433
  const zipPath = constants.BUILD_PATH;
434
434
  const sourceZipPath = constants.SOURCE_PATH;
@@ -461,7 +461,7 @@ const upload = async (
461
461
  headers['X-Overwrite-Partner-Changes'] = 'true';
462
462
  }
463
463
 
464
- const version = versionOverride ?? definition.version;
464
+ const version = snapshotVersion ?? definition.version;
465
465
  startSpinner(`Uploading version ${version}`);
466
466
  try {
467
467
  await callAPI(
@@ -11,7 +11,7 @@ const archiver = require('archiver');
11
11
  const colors = require('colors/safe');
12
12
  const esbuild = require('esbuild');
13
13
  const fse = require('fs-extra');
14
- const updateNotifier = require('update-notifier');
14
+ const { createUpdateNotifier } = require('./esm-wrapper');
15
15
  const decompress = require('decompress');
16
16
 
17
17
  const {
@@ -45,6 +45,7 @@ const checkMissingAppInfo = require('./check-missing-app-info');
45
45
  const { findCorePackageDir, isWindows, runCommand } = require('./misc');
46
46
  const { isBlocklisted, respectGitIgnore } = require('./ignore');
47
47
  const { localAppCommand } = require('./local');
48
+ const { throwForInvalidVersion } = require('./version');
48
49
 
49
50
  const debug = require('debug')('zapier:build');
50
51
 
@@ -467,7 +468,8 @@ const makeSourceZip = async (workingDir, zipPath) => {
467
468
  await zip.finish();
468
469
  };
469
470
 
470
- const maybeNotifyAboutOutdated = () => {
471
+ const maybeNotifyAboutOutdated = async () => {
472
+ // Made async because createUpdateNotifier() uses dynamic import() to load ESM-only update-notifier package
471
473
  // find a package.json for the app and notify on the core dep
472
474
  // `build` won't run if package.json isn't there, so if we get to here we're good
473
475
  const requiredVersion = _.get(
@@ -476,7 +478,7 @@ const maybeNotifyAboutOutdated = () => {
476
478
  );
477
479
 
478
480
  if (requiredVersion) {
479
- const notifier = updateNotifier({
481
+ const notifier = await createUpdateNotifier({
480
482
  pkg: { name: PLATFORM_PACKAGE, version: requiredVersion },
481
483
  updateCheckInterval: UPDATE_NOTIFICATION_INTERVAL,
482
484
  });
@@ -588,18 +590,21 @@ const testBuildZip = async (zipPath) => {
588
590
  }
589
591
  };
590
592
 
591
- const _buildFunc = async ({
592
- skipNpmInstall = false,
593
- disableDependencyDetection = false,
594
- skipValidation = false,
595
- printProgress = true,
596
- checkOutdated = true,
597
- } = {}) => {
593
+ const _buildFunc = async (
594
+ {
595
+ skipNpmInstall = false,
596
+ disableDependencyDetection = false,
597
+ skipValidation = false,
598
+ printProgress = true,
599
+ checkOutdated = true,
600
+ } = {},
601
+ snapshotVersion,
602
+ ) => {
598
603
  const maybeStartSpinner = printProgress ? startSpinner : () => {};
599
604
  const maybeEndSpinner = printProgress ? endSpinner : () => {};
600
605
 
601
606
  if (checkOutdated) {
602
- maybeNotifyAboutOutdated();
607
+ await maybeNotifyAboutOutdated(); // await needed because function is now async due to ESM import
603
608
  }
604
609
  const appDir = process.cwd();
605
610
 
@@ -659,6 +664,9 @@ const _buildFunc = async ({
659
664
  false,
660
665
  );
661
666
 
667
+ const version = snapshotVersion ?? rawDefinition.version;
668
+ throwForInvalidVersion(version);
669
+
662
670
  try {
663
671
  fs.writeFileSync(
664
672
  path.join(workingDir, 'definition.json'),
@@ -761,7 +769,7 @@ const _buildFunc = async ({
761
769
  const buildAndOrUpload = async (
762
770
  { build = false, upload = false } = {},
763
771
  buildOpts,
764
- versionOverride,
772
+ snapshotVersion,
765
773
  ) => {
766
774
  if (!(build || upload)) {
767
775
  throw new Error('must either build or upload');
@@ -775,10 +783,10 @@ const buildAndOrUpload = async (
775
783
  }
776
784
 
777
785
  if (build) {
778
- await _buildFunc(buildOpts);
786
+ await _buildFunc(buildOpts, snapshotVersion);
779
787
  }
780
788
  if (upload) {
781
- await _uploadFunc(app, buildOpts, versionOverride);
789
+ await _uploadFunc(app, buildOpts, snapshotVersion);
782
790
  }
783
791
  };
784
792
 
@@ -0,0 +1,86 @@
1
+ /**
2
+ * CommonJS wrapper for ESM-only modules
3
+ * This allows us to use yeoman-environment v4+, yeoman-generator v7+, and update-notifier v7+ from CommonJS code without downgrading
4
+ */
5
+
6
+ let yeomanEnvironment = null;
7
+ let yeomanGenerator = null;
8
+ let updateNotifier = null;
9
+
10
+ /**
11
+ * Lazy-load yeoman-environment using dynamic import
12
+ * @returns {Promise<Object>} The yeoman-environment module
13
+ */
14
+ async function getYeomanEnvironment() {
15
+ if (!yeomanEnvironment) {
16
+ yeomanEnvironment = await import('yeoman-environment');
17
+ }
18
+ return yeomanEnvironment;
19
+ }
20
+
21
+ /**
22
+ * Lazy-load yeoman-generator using dynamic import
23
+ * @returns {Promise<Object>} The yeoman-generator module
24
+ */
25
+ async function getYeomanGenerator() {
26
+ if (!yeomanGenerator) {
27
+ yeomanGenerator = await import('yeoman-generator');
28
+ }
29
+ return yeomanGenerator;
30
+ }
31
+
32
+ /**
33
+ * Lazy-load update-notifier using dynamic import
34
+ * @returns {Promise<Object>} The update-notifier module
35
+ */
36
+ async function getUpdateNotifier() {
37
+ if (!updateNotifier) {
38
+ updateNotifier = await import('update-notifier');
39
+ }
40
+ return updateNotifier;
41
+ }
42
+
43
+ /**
44
+ * Create a yeoman environment (async version of yeoman.createEnv())
45
+ * @param {Object} options - Environment options
46
+ * @returns {Promise<Object>} Environment instance
47
+ */
48
+ async function createEnv(options) {
49
+ const yeoman = await getYeomanEnvironment();
50
+ return yeoman.createEnv(options);
51
+ }
52
+
53
+ /**
54
+ * Get the Generator class (async version of require('yeoman-generator'))
55
+ * @returns {Promise<Function>} The Generator class
56
+ */
57
+ async function getGenerator() {
58
+ const yeomanGen = await getYeomanGenerator();
59
+ return yeomanGen.default;
60
+ }
61
+
62
+ /**
63
+ * Create a generator class factory that extends the yeoman Generator
64
+ * @param {Function} generatorFactory - A function that takes Generator class and returns a class extending it
65
+ * @returns {Promise<Function>} The generated class
66
+ */
67
+ async function createGeneratorClass(generatorFactory) {
68
+ const Generator = await getGenerator();
69
+ return generatorFactory(Generator);
70
+ }
71
+
72
+ /**
73
+ * Create an update notifier (async version of require('update-notifier'))
74
+ * @param {Object} options - Update notifier options (pkg, updateCheckInterval, etc.)
75
+ * @returns {Promise<Object>} Update notifier instance
76
+ */
77
+ async function createUpdateNotifier(options) {
78
+ const updateNotifierModule = await getUpdateNotifier();
79
+ return updateNotifierModule.default(options);
80
+ }
81
+
82
+ module.exports = {
83
+ createEnv,
84
+ createGeneratorClass,
85
+ createUpdateNotifier,
86
+ };
@@ -282,13 +282,21 @@ const getLocalAppHandler = async ({
282
282
  appRaw = loadAppRawUsingRequire(appDir);
283
283
  } catch (err) {
284
284
  if (err.code === 'MODULE_NOT_FOUND' || err.code === 'ERR_REQUIRE_ESM') {
285
- appRaw = await loadAppRawUsingImport(
286
- appDir,
287
- corePackageDir,
288
- shouldDeleteWrapper,
289
- );
285
+ try {
286
+ appRaw = await loadAppRawUsingImport(
287
+ appDir,
288
+ corePackageDir,
289
+ shouldDeleteWrapper,
290
+ );
291
+ } catch (err) {
292
+ err.message =
293
+ 'Your ESM integration requires a compiled `dist/` directory. Run `zapier build` to compile your code first.\n\n' +
294
+ err.message;
295
+ throw err;
296
+ }
290
297
  } else {
291
298
  // err.name === 'SyntaxError' or others
299
+
292
300
  throw err;
293
301
  }
294
302
  }
@@ -0,0 +1,16 @@
1
+ const throwForInvalidVersion = (version) => {
2
+ if (
3
+ !version.match(
4
+ // this is mirrored in schemas/VersionSchema.js and developer_cli/constants.py
5
+ /^(?:0|[1-9]\d{0,2})\.(?:0|[1-9]\d{0,2})\.(?:0|[1-9]\d{0,2})(?:-(?=.{1,12}$)[A-Za-z0-9]+(?:-[A-Za-z0-9]+)*)?$/g,
6
+ )
7
+ ) {
8
+ throw new Error(
9
+ `${version} is an invalid version str. Try something like \`1.2.3\` or \`0.0.0-TICKET\``,
10
+ );
11
+ }
12
+ };
13
+
14
+ module.exports = {
15
+ throwForInvalidVersion,
16
+ };
@@ -19,4 +19,5 @@ module.exports = [
19
19
  { nodeVersion: '18', npmVersion: '>=5.6.0' }, // 15.x
20
20
  { nodeVersion: '18', npmVersion: '>=10.7.0' }, // 16.x
21
21
  { nodeVersion: '18', npmVersion: '>=10.7.0' }, // 17.x
22
+ { nodeVersion: '22', npmVersion: '>=10.7.0' }, // 18.x
22
23
  ];
package/src/bin/run.cmd DELETED
@@ -1,3 +0,0 @@
1
- @echo off
2
-
3
- node "%~dp0\run" %*