zapier-platform-cli 16.5.1 → 17.0.1
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.
- package/oclif.manifest.json +16 -3
- package/package.json +23 -23
- package/scaffold/create.template.ts +21 -14
- package/scaffold/search.template.ts +19 -12
- package/scaffold/trigger.template.ts +8 -5
- package/src/generators/index.js +77 -6
- package/src/generators/templates/index-esm.template.js +36 -0
- package/src/generators/templates/index-esm.template.ts +24 -0
- package/src/generators/templates/{typescript/src/index.ts → index.template.ts} +3 -4
- package/src/generators/templates/typescript/src/authentication.ts +1 -1
- package/src/generators/templates/typescript/src/creates/movie.ts +17 -10
- package/src/generators/templates/typescript/src/test/creates.test.ts +1 -1
- package/src/generators/templates/typescript/src/triggers/movie.ts +9 -6
- package/src/oclif/commands/build.js +1 -1
- package/src/oclif/commands/init.js +9 -2
- package/src/oclif/commands/invoke.js +1 -5
- package/src/utils/build.js +42 -104
- package/src/utils/local.js +108 -43
- package/src/utils/zapierwrapper.js +55 -0
- package/src/version-store.js +1 -0
- package/src/generators/templates/typescript/index.js +0 -1
package/oclif.manifest.json
CHANGED
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"build": {
|
|
56
56
|
"aliases": [],
|
|
57
57
|
"args": {},
|
|
58
|
-
"description": "Build a pushable zip from the current directory.\n\nThis command does the following:\n\n* Creates a temporary folder\n* Copies all code into the temporary folder\n* Adds an entry point: `zapierwrapper.js`\n* Generates and validates app definition.\n* Detects dependencies via
|
|
58
|
+
"description": "Build a pushable zip from the current directory.\n\nThis command does the following:\n\n* Creates a temporary folder\n* Copies all code into the temporary folder\n* Adds an entry point: `zapierwrapper.js`\n* Generates and validates app definition.\n* Detects dependencies via esbuild (optional, on by default)\n* 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 `.zapierapprc`.\n* Moves the zip to `build/build.zip` and `build/source.zip` and deletes the temp folder\n\nThis command is typically followed by `zapier upload`.",
|
|
59
59
|
"flags": {
|
|
60
60
|
"disable-dependency-detection": {
|
|
61
61
|
"description": "Disable \"smart\" file inclusion. By default, Zapier only includes files that are required by `index.js`. If you (or your dependencies) require files dynamically (such as with `require(someVar)`), then you may see \"Cannot find module\" errors. Disabling this may make your `build.zip` too large. If that's the case, try using the `includeInBuild` option in your `.zapierapprc`. See the docs about `includeInBuild` for more info.",
|
|
@@ -337,7 +337,8 @@
|
|
|
337
337
|
"description": "Initialize a new Zapier integration with a project template.\n\nAfter running this, you'll have a new integration in the specified directory. If you re-run this command on an existing directory, it will prompt before overwriting any existing files.\n\nThis doesn't register or deploy the integration with Zapier - try the `zapier register` and `zapier push` commands for that!",
|
|
338
338
|
"examples": [
|
|
339
339
|
"zapier init myapp",
|
|
340
|
-
"zapier init ./path/myapp --template oauth2"
|
|
340
|
+
"zapier init ./path/myapp --template oauth2",
|
|
341
|
+
"zapier init ./path/myapp --template minimal --module esm"
|
|
341
342
|
],
|
|
342
343
|
"flags": {
|
|
343
344
|
"template": {
|
|
@@ -363,6 +364,18 @@
|
|
|
363
364
|
],
|
|
364
365
|
"type": "option"
|
|
365
366
|
},
|
|
367
|
+
"module": {
|
|
368
|
+
"char": "m",
|
|
369
|
+
"description": "Choose module type: CommonJS or ES Modules. Only enabled for Typescript and Minimal templates.",
|
|
370
|
+
"name": "module",
|
|
371
|
+
"hasDynamicHelp": false,
|
|
372
|
+
"multiple": false,
|
|
373
|
+
"options": [
|
|
374
|
+
"commonjs",
|
|
375
|
+
"esm"
|
|
376
|
+
],
|
|
377
|
+
"type": "option"
|
|
378
|
+
},
|
|
366
379
|
"debug": {
|
|
367
380
|
"char": "d",
|
|
368
381
|
"description": "Show extra debugging output.",
|
|
@@ -2417,5 +2430,5 @@
|
|
|
2417
2430
|
]
|
|
2418
2431
|
}
|
|
2419
2432
|
},
|
|
2420
|
-
"version": "
|
|
2433
|
+
"version": "17.0.1"
|
|
2421
2434
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zapier-platform-cli",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "17.0.1",
|
|
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,56 +40,56 @@
|
|
|
40
40
|
"validate": "yarn test && yarn smoke-test && yarn lint"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@oclif/core": "4.0
|
|
44
|
-
"@oclif/plugin-autocomplete": "3.2.
|
|
45
|
-
"@oclif/plugin-help": "6.2.
|
|
46
|
-
"@oclif/plugin-not-found": "3.2.
|
|
47
|
-
"@oclif/plugin-version": "2.2.
|
|
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",
|
|
48
48
|
"adm-zip": "0.5.16",
|
|
49
49
|
"archiver": "7.0.1",
|
|
50
|
-
"
|
|
51
|
-
"chrono-node": "2.7.7",
|
|
50
|
+
"chrono-node": "2.8.0",
|
|
52
51
|
"cli-table3": "0.6.5",
|
|
53
52
|
"colors": "1.4.0",
|
|
54
|
-
"debug": "4.
|
|
55
|
-
"dotenv": "16.
|
|
53
|
+
"debug": "4.4.0",
|
|
54
|
+
"dotenv": "16.5.0",
|
|
55
|
+
"esbuild": "0.25.4",
|
|
56
56
|
"fs-extra": "11.2.0",
|
|
57
57
|
"gulp-filter": "7.0.0",
|
|
58
|
-
"gulp-prettier": "
|
|
58
|
+
"gulp-prettier": "5.0.0",
|
|
59
59
|
"ignore": "5.2.4",
|
|
60
60
|
"inquirer": "8.2.5",
|
|
61
|
-
"jscodeshift": "^17.
|
|
61
|
+
"jscodeshift": "^17.3.0",
|
|
62
62
|
"klaw": "4.1.0",
|
|
63
63
|
"lodash": "4.17.21",
|
|
64
|
-
"luxon": "3.
|
|
64
|
+
"luxon": "3.6.1",
|
|
65
65
|
"marked": "14.1.4",
|
|
66
66
|
"marked-terminal": "7.2.1",
|
|
67
67
|
"minimatch": "9.0.3",
|
|
68
68
|
"node-fetch": "2.7.0",
|
|
69
|
-
"open": "10.1.
|
|
69
|
+
"open": "10.1.2",
|
|
70
70
|
"ora": "5.4.0",
|
|
71
71
|
"parse-gitignore": "0.5.1",
|
|
72
|
-
"prettier": "3.
|
|
73
|
-
"read": "4.
|
|
74
|
-
"semver": "7.
|
|
72
|
+
"prettier": "3.5.3",
|
|
73
|
+
"read": "4.1.0",
|
|
74
|
+
"semver": "7.7.1",
|
|
75
75
|
"string-length": "4.0.2",
|
|
76
76
|
"through2": "4.0.2",
|
|
77
77
|
"tmp": "0.2.3",
|
|
78
|
-
"traverse": "0.6.
|
|
78
|
+
"traverse": "0.6.11",
|
|
79
79
|
"update-notifier": "5.1.0",
|
|
80
80
|
"yeoman-environment": "3.19.3",
|
|
81
81
|
"yeoman-generator": "5.9.0"
|
|
82
82
|
},
|
|
83
83
|
"devDependencies": {
|
|
84
|
-
"@oclif/test": "^4.
|
|
84
|
+
"@oclif/test": "^4.1.12",
|
|
85
85
|
"@types/jscodeshift": "^0.12.0",
|
|
86
86
|
"@types/mocha": "^10.0.9",
|
|
87
87
|
"chai": "^4.3.7",
|
|
88
88
|
"decompress": "4.2.1",
|
|
89
|
-
"mock-fs": "^5.
|
|
90
|
-
"nock": "^
|
|
91
|
-
"oclif": "^4.
|
|
92
|
-
"typescript": "^5.
|
|
89
|
+
"mock-fs": "^5.5.0",
|
|
90
|
+
"nock": "^14.0.4",
|
|
91
|
+
"oclif": "^4.17.46",
|
|
92
|
+
"typescript": "^5.8.3",
|
|
93
93
|
"yamljs": "0.3.0"
|
|
94
94
|
},
|
|
95
95
|
"bin": {
|
|
@@ -1,21 +1,31 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {
|
|
2
|
+
defineInputFields,
|
|
3
|
+
defineCreate,
|
|
4
|
+
type CreatePerform,
|
|
5
|
+
type InferInputData,
|
|
6
|
+
} from 'zapier-platform-core';
|
|
7
|
+
|
|
8
|
+
const inputFields = defineInputFields([
|
|
9
|
+
{ key: 'name', required: true },
|
|
10
|
+
{ key: 'fave_meal', label: 'Favorite Meal', required: false },
|
|
11
|
+
]);
|
|
2
12
|
|
|
3
13
|
// create a particular <%= LOWER_NOUN %> by name
|
|
4
|
-
const perform
|
|
14
|
+
const perform = (async (z, bundle) => {
|
|
5
15
|
const response = await z.request({
|
|
6
16
|
method: 'POST',
|
|
7
17
|
url: 'https://jsonplaceholder.typicode.com/posts',
|
|
8
18
|
// if `body` is an object, it'll automatically get run through JSON.stringify
|
|
9
19
|
// if you don't want to send JSON, pass a string in your chosen format here instead
|
|
10
20
|
body: {
|
|
11
|
-
name: bundle.inputData.name
|
|
12
|
-
}
|
|
21
|
+
name: bundle.inputData.name,
|
|
22
|
+
},
|
|
13
23
|
});
|
|
14
24
|
// this should return a single object
|
|
15
25
|
return response.data;
|
|
16
|
-
}
|
|
26
|
+
}) satisfies CreatePerform<InferInputData<typeof inputFields>>;
|
|
17
27
|
|
|
18
|
-
export default {
|
|
28
|
+
export default defineCreate({
|
|
19
29
|
// see here for a full list of available properties:
|
|
20
30
|
// https://github.com/zapier/zapier-platform/blob/main/packages/schema/docs/build/schema.md#createschema
|
|
21
31
|
key: '<%= KEY %>',
|
|
@@ -34,10 +44,7 @@ export default {
|
|
|
34
44
|
'// Zapier will pass them in as `bundle.inputData` later. They\'re optional.',
|
|
35
45
|
'// End-users will map data into these fields. In general, they should have any fields that the API can accept. Be sure to accurately mark which fields are required!'
|
|
36
46
|
].join('\n ') : '' %>
|
|
37
|
-
inputFields
|
|
38
|
-
{key: 'name', required: true},
|
|
39
|
-
{key: 'fave_meal', label: 'Favorite Meal', required: false}
|
|
40
|
-
],
|
|
47
|
+
inputFields,
|
|
41
48
|
|
|
42
49
|
<%= INCLUDE_INTRO_COMMENTS ? [
|
|
43
50
|
'// In cases where Zapier needs to show an example record to the user, but we are unable to get a live example',
|
|
@@ -46,7 +53,7 @@ export default {
|
|
|
46
53
|
].join('\n ') : '' %>
|
|
47
54
|
sample: {
|
|
48
55
|
id: 1,
|
|
49
|
-
name: 'Test'
|
|
56
|
+
name: 'Test',
|
|
50
57
|
},
|
|
51
58
|
|
|
52
59
|
<%= INCLUDE_INTRO_COMMENTS ? [
|
|
@@ -59,6 +66,6 @@ export default {
|
|
|
59
66
|
// these are placeholders to match the example `perform` above
|
|
60
67
|
// {key: 'id', label: 'Person ID'},
|
|
61
68
|
// {key: 'name', label: 'Person Name'}
|
|
62
|
-
]
|
|
63
|
-
}
|
|
64
|
-
}
|
|
69
|
+
],
|
|
70
|
+
},
|
|
71
|
+
});
|
|
@@ -1,7 +1,20 @@
|
|
|
1
|
-
import
|
|
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
|
|
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
|
-
}
|
|
70
|
+
});
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import
|
|
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
|
|
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
|
-
}
|
|
61
|
+
});
|
package/src/generators/index.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
|
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
|
-
}
|
|
24
|
+
});
|
|
@@ -1,7 +1,17 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
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
|
|
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
|
-
}
|
|
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
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
defineTrigger,
|
|
3
|
+
type PollingTriggerPerform,
|
|
4
|
+
} from 'zapier-platform-core';
|
|
5
|
+
import { API_URL } from '../constants.js';
|
|
3
6
|
|
|
4
|
-
const perform
|
|
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
|
-
}
|
|
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
|
|
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
|
|
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.');
|
package/src/utils/build.js
CHANGED
|
@@ -2,10 +2,9 @@ const crypto = require('crypto');
|
|
|
2
2
|
const os = require('os');
|
|
3
3
|
const path = require('path');
|
|
4
4
|
|
|
5
|
-
const browserify = require('browserify');
|
|
6
|
-
const through = require('through2');
|
|
7
5
|
const _ = require('lodash');
|
|
8
6
|
const archiver = require('archiver');
|
|
7
|
+
const esbuild = require('esbuild');
|
|
9
8
|
const fs = require('fs');
|
|
10
9
|
const fse = require('fs-extra');
|
|
11
10
|
const klaw = require('klaw');
|
|
@@ -20,13 +19,7 @@ const {
|
|
|
20
19
|
|
|
21
20
|
const constants = require('../constants');
|
|
22
21
|
|
|
23
|
-
const {
|
|
24
|
-
writeFile,
|
|
25
|
-
readFile,
|
|
26
|
-
copyDir,
|
|
27
|
-
ensureDir,
|
|
28
|
-
removeDir,
|
|
29
|
-
} = require('./files');
|
|
22
|
+
const { writeFile, copyDir, ensureDir, removeDir } = require('./files');
|
|
30
23
|
|
|
31
24
|
const {
|
|
32
25
|
prettyJSONstringify,
|
|
@@ -42,67 +35,39 @@ const {
|
|
|
42
35
|
validateApp,
|
|
43
36
|
} = require('./api');
|
|
44
37
|
|
|
38
|
+
const { copyZapierWrapper } = require('./zapierwrapper');
|
|
39
|
+
|
|
45
40
|
const checkMissingAppInfo = require('./check-missing-app-info');
|
|
46
41
|
|
|
47
42
|
const { runCommand, isWindows, findCorePackageDir } = require('./misc');
|
|
48
43
|
const { respectGitIgnore } = require('./ignore');
|
|
44
|
+
const { localAppCommand } = require('./local');
|
|
49
45
|
|
|
50
46
|
const debug = require('debug')('zapier:build');
|
|
51
47
|
|
|
52
48
|
const stripPath = (cwd, filePath) => filePath.split(cwd).pop();
|
|
53
49
|
|
|
54
50
|
// given entry points in a directory, return a list of files that uses
|
|
55
|
-
|
|
56
|
-
// TODO: needs to include package.json files too i think
|
|
57
|
-
// https://github.com/serverless/serverless-optimizer-plugin?
|
|
58
|
-
const requiredFiles = (cwd, entryPoints) => {
|
|
51
|
+
const requiredFiles = async ({ cwd, entryPoints }) => {
|
|
59
52
|
if (!_.endsWith(cwd, path.sep)) {
|
|
60
53
|
cwd += path.sep;
|
|
61
54
|
}
|
|
62
55
|
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
browserField: false,
|
|
74
|
-
detectGlobals: true,
|
|
75
|
-
insertGlobals: false,
|
|
76
|
-
insertGlobalVars: {
|
|
77
|
-
process: undefined,
|
|
78
|
-
global: undefined,
|
|
79
|
-
'Buffer.isBuffer': undefined,
|
|
80
|
-
Buffer: undefined,
|
|
81
|
-
},
|
|
82
|
-
ignoreMissing: true,
|
|
83
|
-
debug: false,
|
|
84
|
-
standalone: undefined,
|
|
85
|
-
};
|
|
86
|
-
const b = browserify(argv);
|
|
87
|
-
|
|
88
|
-
return new Promise((resolve, reject) => {
|
|
89
|
-
b.on('error', reject);
|
|
90
|
-
|
|
91
|
-
const paths = [];
|
|
92
|
-
b.pipeline.get('deps').push(
|
|
93
|
-
through
|
|
94
|
-
.obj((row, enc, next) => {
|
|
95
|
-
const filePath = row.file || row.id;
|
|
96
|
-
paths.push(stripPath(cwd, filePath));
|
|
97
|
-
next();
|
|
98
|
-
})
|
|
99
|
-
.on('end', () => {
|
|
100
|
-
paths.sort();
|
|
101
|
-
resolve(paths);
|
|
102
|
-
}),
|
|
103
|
-
);
|
|
104
|
-
b.bundle();
|
|
56
|
+
const result = await esbuild.build({
|
|
57
|
+
entryPoints,
|
|
58
|
+
outdir: './build',
|
|
59
|
+
bundle: true,
|
|
60
|
+
platform: 'node',
|
|
61
|
+
metafile: true,
|
|
62
|
+
logLevel: 'warning',
|
|
63
|
+
external: ['../test/userapp'],
|
|
64
|
+
format: 'esm',
|
|
65
|
+
write: false, // no need to write outfile
|
|
105
66
|
});
|
|
67
|
+
|
|
68
|
+
return Object.keys(result.metafile.inputs).map((path) =>
|
|
69
|
+
stripPath(cwd, path),
|
|
70
|
+
);
|
|
106
71
|
};
|
|
107
72
|
|
|
108
73
|
const listFiles = (dir) => {
|
|
@@ -194,16 +159,21 @@ const writeZipFromPaths = (dir, zipPath, paths) => {
|
|
|
194
159
|
};
|
|
195
160
|
|
|
196
161
|
const makeZip = async (dir, zipPath, disableDependencyDetection) => {
|
|
197
|
-
const entryPoints = [
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
162
|
+
const entryPoints = [path.resolve(dir, 'zapierwrapper.js')];
|
|
163
|
+
|
|
164
|
+
const indexPath = path.resolve(dir, 'index.js');
|
|
165
|
+
if (fs.existsSync(indexPath)) {
|
|
166
|
+
// Necessary for CommonJS integrations. The zapierwrapper they use require()
|
|
167
|
+
// the index.js file using a variable. esbuild can't detect it, so we need
|
|
168
|
+
// to add it here specifically.
|
|
169
|
+
entryPoints.push(indexPath);
|
|
170
|
+
}
|
|
201
171
|
|
|
202
172
|
let paths;
|
|
203
173
|
|
|
204
174
|
const [dumbPaths, smartPaths, appConfig] = await Promise.all([
|
|
205
175
|
listFiles(dir),
|
|
206
|
-
requiredFiles(dir, entryPoints),
|
|
176
|
+
requiredFiles({ cwd: dir, entryPoints }),
|
|
207
177
|
getLinkedAppConfig(dir).catch(() => ({})),
|
|
208
178
|
]);
|
|
209
179
|
|
|
@@ -234,24 +204,6 @@ const makeSourceZip = async (dir, zipPath) => {
|
|
|
234
204
|
await writeZipFromPaths(dir, zipPath, finalPaths);
|
|
235
205
|
};
|
|
236
206
|
|
|
237
|
-
// Similar to utils.appCommand, but given a ready to go app
|
|
238
|
-
// with a different location and ready to go zapierwrapper.js.
|
|
239
|
-
const _appCommandZapierWrapper = (dir, event) => {
|
|
240
|
-
const app = require(`${dir}/zapierwrapper.js`);
|
|
241
|
-
event = Object.assign({}, event, {
|
|
242
|
-
calledFromCli: true,
|
|
243
|
-
});
|
|
244
|
-
return new Promise((resolve, reject) => {
|
|
245
|
-
app.handler(event, {}, (err, resp) => {
|
|
246
|
-
if (err) {
|
|
247
|
-
reject(err);
|
|
248
|
-
} else {
|
|
249
|
-
resolve(resp);
|
|
250
|
-
}
|
|
251
|
-
});
|
|
252
|
-
});
|
|
253
|
-
};
|
|
254
|
-
|
|
255
207
|
const maybeNotifyAboutOutdated = () => {
|
|
256
208
|
// find a package.json for the app and notify on the core dep
|
|
257
209
|
// `build` won't run if package.json isn't there, so if we get to here we're good
|
|
@@ -417,35 +369,21 @@ const _buildFunc = async ({
|
|
|
417
369
|
|
|
418
370
|
if (printProgress) {
|
|
419
371
|
endSpinner();
|
|
420
|
-
startSpinner('Applying entry point
|
|
372
|
+
startSpinner('Applying entry point files');
|
|
421
373
|
}
|
|
422
374
|
|
|
423
|
-
|
|
424
|
-
const zapierWrapperBuf = await readFile(
|
|
425
|
-
path.join(
|
|
426
|
-
tmpDir,
|
|
427
|
-
'node_modules',
|
|
428
|
-
constants.PLATFORM_PACKAGE,
|
|
429
|
-
'include',
|
|
430
|
-
'zapierwrapper.js',
|
|
431
|
-
),
|
|
432
|
-
);
|
|
433
|
-
await writeFile(
|
|
434
|
-
path.join(tmpDir, 'zapierwrapper.js'),
|
|
435
|
-
zapierWrapperBuf.toString(),
|
|
436
|
-
);
|
|
375
|
+
await copyZapierWrapper(corePath, tmpDir);
|
|
437
376
|
|
|
438
377
|
if (printProgress) {
|
|
439
378
|
endSpinner();
|
|
440
379
|
startSpinner('Building app definition.json');
|
|
441
380
|
}
|
|
442
381
|
|
|
443
|
-
const rawDefinition = (
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
)
|
|
448
|
-
|
|
382
|
+
const rawDefinition = await localAppCommand(
|
|
383
|
+
{ command: 'definition' },
|
|
384
|
+
tmpDir,
|
|
385
|
+
false,
|
|
386
|
+
);
|
|
449
387
|
const fileWriteError = await writeFile(
|
|
450
388
|
path.join(tmpDir, 'definition.json'),
|
|
451
389
|
prettyJSONstringify(rawDefinition),
|
|
@@ -472,11 +410,11 @@ const _buildFunc = async ({
|
|
|
472
410
|
if (printProgress) {
|
|
473
411
|
startSpinner('Validating project schema and style');
|
|
474
412
|
}
|
|
475
|
-
const
|
|
476
|
-
command: 'validate',
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
413
|
+
const validationErrors = await localAppCommand(
|
|
414
|
+
{ command: 'validate' },
|
|
415
|
+
tmpDir,
|
|
416
|
+
false,
|
|
417
|
+
);
|
|
480
418
|
if (validationErrors.length) {
|
|
481
419
|
debug('\nErrors:\n', validationErrors, '\n');
|
|
482
420
|
throw new Error(
|
package/src/utils/local.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
const
|
|
2
|
-
const path = require('path');
|
|
1
|
+
const path = require('node:path');
|
|
3
2
|
|
|
4
|
-
const { findCorePackageDir } = require('./misc');
|
|
5
3
|
const { BASE_ENDPOINT } = require('../constants');
|
|
4
|
+
const { findCorePackageDir, runCommand } = require('./misc');
|
|
5
|
+
const { copyZapierWrapper, deleteZapierWrapper } = require('./zapierwrapper');
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Wraps Node's http.request() / https.request() so that all requests go via a relay URL.
|
|
@@ -218,34 +218,75 @@ function wrapFetchWithRelay(fetchFunc, relayUrl, relayHeaders) {
|
|
|
218
218
|
};
|
|
219
219
|
}
|
|
220
220
|
|
|
221
|
-
const
|
|
222
|
-
|
|
223
|
-
|
|
221
|
+
const loadAppRawUsingImport = async (
|
|
222
|
+
appDir,
|
|
223
|
+
corePackageDir,
|
|
224
|
+
shouldDeleteWrapper,
|
|
225
|
+
) => {
|
|
226
|
+
const wrapperPath = await copyZapierWrapper(corePackageDir, appDir);
|
|
227
|
+
let appRaw;
|
|
228
|
+
try {
|
|
229
|
+
// zapierwrapper.mjs is only available since zapier-platform-core v17.
|
|
230
|
+
// And only zapierwrapper.mjs exposes appRaw just for this use case.
|
|
231
|
+
appRaw = (await import(wrapperPath)).appRaw;
|
|
232
|
+
} catch (err) {
|
|
233
|
+
if (err.name === 'SyntaxError') {
|
|
234
|
+
// Run a separate process to print the line number of the SyntaxError.
|
|
235
|
+
// This workaround is needed because `err` doesn't provide the location
|
|
236
|
+
// info about the SyntaxError. However, if the error is thrown to
|
|
237
|
+
// Node.js's built-in error handler, it will print the location info.
|
|
238
|
+
// See: https://github.com/nodejs/node/issues/49441
|
|
239
|
+
await runCommand(process.execPath, ['zapierwrapper.js'], {
|
|
240
|
+
cwd: appDir,
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
throw err;
|
|
244
|
+
} finally {
|
|
245
|
+
if (shouldDeleteWrapper) {
|
|
246
|
+
await deleteZapierWrapper(appDir);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
return appRaw;
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
const loadAppRawUsingRequire = (appDir) => {
|
|
254
|
+
let appRaw = require(appDir);
|
|
255
|
+
if (appRaw && appRaw.default) {
|
|
256
|
+
// Node.js 22+ supports using require() to import ESM.
|
|
257
|
+
// For Node.js < 20.17.0, require() will throw an error on ESM.
|
|
258
|
+
// https://nodejs.org/api/modules.html#loading-ecmascript-modules-using-require
|
|
259
|
+
appRaw = appRaw.default;
|
|
260
|
+
}
|
|
261
|
+
return appRaw;
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
const getLocalAppHandler = async ({
|
|
265
|
+
appDir = null,
|
|
224
266
|
appId = null,
|
|
225
267
|
deployKey = null,
|
|
226
268
|
relayAuthenticationId = null,
|
|
227
269
|
beforeRequest = null,
|
|
228
270
|
afterResponse = null,
|
|
271
|
+
shouldDeleteWrapper = true,
|
|
229
272
|
} = {}) => {
|
|
230
|
-
|
|
231
|
-
const rootPath = path.dirname(require.resolve(entryPath));
|
|
232
|
-
const corePackageDir = findCorePackageDir();
|
|
273
|
+
appDir = path.resolve(appDir || process.cwd());
|
|
233
274
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
if (cachePath.startsWith(rootPath)) {
|
|
237
|
-
delete require.cache[cachePath];
|
|
238
|
-
}
|
|
239
|
-
});
|
|
240
|
-
}
|
|
241
|
-
let appRaw, zapier;
|
|
275
|
+
const corePackageDir = findCorePackageDir();
|
|
276
|
+
let appRaw;
|
|
242
277
|
try {
|
|
243
|
-
appRaw =
|
|
244
|
-
zapier = require(corePackageDir);
|
|
278
|
+
appRaw = loadAppRawUsingRequire(appDir);
|
|
245
279
|
} catch (err) {
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
280
|
+
if (err.code === 'MODULE_NOT_FOUND' || err.code === 'ERR_REQUIRE_ESM') {
|
|
281
|
+
appRaw = await loadAppRawUsingImport(
|
|
282
|
+
appDir,
|
|
283
|
+
corePackageDir,
|
|
284
|
+
shouldDeleteWrapper,
|
|
285
|
+
);
|
|
286
|
+
} else {
|
|
287
|
+
// err.name === 'SyntaxError' or others
|
|
288
|
+
throw err;
|
|
289
|
+
}
|
|
249
290
|
}
|
|
250
291
|
|
|
251
292
|
if (beforeRequest) {
|
|
@@ -282,41 +323,65 @@ const getLocalAppHandler = ({
|
|
|
282
323
|
global.fetch = wrapFetchWithRelay(global.fetch, relayUrl, relayHeaders);
|
|
283
324
|
}
|
|
284
325
|
|
|
326
|
+
// Assumes the entry point of zapier-platform-core is index.js
|
|
327
|
+
const coreEntryPoint = path.join(corePackageDir, 'index.js');
|
|
328
|
+
const zapier = (await import(coreEntryPoint)).default;
|
|
329
|
+
|
|
285
330
|
const handler = zapier.createAppHandler(appRaw);
|
|
286
|
-
|
|
287
|
-
event
|
|
288
|
-
|
|
289
|
-
event
|
|
290
|
-
|
|
331
|
+
if (handler.length === 3) {
|
|
332
|
+
// < v17: function handler(event, ctx, callback)
|
|
333
|
+
return (event, ctx, callback) => {
|
|
334
|
+
event = {
|
|
335
|
+
...event,
|
|
291
336
|
calledFromCli: true,
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
337
|
+
};
|
|
338
|
+
return handler(event, ctx, callback);
|
|
339
|
+
};
|
|
340
|
+
} else {
|
|
341
|
+
// >= v17: async function handler(event, ctx = {})
|
|
342
|
+
return async (event, ctx = {}) => {
|
|
343
|
+
event = {
|
|
344
|
+
...event,
|
|
345
|
+
calledFromCli: true,
|
|
346
|
+
};
|
|
347
|
+
return await handler(event, ctx);
|
|
348
|
+
};
|
|
349
|
+
}
|
|
297
350
|
};
|
|
298
351
|
|
|
299
352
|
// Runs a local app command (./index.js) like {command: 'validate'};
|
|
300
|
-
const localAppCommand = (event) => {
|
|
301
|
-
const handler = getLocalAppHandler({
|
|
353
|
+
const localAppCommand = async (event, appDir, shouldDeleteWrapper = true) => {
|
|
354
|
+
const handler = await getLocalAppHandler({
|
|
302
355
|
appId: event.appId,
|
|
303
356
|
deployKey: event.deployKey,
|
|
304
357
|
relayAuthenticationId: event.relayAuthenticationId,
|
|
305
358
|
beforeRequest: event.beforeRequest,
|
|
306
359
|
afterResponse: event.afterResponse,
|
|
360
|
+
appDir,
|
|
361
|
+
shouldDeleteWrapper,
|
|
307
362
|
});
|
|
308
|
-
|
|
309
|
-
handler(event,
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
}
|
|
363
|
+
if (handler.length === 3) {
|
|
364
|
+
// < 17: function handler(event, ctx, callback)
|
|
365
|
+
return new Promise((resolve, reject) => {
|
|
366
|
+
event = {
|
|
367
|
+
...event,
|
|
368
|
+
calledFromCli: true,
|
|
369
|
+
};
|
|
370
|
+
handler(event, {}, (err, response) => {
|
|
371
|
+
if (err) {
|
|
372
|
+
reject(err);
|
|
373
|
+
} else {
|
|
374
|
+
resolve(response.results);
|
|
375
|
+
}
|
|
376
|
+
});
|
|
315
377
|
});
|
|
316
|
-
}
|
|
378
|
+
} else {
|
|
379
|
+
// >= 17: async function handler(event, ctx = {})
|
|
380
|
+
const response = await handler(event);
|
|
381
|
+
return response.results;
|
|
382
|
+
}
|
|
317
383
|
};
|
|
318
384
|
|
|
319
385
|
module.exports = {
|
|
320
|
-
getLocalAppHandler,
|
|
321
386
|
localAppCommand,
|
|
322
387
|
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// Utility functions that helps you copy and delete the Lambda function entry
|
|
2
|
+
// point zapierwrapper.mjs or zapierwrapper.js to the integration directory.
|
|
3
|
+
|
|
4
|
+
const { existsSync } = require('node:fs');
|
|
5
|
+
const { readFile, writeFile, rm } = require('node:fs/promises');
|
|
6
|
+
const { join } = require('node:path');
|
|
7
|
+
|
|
8
|
+
// We have two different versions of zapierwrapper: the .mjs one for ESM and the
|
|
9
|
+
// .js one for CommonJS. To copy the right one, we check the module type in the
|
|
10
|
+
// integration's package.json.
|
|
11
|
+
//
|
|
12
|
+
// For esbuild to perform static analysis, zapierwrapper.mjs can only
|
|
13
|
+
// import('packageName') where the packageName must be a static string literal.
|
|
14
|
+
// It can't import(packageName) where packageName is a variable. So in
|
|
15
|
+
// zapierwrapper.mjs, there's a placeholder {REPLACE_ME_PACKAGE_NAME} that
|
|
16
|
+
// we'll replace with the actual package name.
|
|
17
|
+
const copyZapierWrapper = async (corePackageDir, appDir) => {
|
|
18
|
+
const appPackageJson = require(join(appDir, 'package.json'));
|
|
19
|
+
let wrapperFilename;
|
|
20
|
+
if (appPackageJson.type === 'module') {
|
|
21
|
+
wrapperFilename = 'zapierwrapper.mjs';
|
|
22
|
+
} else {
|
|
23
|
+
wrapperFilename = 'zapierwrapper.js';
|
|
24
|
+
}
|
|
25
|
+
const wrapperPath = join(corePackageDir, 'include', wrapperFilename);
|
|
26
|
+
|
|
27
|
+
if (appPackageJson.type === 'module' && !existsSync(wrapperPath)) {
|
|
28
|
+
throw new Error(
|
|
29
|
+
"Couldn't find zapierwrapper.mjs in zapier-platform-core. Are you trying to run ESM? " +
|
|
30
|
+
'If so, you need to upgrade zapier-platform-core to at least v17.',
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const wrapperText = (await readFile(wrapperPath, 'utf8')).replace(
|
|
35
|
+
'{REPLACE_ME_PACKAGE_NAME}',
|
|
36
|
+
appPackageJson.name,
|
|
37
|
+
);
|
|
38
|
+
const wrapperDest = join(appDir, 'zapierwrapper.js');
|
|
39
|
+
await writeFile(wrapperDest, wrapperText);
|
|
40
|
+
return wrapperDest;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const deleteZapierWrapper = async (appDir) => {
|
|
44
|
+
const wrapperPath = join(appDir, 'zapierwrapper.js');
|
|
45
|
+
try {
|
|
46
|
+
await rm(wrapperPath);
|
|
47
|
+
} catch (err) {
|
|
48
|
+
// ignore
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
module.exports = {
|
|
53
|
+
copyZapierWrapper,
|
|
54
|
+
deleteZapierWrapper,
|
|
55
|
+
};
|
package/src/version-store.js
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
module.exports = require('./dist').default;
|