zapier-platform-cli 17.3.0 → 17.4.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.
- package/oclif.manifest.json +16 -4
- package/package.json +1 -1
- package/scaffold/resource.template.ts +30 -9
- package/src/generators/index.js +70 -68
- package/src/generators/templates/README.template.md +10 -0
- package/src/generators/templates/authTests/basic.test.ts +42 -0
- package/src/generators/templates/authTests/custom.test.ts +34 -0
- package/src/generators/templates/authTests/digest.test.ts +43 -0
- package/src/generators/templates/authTests/oauth1.test.ts +63 -0
- package/src/generators/templates/authTests/oauth2.test.ts +115 -0
- package/src/generators/templates/authTests/session.test.ts +36 -0
- package/src/generators/templates/index.template.ts +11 -14
- package/src/generators/templates/tsconfig.template.json +18 -0
- package/src/oclif/commands/init.js +9 -2
- package/src/oclif/commands/versions.js +0 -24
- package/src/utils/auth-files-codegen.js +141 -69
- package/src/utils/build.js +62 -53
- package/src/utils/codegen.js +24 -4
- package/src/utils/files.js +12 -2
- package/src/utils/zapierwrapper.js +1 -1
- package/src/generators/templates/index-esm.template.ts +0 -24
- package/src/generators/templates/typescript/README.md +0 -3
- package/src/generators/templates/typescript/src/authentication.ts +0 -48
- package/src/generators/templates/typescript/src/constants.ts +0 -3
- package/src/generators/templates/typescript/src/creates/movie.ts +0 -43
- package/src/generators/templates/typescript/src/middleware.ts +0 -11
- package/src/generators/templates/typescript/src/test/creates.test.ts +0 -21
- package/src/generators/templates/typescript/src/test/triggers.test.ts +0 -25
- package/src/generators/templates/typescript/src/triggers/movie.ts +0 -29
- package/src/generators/templates/typescript/tsconfig.json +0 -17
package/src/utils/build.js
CHANGED
|
@@ -64,12 +64,10 @@ const findRequiredFiles = async (workingDir, entryPoints) => {
|
|
|
64
64
|
platform: 'node',
|
|
65
65
|
metafile: true,
|
|
66
66
|
logLevel: 'warning',
|
|
67
|
-
|
|
68
|
-
'
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
'./xhr-sync-worker.js', // appears in jsdom/living/xmlhttprequest.js
|
|
72
|
-
],
|
|
67
|
+
logOverride: {
|
|
68
|
+
'require-resolve-not-external': 'silent',
|
|
69
|
+
},
|
|
70
|
+
external: ['../test/userapp'],
|
|
73
71
|
format,
|
|
74
72
|
// Setting conditions to an empty array to exclude 'module' condition,
|
|
75
73
|
// which Node.js doesn't use. https://esbuild.github.io/api/#conditions
|
|
@@ -220,44 +218,6 @@ const openZip = (outputPath) => {
|
|
|
220
218
|
return zip;
|
|
221
219
|
};
|
|
222
220
|
|
|
223
|
-
const looksLikeWorkspaceRoot = async (dir) => {
|
|
224
|
-
if (fs.existsSync(path.join(dir, 'pnpm-workspace.yaml'))) {
|
|
225
|
-
return true;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
const packageJsonPath = path.join(dir, 'package.json');
|
|
229
|
-
if (!fs.existsSync(packageJsonPath)) {
|
|
230
|
-
return false;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
let packageJson;
|
|
234
|
-
try {
|
|
235
|
-
packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
236
|
-
} catch (err) {
|
|
237
|
-
return false;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
return packageJson?.workspaces != null;
|
|
241
|
-
};
|
|
242
|
-
|
|
243
|
-
// Traverses up the directory tree to find the workspace root. The workspace
|
|
244
|
-
// root directory either contains pnpm-workspace.yaml or a package.json file
|
|
245
|
-
// with a "workspaces" field. Returns the absolute path to the workspace root
|
|
246
|
-
// directory, or null if not found.
|
|
247
|
-
const findWorkspaceRoot = async (workingDir) => {
|
|
248
|
-
let dir = workingDir;
|
|
249
|
-
for (let i = 0; i < 500; i++) {
|
|
250
|
-
if (await looksLikeWorkspaceRoot(dir)) {
|
|
251
|
-
return dir;
|
|
252
|
-
}
|
|
253
|
-
if (dir === '/' || dir.match(/^[a-z]:\\$/i)) {
|
|
254
|
-
break;
|
|
255
|
-
}
|
|
256
|
-
dir = path.dirname(dir);
|
|
257
|
-
}
|
|
258
|
-
return null;
|
|
259
|
-
};
|
|
260
|
-
|
|
261
221
|
const getNearestNodeModulesDir = (workingDir, relPath) => {
|
|
262
222
|
if (path.basename(relPath) === 'package.json') {
|
|
263
223
|
const nmDir = path.resolve(
|
|
@@ -266,7 +226,7 @@ const getNearestNodeModulesDir = (workingDir, relPath) => {
|
|
|
266
226
|
'node_modules',
|
|
267
227
|
);
|
|
268
228
|
return fs.existsSync(nmDir) ? path.relative(workingDir, nmDir) : null;
|
|
269
|
-
} else {
|
|
229
|
+
} else if (relPath.includes('node_modules')) {
|
|
270
230
|
let dir = path.dirname(relPath);
|
|
271
231
|
for (let i = 0; i < 100; i++) {
|
|
272
232
|
if (dir.endsWith(`${path.sep}node_modules`)) {
|
|
@@ -278,8 +238,49 @@ const getNearestNodeModulesDir = (workingDir, relPath) => {
|
|
|
278
238
|
}
|
|
279
239
|
dir = nextDir;
|
|
280
240
|
}
|
|
281
|
-
return null;
|
|
282
241
|
}
|
|
242
|
+
|
|
243
|
+
let dir = path.dirname(relPath);
|
|
244
|
+
for (let i = 0; i < 100; i++) {
|
|
245
|
+
const nmDir = path.join(dir, 'node_modules');
|
|
246
|
+
if (fs.existsSync(path.resolve(workingDir, nmDir))) {
|
|
247
|
+
return nmDir;
|
|
248
|
+
}
|
|
249
|
+
const nextDir = path.dirname(dir);
|
|
250
|
+
if (nextDir === dir) {
|
|
251
|
+
break;
|
|
252
|
+
}
|
|
253
|
+
dir = nextDir;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return null;
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
const countLeadingDoubleDots = (relPath) => {
|
|
260
|
+
const parts = relPath.split(path.sep);
|
|
261
|
+
for (let i = 0; i < parts.length; i++) {
|
|
262
|
+
if (parts[i] !== '..') {
|
|
263
|
+
return i;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return 0;
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
// Join all relPaths with workingDir and return the common ancestor directory.
|
|
270
|
+
const findCommonAncestor = (workingDir, relPaths) => {
|
|
271
|
+
let maxLeadingDoubleDots = 0;
|
|
272
|
+
for (const relPath of relPaths) {
|
|
273
|
+
maxLeadingDoubleDots = Math.max(
|
|
274
|
+
maxLeadingDoubleDots,
|
|
275
|
+
countLeadingDoubleDots(relPath),
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
let commonAncestor = workingDir;
|
|
280
|
+
for (let i = 0; i < maxLeadingDoubleDots; i++) {
|
|
281
|
+
commonAncestor = path.dirname(commonAncestor);
|
|
282
|
+
}
|
|
283
|
+
return commonAncestor;
|
|
283
284
|
};
|
|
284
285
|
|
|
285
286
|
const writeBuildZipDumbly = async (workingDir, zip) => {
|
|
@@ -322,11 +323,14 @@ const writeBuildZipSmartly = async (workingDir, zip) => {
|
|
|
322
323
|
]),
|
|
323
324
|
).sort();
|
|
324
325
|
|
|
325
|
-
const
|
|
326
|
+
const zipRoot = findCommonAncestor(workingDir, relPaths) || workingDir;
|
|
326
327
|
|
|
327
|
-
if (
|
|
328
|
-
const appDirRelPath = path.relative(
|
|
329
|
-
|
|
328
|
+
if (zipRoot !== workingDir) {
|
|
329
|
+
const appDirRelPath = path.relative(zipRoot, workingDir);
|
|
330
|
+
// zapierwrapper.js and index.js are entry points.
|
|
331
|
+
// 'config' is the default directory that the 'config' npm package expects
|
|
332
|
+
// to find config files at the root directory.
|
|
333
|
+
const linkNames = ['zapierwrapper.js', 'index.js', 'config'];
|
|
330
334
|
for (const name of linkNames) {
|
|
331
335
|
if (fs.existsSync(path.join(workingDir, name))) {
|
|
332
336
|
zip.symlink(name, path.join(appDirRelPath, name), 0o644);
|
|
@@ -343,8 +347,8 @@ const writeBuildZipSmartly = async (workingDir, zip) => {
|
|
|
343
347
|
// Write required files to the zip
|
|
344
348
|
for (const relPath of relPaths) {
|
|
345
349
|
const absPath = path.resolve(workingDir, relPath);
|
|
346
|
-
const nameInZip = path.relative(
|
|
347
|
-
if (nameInZip === 'package.json' &&
|
|
350
|
+
const nameInZip = path.relative(zipRoot, absPath);
|
|
351
|
+
if (nameInZip === 'package.json' && zipRoot !== workingDir) {
|
|
348
352
|
// Ignore workspace root's package.json
|
|
349
353
|
continue;
|
|
350
354
|
}
|
|
@@ -381,7 +385,7 @@ const writeBuildZipSmartly = async (workingDir, zip) => {
|
|
|
381
385
|
symlink.parentPath,
|
|
382
386
|
symlink.name,
|
|
383
387
|
);
|
|
384
|
-
const nameInZip = path.relative(
|
|
388
|
+
const nameInZip = path.relative(zipRoot, absPath);
|
|
385
389
|
const targetInZip = path.relative(
|
|
386
390
|
symlink.parentPath,
|
|
387
391
|
fs.realpathSync(absPath),
|
|
@@ -548,6 +552,11 @@ const testBuildZip = async (zipPath) => {
|
|
|
548
552
|
`You may have to add it to ${colors.bold.underline('includeInBuild')} ` +
|
|
549
553
|
`in your ${colors.bold.underline('.zapierapprc')} file.`,
|
|
550
554
|
);
|
|
555
|
+
} else if (error.message) {
|
|
556
|
+
// Hide the unzipped temporary directory
|
|
557
|
+
error.message = error.message
|
|
558
|
+
.replaceAll(`file://${testDir}/`, '')
|
|
559
|
+
.replaceAll(`${testDir}/`, '');
|
|
551
560
|
}
|
|
552
561
|
throw error;
|
|
553
562
|
}
|
package/src/utils/codegen.js
CHANGED
|
@@ -23,19 +23,30 @@ const obj = (...properties) =>
|
|
|
23
23
|
.join('')}}
|
|
24
24
|
`.trim();
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
// TypeScript version of obj that supports satisfies clause
|
|
27
|
+
const objTS = (type, ...properties) =>
|
|
28
|
+
`
|
|
29
|
+
{${properties
|
|
30
|
+
.map((p) => (p.startsWith('/') ? `\n\n${p}\n` : p + ','))
|
|
31
|
+
.join('')}}
|
|
32
|
+
`.trim() + ` satisfies ${type}`;
|
|
33
|
+
|
|
34
|
+
const exportStatement = (obj, language) =>
|
|
35
|
+
language === 'typescript'
|
|
36
|
+
? `export default ${obj}`
|
|
37
|
+
: `module.exports = ${obj}`;
|
|
28
38
|
|
|
29
39
|
/**
|
|
30
40
|
* @param {string} key could be a variable name or string value
|
|
31
41
|
* @param {string | undefined} value can either be a variable or actual string. or could be missing, in which case the input is treated as a variable
|
|
42
|
+
* @param {string | undefined} satisfiesType if provided, the property will be typed with the given type
|
|
32
43
|
*/
|
|
33
|
-
const objProperty = (key, value) => {
|
|
44
|
+
const objProperty = (key, value, satisfiesType) => {
|
|
34
45
|
if (value === undefined) {
|
|
35
46
|
return `${key}`;
|
|
36
47
|
}
|
|
37
48
|
// wrap key in quotes here in case the key isn't a valid property. prettier will remove if needed
|
|
38
|
-
return `'${key}': ${value}`;
|
|
49
|
+
return `'${key}': ${value}${satisfiesType ? ` satisfies ${satisfiesType}` : ''}`;
|
|
39
50
|
};
|
|
40
51
|
|
|
41
52
|
const variableAssignmentDeclaration = (varName, value) =>
|
|
@@ -157,6 +168,13 @@ const file = (...statements) =>
|
|
|
157
168
|
${statements.join('\n\n')}
|
|
158
169
|
`.trim();
|
|
159
170
|
|
|
171
|
+
const fileTS = (typesToImport = [], ...statements) =>
|
|
172
|
+
`
|
|
173
|
+
import type { ${typesToImport.join(', ')} } from 'zapier-platform-core';
|
|
174
|
+
|
|
175
|
+
${statements.join('\n\n')}
|
|
176
|
+
`.trim();
|
|
177
|
+
|
|
160
178
|
module.exports = {
|
|
161
179
|
arr,
|
|
162
180
|
assignmentStatement,
|
|
@@ -166,11 +184,13 @@ module.exports = {
|
|
|
166
184
|
exportStatement,
|
|
167
185
|
fatArrowReturnFunctionDeclaration,
|
|
168
186
|
file,
|
|
187
|
+
fileTS,
|
|
169
188
|
functionDeclaration,
|
|
170
189
|
ifStatement,
|
|
171
190
|
interpLiteral,
|
|
172
191
|
obj,
|
|
173
192
|
objProperty,
|
|
193
|
+
objTS,
|
|
174
194
|
RESPONSE_VAR,
|
|
175
195
|
returnStatement,
|
|
176
196
|
strLiteral,
|
package/src/utils/files.js
CHANGED
|
@@ -207,9 +207,14 @@ function* walkDir(dir) {
|
|
|
207
207
|
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
208
208
|
for (const entry of entries) {
|
|
209
209
|
if (entry.isDirectory()) {
|
|
210
|
-
const subDir = path.join(
|
|
210
|
+
const subDir = path.join(dir, entry.name);
|
|
211
211
|
yield* walkDir(subDir);
|
|
212
212
|
} else if (entry.isFile() || entry.isSymbolicLink()) {
|
|
213
|
+
if (!entry.parentPath) {
|
|
214
|
+
// dirent.parentPath is only available since Node.js 18.20, 20.12, and
|
|
215
|
+
// 21.4. Re-assigning it so the caller can use dirent.parentPath.
|
|
216
|
+
entry.parentPath = dir;
|
|
217
|
+
}
|
|
213
218
|
yield entry;
|
|
214
219
|
}
|
|
215
220
|
}
|
|
@@ -223,10 +228,15 @@ function* walkDirLimitedLevels(dir, maxLevels, currentLevel = 1) {
|
|
|
223
228
|
for (const entry of entries) {
|
|
224
229
|
if (entry.isDirectory()) {
|
|
225
230
|
if (currentLevel < maxLevels) {
|
|
226
|
-
const subDir = path.join(
|
|
231
|
+
const subDir = path.join(dir, entry.name);
|
|
227
232
|
yield* walkDirLimitedLevels(subDir, maxLevels, currentLevel + 1);
|
|
228
233
|
}
|
|
229
234
|
} else if (entry.isFile() || entry.isSymbolicLink()) {
|
|
235
|
+
if (!entry.parentPath) {
|
|
236
|
+
// dirent.parentPath is only available since Node.js 18.20, 20.12, and
|
|
237
|
+
// 21.4. Re-assigning it so the caller can use dirent.parentPath.
|
|
238
|
+
entry.parentPath = dir;
|
|
239
|
+
}
|
|
230
240
|
yield entry;
|
|
231
241
|
}
|
|
232
242
|
}
|
|
@@ -31,7 +31,7 @@ const copyZapierWrapper = async (corePackageDir, appDir) => {
|
|
|
31
31
|
);
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
const wrapperText = (await readFile(wrapperPath, 'utf8')).
|
|
34
|
+
const wrapperText = (await readFile(wrapperPath, 'utf8')).replaceAll(
|
|
35
35
|
'{REPLACE_ME_PACKAGE_NAME}',
|
|
36
36
|
appPackageJson.name,
|
|
37
37
|
);
|
|
@@ -1,24 +0,0 @@
|
|
|
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,48 +0,0 @@
|
|
|
1
|
-
import type { Authentication } from 'zapier-platform-core';
|
|
2
|
-
|
|
3
|
-
import { API_URL, SCOPES } from './constants.js';
|
|
4
|
-
|
|
5
|
-
export default {
|
|
6
|
-
type: 'oauth2',
|
|
7
|
-
test: { url: `${API_URL}/me` },
|
|
8
|
-
connectionLabel: '{{email}}', // Set this from the test data.
|
|
9
|
-
oauth2Config: {
|
|
10
|
-
authorizeUrl: {
|
|
11
|
-
url: `${API_URL}/oauth/authorize`,
|
|
12
|
-
params: {
|
|
13
|
-
client_id: '{{process.env.CLIENT_ID}}',
|
|
14
|
-
response_type: 'code',
|
|
15
|
-
scope: SCOPES.join(' '),
|
|
16
|
-
redirect_uri: '{{bundle.inputData.redirect_uri}}',
|
|
17
|
-
state: '{{bundle.inputData.state}}',
|
|
18
|
-
},
|
|
19
|
-
},
|
|
20
|
-
getAccessToken: {
|
|
21
|
-
url: `${API_URL}/oauth/access-token`,
|
|
22
|
-
method: 'POST',
|
|
23
|
-
headers: {
|
|
24
|
-
'content-type': 'application/x-www-form-urlencoded',
|
|
25
|
-
},
|
|
26
|
-
body: {
|
|
27
|
-
client_id: '{{process.env.CLIENT_ID}}',
|
|
28
|
-
client_secret: '{{process.env.CLIENT_SECRET}}',
|
|
29
|
-
code: '{{bundle.inputData.code}}',
|
|
30
|
-
grant_type: 'authorization_code',
|
|
31
|
-
redirect_uri: '{{bundle.inputData.redirect_uri}}',
|
|
32
|
-
},
|
|
33
|
-
},
|
|
34
|
-
refreshAccessToken: {
|
|
35
|
-
url: `${API_URL}/oauth/refresh-token`,
|
|
36
|
-
method: 'POST',
|
|
37
|
-
headers: {
|
|
38
|
-
'content-type': 'application/x-www-form-urlencoded',
|
|
39
|
-
},
|
|
40
|
-
body: {
|
|
41
|
-
client_id: '{{process.env.CLIENT_ID}}',
|
|
42
|
-
client_secret: '{{process.env.CLIENT_SECRET}}',
|
|
43
|
-
refresh_token: '{{bundle.authData.refresh_token}}',
|
|
44
|
-
grant_type: 'refresh_token',
|
|
45
|
-
},
|
|
46
|
-
},
|
|
47
|
-
},
|
|
48
|
-
} satisfies Authentication;
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
defineInputFields,
|
|
3
|
-
defineCreate,
|
|
4
|
-
type CreatePerform,
|
|
5
|
-
type InferInputData,
|
|
6
|
-
} from 'zapier-platform-core';
|
|
7
|
-
import { API_URL } from '../constants.js';
|
|
8
|
-
|
|
9
|
-
const inputFields = defineInputFields([
|
|
10
|
-
{ key: 'title', required: true },
|
|
11
|
-
{ key: 'year', type: 'integer' },
|
|
12
|
-
]);
|
|
13
|
-
|
|
14
|
-
const perform = (async (z, bundle) => {
|
|
15
|
-
const response = await z.request({
|
|
16
|
-
method: 'POST',
|
|
17
|
-
url: `${API_URL}/movies`,
|
|
18
|
-
body: {
|
|
19
|
-
title: bundle.inputData.title,
|
|
20
|
-
year: bundle.inputData.year,
|
|
21
|
-
},
|
|
22
|
-
});
|
|
23
|
-
return response.data;
|
|
24
|
-
}) satisfies CreatePerform<InferInputData<typeof inputFields>>;
|
|
25
|
-
|
|
26
|
-
export default defineCreate({
|
|
27
|
-
key: 'movie',
|
|
28
|
-
noun: 'Movie',
|
|
29
|
-
|
|
30
|
-
display: {
|
|
31
|
-
label: 'Create Movie',
|
|
32
|
-
description: 'Creates a new movie.',
|
|
33
|
-
},
|
|
34
|
-
|
|
35
|
-
operation: {
|
|
36
|
-
perform,
|
|
37
|
-
inputFields,
|
|
38
|
-
sample: {
|
|
39
|
-
id: '1',
|
|
40
|
-
title: 'example',
|
|
41
|
-
},
|
|
42
|
-
},
|
|
43
|
-
});
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { BeforeRequestMiddleware } from 'zapier-platform-core';
|
|
2
|
-
|
|
3
|
-
export const addBearerHeader: BeforeRequestMiddleware = (request, z, bundle) => {
|
|
4
|
-
if (bundle.authData.access_token && !request.headers?.Authorization) {
|
|
5
|
-
request.headers = {
|
|
6
|
-
...request.headers,
|
|
7
|
-
Authorization: `Bearer ${bundle.authData.access_token}`,
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
return request;
|
|
11
|
-
};
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { createAppTester, tools } from 'zapier-platform-core';
|
|
2
|
-
import { describe, test, expect } from 'vitest';
|
|
3
|
-
|
|
4
|
-
import App from '../index';
|
|
5
|
-
|
|
6
|
-
const appTester = createAppTester(App);
|
|
7
|
-
tools.env.inject();
|
|
8
|
-
|
|
9
|
-
describe('movie', () => {
|
|
10
|
-
test('create a movie', async () => {
|
|
11
|
-
const bundle = {
|
|
12
|
-
inputData: { title: 'hello', year: 2020 },
|
|
13
|
-
authData: { access_token: 'a_token' },
|
|
14
|
-
};
|
|
15
|
-
const result = await appTester(App.creates.movie.operation.perform, bundle);
|
|
16
|
-
expect(result).toMatchObject({
|
|
17
|
-
title: 'hello',
|
|
18
|
-
year: 2020,
|
|
19
|
-
});
|
|
20
|
-
});
|
|
21
|
-
});
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { createAppTester, tools } from 'zapier-platform-core';
|
|
2
|
-
import { describe, test, expect } from 'vitest';
|
|
3
|
-
|
|
4
|
-
import App from '../index';
|
|
5
|
-
|
|
6
|
-
const appTester = createAppTester(App);
|
|
7
|
-
tools.env.inject();
|
|
8
|
-
|
|
9
|
-
describe('movie', () => {
|
|
10
|
-
test('list movies', async () => {
|
|
11
|
-
const bundle = { inputData: {}, authData: { access_token: 'a_token' } };
|
|
12
|
-
const results = (await appTester(
|
|
13
|
-
App.triggers.movie.operation.perform,
|
|
14
|
-
bundle
|
|
15
|
-
)) as Array<object>;
|
|
16
|
-
|
|
17
|
-
expect(results.length).toBeGreaterThan(0);
|
|
18
|
-
|
|
19
|
-
const firstMovie = results[0];
|
|
20
|
-
expect(firstMovie).toMatchObject({
|
|
21
|
-
id: '1',
|
|
22
|
-
title: 'title 1',
|
|
23
|
-
});
|
|
24
|
-
});
|
|
25
|
-
});
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
defineTrigger,
|
|
3
|
-
type PollingTriggerPerform,
|
|
4
|
-
} from 'zapier-platform-core';
|
|
5
|
-
import { API_URL } from '../constants.js';
|
|
6
|
-
|
|
7
|
-
const perform = (async (z, bundle) => {
|
|
8
|
-
const response = await z.request(`${API_URL}/movies`);
|
|
9
|
-
return response.data;
|
|
10
|
-
}) satisfies PollingTriggerPerform;
|
|
11
|
-
|
|
12
|
-
export default defineTrigger({
|
|
13
|
-
key: 'movie',
|
|
14
|
-
noun: 'Movie',
|
|
15
|
-
|
|
16
|
-
display: {
|
|
17
|
-
label: 'New Movie',
|
|
18
|
-
description: 'Triggers when a new movie is created.',
|
|
19
|
-
},
|
|
20
|
-
|
|
21
|
-
operation: {
|
|
22
|
-
type: 'polling',
|
|
23
|
-
perform,
|
|
24
|
-
sample: {
|
|
25
|
-
id: '1',
|
|
26
|
-
title: 'example',
|
|
27
|
-
},
|
|
28
|
-
},
|
|
29
|
-
});
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ESNext",
|
|
4
|
-
"module": "NodeNext",
|
|
5
|
-
"moduleResolution": "NodeNext",
|
|
6
|
-
"resolveJsonModule": true,
|
|
7
|
-
"esModuleInterop": true,
|
|
8
|
-
"noUncheckedIndexedAccess": true,
|
|
9
|
-
"isolatedModules": true,
|
|
10
|
-
"skipLibCheck": true,
|
|
11
|
-
"outDir": "./dist",
|
|
12
|
-
"rootDir": "./src",
|
|
13
|
-
"strict": true
|
|
14
|
-
},
|
|
15
|
-
"include": ["./src/**/*.ts"],
|
|
16
|
-
"exclude": ["./**/*.test.ts"]
|
|
17
|
-
}
|