diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 95f54f0..dc50fbd 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -2,14 +2,34 @@ module.exports = { env: { node: true, es2021: true, + jest: true, // Add jest environment for test files }, - extends: ['eslint:recommended'], + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended', + 'plugin:@typescript-eslint/strict', + ], + parser: '@typescript-eslint/parser', + plugins: ['@typescript-eslint'], parserOptions: { ecmaVersion: 'latest', sourceType: 'module', + project: './tsconfig.json', }, rules: { 'no-console': 'warn', - 'no-unused-vars': ['error', { argsIgnorePattern: '^_' }], + 'no-unused-vars': 'off', // Turn off base rule as it can report incorrect errors + '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }], + '@typescript-eslint/no-explicit-any': 'error', + '@typescript-eslint/explicit-function-return-type': 'error', }, + ignorePatterns: [ + 'index.js', + 'dist/**/*', + 'coverage/**/*', + 'test/**/*', + '**/*.test.ts', + 'vitest.config.ts', + 'vitest.visual.config.ts', + ], }; diff --git a/.prettierrc b/.prettierrc index a95cb05..eba5a68 100644 --- a/.prettierrc +++ b/.prettierrc @@ -2,6 +2,6 @@ "semi": true, "singleQuote": true, "trailingComma": "es5", - "printWidth": 100, + "printWidth": 80, "tabWidth": 2 } diff --git a/docs/developer-documentation.md b/docs/developer-documentation.md index 0638ae5..7a5fd27 100644 --- a/docs/developer-documentation.md +++ b/docs/developer-documentation.md @@ -42,6 +42,8 @@ - `npm run lint` - Run ESLint - `npm run format` - Format code with Prettier - `npm run clean` - Clean up generated files +- `npm run build` - Compile TypeScript code +- `npm run deploy` - Deploy to Zapier - `npm run prepare` - Install git hooks (runs automatically after npm install) Visual tests are only run in CI environment: @@ -166,7 +168,7 @@ The integration is automatically deployed to Zapier when a new version tag is pu If you wish to deploy the integration privately, you can do so by following the steps below, given that you have completed the [initial setup steps above](#setting-up-zapier-deployment). ```bash -zapier push +npm run build && zapier push ``` ## Version Management diff --git a/package-lock.json b/package-lock.json index aade23c..f343bf0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,8 @@ "zapier-platform-core": "16.3.0" }, "devDependencies": { + "@typescript-eslint/eslint-plugin": "^8.28.0", + "@typescript-eslint/parser": "^8.28.0", "@vitest/coverage-v8": "^3.0.8", "eslint": "^8.57.1", "husky": "^9.1.7", @@ -2418,6 +2420,238 @@ "@types/node": "*" } }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.28.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.28.0.tgz", + "integrity": "sha512-lvFK3TCGAHsItNdWZ/1FkvpzCxTHUVuFrdnOGLMa0GGCFIbCgQWVk3CzCGdA7kM3qGVc+dfW9tr0Z/sHnGDFyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.28.0", + "@typescript-eslint/type-utils": "8.28.0", + "@typescript-eslint/utils": "8.28.0", + "@typescript-eslint/visitor-keys": "8.28.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.0.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.28.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.28.0.tgz", + "integrity": "sha512-LPcw1yHD3ToaDEoljFEfQ9j2xShY367h7FZ1sq5NJT9I3yj4LHer1Xd1yRSOdYy9BpsrxU7R+eoDokChYM53lQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.28.0", + "@typescript-eslint/types": "8.28.0", + "@typescript-eslint/typescript-estree": "8.28.0", + "@typescript-eslint/visitor-keys": "8.28.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.28.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.28.0.tgz", + "integrity": "sha512-u2oITX3BJwzWCapoZ/pXw6BCOl8rJP4Ij/3wPoGvY8XwvXflOzd1kLrDUUUAIEdJSFh+ASwdTHqtan9xSg8buw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.28.0", + "@typescript-eslint/visitor-keys": "8.28.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.28.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.28.0.tgz", + "integrity": "sha512-oRoXu2v0Rsy/VoOGhtWrOKDiIehvI+YNrDk5Oqj40Mwm0Yt01FC/Q7nFqg088d3yAsR1ZcZFVfPCTTFCe/KPwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "8.28.0", + "@typescript-eslint/utils": "8.28.0", + "debug": "^4.3.4", + "ts-api-utils": "^2.0.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.28.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.28.0.tgz", + "integrity": "sha512-bn4WS1bkKEjx7HqiwG2JNB3YJdC1q6Ue7GyGlwPHyt0TnVq6TtD/hiOdTZt71sq0s7UzqBFXD8t8o2e63tXgwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.28.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.28.0.tgz", + "integrity": "sha512-H74nHEeBGeklctAVUvmDkxB1mk+PAZ9FiOMPFncdqeRBXxk1lWSYraHw8V12b7aa6Sg9HOBNbGdSHobBPuQSuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.28.0", + "@typescript-eslint/visitor-keys": "8.28.0", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.0.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.28.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.28.0.tgz", + "integrity": "sha512-OELa9hbTYciYITqgurT1u/SzpQVtDLmQMFzy/N8pQE+tefOyCWT79jHsav294aTqV1q1u+VzqDGbuujvRYaeSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.28.0", + "@typescript-eslint/types": "8.28.0", + "@typescript-eslint/typescript-estree": "8.28.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.28.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.28.0.tgz", + "integrity": "sha512-hbn8SZ8w4u2pRwgQ1GlUrPKE+t2XvcCW5tTRF7j6SMYIuYG37XuzIW44JCZPa36evi0Oy2SnM664BlIaAuQcvg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.28.0", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@ungap/structured-clone": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", @@ -4443,6 +4677,36 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -7120,6 +7384,16 @@ "dev": true, "license": "MIT" }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, "node_modules/micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", @@ -9001,6 +9275,19 @@ "node": ">=18" } }, + "node_modules/ts-api-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", + "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", diff --git a/package.json b/package.json index a7bf73b..d2a31a0 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,8 @@ "zapier-platform-core": "16.3.0" }, "devDependencies": { + "@typescript-eslint/eslint-plugin": "^8.28.0", + "@typescript-eslint/parser": "^8.28.0", "@vitest/coverage-v8": "^3.0.8", "eslint": "^8.57.1", "husky": "^9.1.7", diff --git a/src/actions/assign-screen-to-playlist.ts b/src/actions/assign-screen-to-playlist.ts index d76b8e4..fe63ef6 100644 --- a/src/actions/assign-screen-to-playlist.ts +++ b/src/actions/assign-screen-to-playlist.ts @@ -1,3 +1,4 @@ +import { ZObject, Bundle } from 'zapier-platform-core'; import utils from '../utils.js'; const assignScreenToPlaylist = { @@ -26,7 +27,7 @@ const assignScreenToPlaylist = { helpText: 'Select the playlist to assign to the screen', }, ], - perform: async (z: any, bundle: any) => { + perform: async (z: ZObject, bundle: Bundle): Promise => { return await utils.assignPlaylistToScreen(z, bundle, { screenId: bundle.inputData.screen_id, playlistId: bundle.inputData.playlist_id, diff --git a/src/actions/cleanup-zapier-content.ts b/src/actions/cleanup-zapier-content.ts index 67fcced..04622d0 100644 --- a/src/actions/cleanup-zapier-content.ts +++ b/src/actions/cleanup-zapier-content.ts @@ -1,3 +1,4 @@ +import { ZObject, Bundle } from 'zapier-platform-core'; import utils from '../utils.js'; import { ZAPIER_TAG } from '../constants.js'; @@ -15,10 +16,11 @@ const cleanupZapierContent = { label: 'Confirm Cleanup', type: 'boolean', required: true, - helpText: 'Are you sure you want to remove all content created by Zapier?', + helpText: + 'Are you sure you want to remove all content created by Zapier?', }, ], - perform: async (z: any, bundle: any) => { + perform: async (z: ZObject, bundle: Bundle): Promise => { if (!bundle.inputData.confirm) { throw new Error('Please confirm the cleanup operation'); } @@ -27,11 +29,17 @@ const cleanupZapierContent = { const label = await utils.getLabel(z, bundle, { name: ZAPIER_TAG }); // Get all playlists associated with the Zapier tag - const playlistToLabelMappings = await utils.getPlaylistsByLabel(z, bundle, { - labelId: label.id, - }); + const playlistToLabelMappings = await utils.getPlaylistsByLabel( + z, + bundle, + { + labelId: label.id, + } + ); - const playListIds = playlistToLabelMappings.map((mapping: any) => mapping.playlist_id); + const playListIds = playlistToLabelMappings.map( + (mapping: { playlist_id: string }) => mapping.playlist_id + ); let successfulDeletions = 0; // Delete each playlist diff --git a/src/actions/complete-workflow.ts b/src/actions/complete-workflow.ts index 2c4bc54..1a90f51 100644 --- a/src/actions/complete-workflow.ts +++ b/src/actions/complete-workflow.ts @@ -1,3 +1,4 @@ +import { ZObject, Bundle } from 'zapier-platform-core'; import utils from '../utils.js'; import { ZAPIER_TAG } from '../constants.js'; @@ -56,9 +57,18 @@ const completeWorkflow = { helpText: 'Select the screen to assign', }, ], - perform: async (z: any, bundle: any) => { - if (!bundle.inputData.playlist_id && !bundle.inputData.new_playlist_name) { - throw new Error('Either select an existing playlist or provide a name for a new one'); + perform: async (z: ZObject, bundle: Bundle): Promise => { + if (!bundle.authData.api_key) { + throw new Error('API key is required'); + } + + if ( + !bundle.inputData.playlist_id && + !bundle.inputData.new_playlist_name + ) { + throw new Error( + 'Either select an existing playlist or provide a name for a new one' + ); } // Upload asset @@ -86,8 +96,8 @@ const completeWorkflow = { }, }); - let labelId: any; - const existingLabels = labelQueryResponse.json; + let labelId: string; + const existingLabels = labelQueryResponse.data; if (existingLabels.length > 0) { labelId = existingLabels[0].id; @@ -104,7 +114,10 @@ const completeWorkflow = { name: ZAPIER_TAG, }, }); - labelId = utils.handleError(labelResponse, 'Failed to create label').id; + labelId = utils.handleError( + labelResponse, + 'Failed to create label' + ).id; } // Tag the new playlist diff --git a/src/actions/schedule-playlist-item.ts b/src/actions/schedule-playlist-item.ts index e64968c..ad1306b 100644 --- a/src/actions/schedule-playlist-item.ts +++ b/src/actions/schedule-playlist-item.ts @@ -1,3 +1,4 @@ +import { ZObject, Bundle } from 'zapier-platform-core'; import utils from '../utils.js'; const schedulePlaylistItem = { @@ -34,8 +35,16 @@ const schedulePlaylistItem = { helpText: 'How long should this asset be shown (in seconds)', }, ], - perform: async (z: any, bundle: any) => { - await utils.waitForAssetReady(z, bundle.inputData.asset_id, bundle.authData.api_key); + perform: async (z: ZObject, bundle: Bundle): Promise => { + if (!bundle.authData.api_key) { + throw new Error('API key is required'); + } + + await utils.waitForAssetReady( + z, + bundle.inputData.asset_id, + bundle.authData.api_key + ); return await utils.createPlaylistItem(z, bundle, { assetId: bundle.inputData.asset_id, diff --git a/src/actions/upload-asset.ts b/src/actions/upload-asset.ts index 5022a91..d074d6d 100644 --- a/src/actions/upload-asset.ts +++ b/src/actions/upload-asset.ts @@ -1,3 +1,4 @@ +import { ZObject, Bundle } from 'zapier-platform-core'; import utils from '../utils.js'; const uploadAsset = { @@ -24,7 +25,7 @@ const uploadAsset = { helpText: 'Title of the asset', }, ], - perform: async (z: any, bundle: any) => { + perform: async (z: ZObject, bundle: Bundle): Promise => { return await utils.createAsset(z, bundle, { title: bundle.inputData.title, sourceUrl: bundle.inputData.file, diff --git a/src/triggers/get-assets.ts b/src/triggers/get-assets.ts index 67ae4b1..57c2ea2 100644 --- a/src/triggers/get-assets.ts +++ b/src/triggers/get-assets.ts @@ -1,3 +1,4 @@ +import { ZObject, Bundle } from 'zapier-platform-core'; import utils from '../utils.js'; const getAssets = { @@ -9,7 +10,7 @@ const getAssets = { hidden: true, }, operation: { - perform: async (z: any, bundle: any) => { + perform: async (z: ZObject, bundle: Bundle): Promise => { const response = await z.request({ url: 'https://api.screenlyapp.com/api/v4/assets/', headers: { diff --git a/src/triggers/get-playlists.ts b/src/triggers/get-playlists.ts index 3e4a034..b066a01 100644 --- a/src/triggers/get-playlists.ts +++ b/src/triggers/get-playlists.ts @@ -1,3 +1,4 @@ +import { ZObject, Bundle } from 'zapier-platform-core'; import utils from '../utils.js'; const getPlaylists = { @@ -9,7 +10,7 @@ const getPlaylists = { hidden: true, }, operation: { - perform: async (z: any, bundle: any) => { + perform: async (z: ZObject, bundle: Bundle): Promise => { const response = await z.request({ url: 'https://api.screenlyapp.com/api/v4/playlists/', headers: { diff --git a/src/triggers/get-screens.ts b/src/triggers/get-screens.ts index 3b4857e..368b205 100644 --- a/src/triggers/get-screens.ts +++ b/src/triggers/get-screens.ts @@ -1,3 +1,4 @@ +import { ZObject, Bundle } from 'zapier-platform-core'; import utils from '../utils.js'; const getScreens = { @@ -9,7 +10,7 @@ const getScreens = { hidden: true, }, operation: { - perform: async (z: any, bundle: any) => { + perform: async (z: ZObject, bundle: Bundle): Promise => { const response = await z.request({ url: 'https://api.screenlyapp.com/api/v4/screens/', headers: { diff --git a/src/types/screenly.ts b/src/types/screenly.ts new file mode 100644 index 0000000..0de4df2 --- /dev/null +++ b/src/types/screenly.ts @@ -0,0 +1,32 @@ +// The interface declarations do not include all the fields in the API response. +// For more information, see the API documentation: https://developer.screenly.io/api_v4/ + +export interface Asset { + id: string; + title: string; + source_url: string; + status: string; + created_at: string; + disable_verification: boolean; +} + +export interface Playlist { + id: string; + title: string; + predicate: string; +} + +export interface PlaylistItem { + asset_id: string; + playlist_id: string; + duration?: number; +} + +export interface PlaylistLabel { + playlist_id: string; +} + +export interface Label { + id: string; + name: string; +} diff --git a/src/utils.ts b/src/utils.ts index ee28f10..d70583f 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,29 +1,31 @@ // Utility functions for Screenly Zapier integration +import { ZObject, Bundle, HttpResponse } from 'zapier-platform-core'; import { READY_STATES } from './constants.js'; - -const handleError = (response: any, customMessage: string) => { +import { + Asset, + PlaylistItem, + Playlist, + Label, + PlaylistLabel, +} from './types/screenly.js'; + +const handleError = ( + response: HttpResponse, + customMessage: string +): T => { if (response.status >= 400) { throw new Error(customMessage); } - return response.json; -}; - -const makeRequest = async (z: any, url: string, options: any = {}) => { - const response = await z.request({ - url, - ...options, - headers: { - ...options.headers, - Authorization: `Token ${z.authData.api_key}`, - }, - }); - - return handleError(response, 'Screenly API Error'); + return response.data; }; -const waitForAssetReady = async (z: any, assetId: any, authToken: string) => { +const waitForAssetReady = async ( + z: ZObject, + assetId: string, + authToken: string +): Promise => { let assetStatus; do { const statusResponse = await z.request({ @@ -44,10 +46,14 @@ const waitForAssetReady = async (z: any, assetId: any, authToken: string) => { }; const createAsset = async ( - z: any, - bundle: any, - { title, sourceUrl, disableVerification = false }: any -) => { + z: ZObject, + bundle: Bundle, + { + title, + sourceUrl, + disableVerification = false, + }: { title: string; sourceUrl: string; disableVerification?: boolean } +): Promise => { const response = await z.request({ url: 'https://api.screenlyapp.com/api/v4/assets/', method: 'POST', @@ -72,8 +78,16 @@ const createAsset = async ( return assets[0]; }; -const createPlaylistItem = async (z: any, bundle: any, { assetId, playlistId, duration }: any) => { - const payload: any = { +const createPlaylistItem = async ( + z: ZObject, + bundle: Bundle, + { + assetId, + playlistId, + duration, + }: { assetId: string; playlistId: string; duration: number } +): Promise => { + const payload: PlaylistItem = { asset_id: assetId, playlist_id: playlistId, }; @@ -103,10 +117,10 @@ const createPlaylistItem = async (z: any, bundle: any, { assetId, playlistId, du }; const assignPlaylistToScreen = async ( - z: any, - bundle: any, + z: ZObject, + bundle: Bundle, { screenId, playlistId }: { screenId: string; playlistId: string } -) => { +): Promise<{ screen_id: string; playlist_id: string; message: string }> => { const response = await z.request({ url: `https://api.screenlyapp.com/api/v4/labels/playlists`, method: 'POST', @@ -136,10 +150,10 @@ const assignPlaylistToScreen = async ( }; const createPlaylist = async ( - z: any, - bundle: any, - { title, predicate }: { title: string; predicate: any } -) => { + z: ZObject, + bundle: Bundle, + { title, predicate }: { title: string; predicate: string } +): Promise => { const response = await z.request({ url: 'https://api.screenlyapp.com/api/v4/playlists', method: 'POST', @@ -163,11 +177,13 @@ const createPlaylist = async ( return playlists[0]; }; -const getLabel = async (z: any, bundle: any, { name }: { name: string }) => { - const queryParams: any = { name: `eq.${name}` }; - const queryString = Object.keys(queryParams) - .map((key) => `${key}=${queryParams[key]}`) - .join('&'); +const getLabel = async ( + z: ZObject, + bundle: Bundle, + { name }: { name: string } +): Promise