From 7706896853e8b150f8a01a3621f1bcf3c53ffa06 Mon Sep 17 00:00:00 2001 From: Roberto Escalante H <30730628+RobertoE91@users.noreply.github.com> Date: Mon, 11 Sep 2023 08:54:48 -0600 Subject: [PATCH 01/10] feat(integrations): AirTable --- integrations/airtable/.eslintrc.js | 6 + integrations/airtable/.gitignore | 50 ++ integrations/airtable/.prettierrc | 4 + integrations/airtable/icon.svg | 6 + .../airtable/integration.definition.ts | 23 + integrations/airtable/package-lock.json | 458 ++++++++++++++++++ integrations/airtable/package.json | 22 + integrations/airtable/readme.md | 58 +++ .../airtable/src/actions/create-record.ts | 32 ++ .../airtable/src/actions/create-table.ts | 28 ++ .../airtable/src/actions/get-base-tables.ts | 20 + .../airtable/src/actions/get-table-records.ts | 35 ++ integrations/airtable/src/actions/index.ts | 15 + .../airtable/src/actions/update-record.ts | 33 ++ .../airtable/src/actions/update-table.ts | 28 ++ integrations/airtable/src/client/index.ts | 70 +++ .../airtable/src/definitions/actions.ts | 98 ++++ .../airtable/src/definitions/channels.ts | 7 + .../airtable/src/definitions/index.ts | 26 + integrations/airtable/src/index.ts | 14 + .../airtable/src/misc/custom-schemas.ts | 89 ++++ .../airtable/src/misc/custom-types.ts | 5 + integrations/airtable/src/misc/custom-uis.ts | 53 ++ .../airtable/src/misc/sub-schemas/index.ts | 25 + .../airtable/src/misc/sub-types/index.ts | 1 + integrations/airtable/src/misc/types.ts | 14 + integrations/airtable/src/setup/channels.ts | 47 ++ integrations/airtable/src/setup/handler.ts | 11 + integrations/airtable/src/setup/index.ts | 4 + integrations/airtable/src/setup/register.ts | 3 + integrations/airtable/src/setup/unregister.ts | 3 + integrations/airtable/src/utils/index.ts | 25 + integrations/airtable/tsconfig.json | 28 ++ 33 files changed, 1341 insertions(+) create mode 100644 integrations/airtable/.eslintrc.js create mode 100644 integrations/airtable/.gitignore create mode 100644 integrations/airtable/.prettierrc create mode 100644 integrations/airtable/icon.svg create mode 100644 integrations/airtable/integration.definition.ts create mode 100644 integrations/airtable/package-lock.json create mode 100644 integrations/airtable/package.json create mode 100644 integrations/airtable/readme.md create mode 100644 integrations/airtable/src/actions/create-record.ts create mode 100644 integrations/airtable/src/actions/create-table.ts create mode 100644 integrations/airtable/src/actions/get-base-tables.ts create mode 100644 integrations/airtable/src/actions/get-table-records.ts create mode 100644 integrations/airtable/src/actions/index.ts create mode 100644 integrations/airtable/src/actions/update-record.ts create mode 100644 integrations/airtable/src/actions/update-table.ts create mode 100644 integrations/airtable/src/client/index.ts create mode 100644 integrations/airtable/src/definitions/actions.ts create mode 100644 integrations/airtable/src/definitions/channels.ts create mode 100644 integrations/airtable/src/definitions/index.ts create mode 100644 integrations/airtable/src/index.ts create mode 100644 integrations/airtable/src/misc/custom-schemas.ts create mode 100644 integrations/airtable/src/misc/custom-types.ts create mode 100644 integrations/airtable/src/misc/custom-uis.ts create mode 100644 integrations/airtable/src/misc/sub-schemas/index.ts create mode 100644 integrations/airtable/src/misc/sub-types/index.ts create mode 100644 integrations/airtable/src/misc/types.ts create mode 100644 integrations/airtable/src/setup/channels.ts create mode 100644 integrations/airtable/src/setup/handler.ts create mode 100644 integrations/airtable/src/setup/index.ts create mode 100644 integrations/airtable/src/setup/register.ts create mode 100644 integrations/airtable/src/setup/unregister.ts create mode 100644 integrations/airtable/src/utils/index.ts create mode 100644 integrations/airtable/tsconfig.json diff --git a/integrations/airtable/.eslintrc.js b/integrations/airtable/.eslintrc.js new file mode 100644 index 00000000000..edf84e074b1 --- /dev/null +++ b/integrations/airtable/.eslintrc.js @@ -0,0 +1,6 @@ +module.exports = { + extends: ['eslint:recommended', 'plugin:prettier/recommended'], + rules: { + 'prettier/prettier': 'warn', + }, +} diff --git a/integrations/airtable/.gitignore b/integrations/airtable/.gitignore new file mode 100644 index 00000000000..eb86529dabf --- /dev/null +++ b/integrations/airtable/.gitignore @@ -0,0 +1,50 @@ +# These are some examples of commonly ignored file patterns. +# You should customize this list as applicable to your project. +# Learn more about .gitignore: +# https://www.atlassian.com/git/tutorials/saving-changes/gitignore + +# Node artifact files +node_modules/ +dist/ + +# Compiled Java class files +*.class + +# Compiled Python bytecode +*.py[cod] + +# Log files +*.log + +# Package files +*.jar + +# Maven +target/ +dist/ + +# JetBrains IDE +.idea/ + +# Unit test reports +TEST*.xml + +# Generated by MacOS +.DS_Store + +# Generated by Windows +Thumbs.db + +# Applications +.botpress +*.app +*.exe +*.war + +# Large media files +*.mp4 +*.tiff +*.avi +*.flv +*.mov +*.wmv \ No newline at end of file diff --git a/integrations/airtable/.prettierrc b/integrations/airtable/.prettierrc new file mode 100644 index 00000000000..b2095be81e4 --- /dev/null +++ b/integrations/airtable/.prettierrc @@ -0,0 +1,4 @@ +{ + "semi": false, + "singleQuote": true +} diff --git a/integrations/airtable/icon.svg b/integrations/airtable/icon.svg new file mode 100644 index 00000000000..3f9d51bd3be --- /dev/null +++ b/integrations/airtable/icon.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/integrations/airtable/integration.definition.ts b/integrations/airtable/integration.definition.ts new file mode 100644 index 00000000000..4bdc4a541d8 --- /dev/null +++ b/integrations/airtable/integration.definition.ts @@ -0,0 +1,23 @@ +import { IntegrationDefinition } from '@botpress/sdk' +import { name } from './package.json' + +import { + configuration, + states, + user, + channels, + actions, +} from './src/definitions' + +export default new IntegrationDefinition({ + name, + version: '0.2.0', + readme: 'readme.md', + icon: 'icon.svg', + configuration, + channels, + user, + actions, + events: {}, + states, +}) \ No newline at end of file diff --git a/integrations/airtable/package-lock.json b/integrations/airtable/package-lock.json new file mode 100644 index 00000000000..f581ea18d5b --- /dev/null +++ b/integrations/airtable/package-lock.json @@ -0,0 +1,458 @@ +{ + "name": "airtable", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "airtable", + "license": "MIT", + "dependencies": { + "@botpress/client": "0.3.8", + "@botpress/sdk": "0.4.4", + "airtable": "^0.12.2", + "axios": "^1.5.0", + "zod": "^3.20.6" + }, + "devDependencies": { + "@types/node": "^18.11.17", + "ts-node": "^10.9.1", + "typescript": "^4.9.4" + } + }, + "node_modules/@botpress/client": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@botpress/client/-/client-0.3.8.tgz", + "integrity": "sha512-y31l2AkM1HzVYNhA2NaHY7UnZ7DoUJudMIMssEBUmU6CcAH2whrENeLqtpRyv+mc3AOB/kpOf1N14RwCWpz5Bg==", + "dependencies": { + "axios": "1.2.5", + "browser-or-node": "^2.1.1", + "type-fest": "^3.4.0" + } + }, + "node_modules/@botpress/client/node_modules/axios": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.2.5.tgz", + "integrity": "sha512-9pU/8mmjSSOb4CXVsvGIevN+MlO/t9OWtKadTaLuN85Gge3HGorUckgp8A/2FH4V4hJ7JuQ3LIeI7KAV9ITZrQ==", + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/@botpress/sdk": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@botpress/sdk/-/sdk-0.4.4.tgz", + "integrity": "sha512-B57YNwDgxk5vJBuGdMm/vO0STBGuZPipWxrEDptylXuLTaa8xR0SjTa1EKfVZX5oJR4vb524DeFrNC9Vh9+oDA==", + "dependencies": { + "@botpress/client": "0.3.8", + "axios": "0.27.2", + "radash": "^9.5.0", + "zod": "^3.20.6" + } + }, + "node_modules/@botpress/sdk/node_modules/axios": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", + "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", + "dependencies": { + "follow-redirects": "^1.14.9", + "form-data": "^4.0.0" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true + }, + "node_modules/@types/node": { + "version": "18.17.14", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.17.14.tgz", + "integrity": "sha512-ZE/5aB73CyGqgQULkLG87N9GnyGe5TcQjv34pwS8tfBs1IkCh0ASM69mydb2znqd6v0eX+9Ytvk6oQRqu8T1Vw==", + "dev": true + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/abortcontroller-polyfill": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.5.tgz", + "integrity": "sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ==" + }, + "node_modules/acorn": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/airtable": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/airtable/-/airtable-0.12.2.tgz", + "integrity": "sha512-HS3VytUBTKj8A0vPl7DDr5p/w3IOGv6RXL0fv7eczOWAtj9Xe8ri4TAiZRXoOyo+Z/COADCj+oARFenbxhmkIg==", + "dependencies": { + "@types/node": ">=8.0.0 <15", + "abort-controller": "^3.0.0", + "abortcontroller-polyfill": "^1.4.0", + "lodash": "^4.17.21", + "node-fetch": "^2.6.7" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/airtable/node_modules/@types/node": { + "version": "14.18.58", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.58.tgz", + "integrity": "sha512-Y8ETZc8afYf6lQ/mVp096phIVsgD/GmDxtm3YaPcc+71jmi/J6zdwbwaUU4JvS56mq6aSfbpkcKhQ5WugrWFPw==" + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/axios": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.5.0.tgz", + "integrity": "sha512-D4DdjDo5CY50Qms0qGQTTw6Q44jl7zRwY7bthds06pUGfChBCTcQs+N743eFWGEd6pRTMd6A+I87aWyFV5wiZQ==", + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/browser-or-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/browser-or-node/-/browser-or-node-2.1.1.tgz", + "integrity": "sha512-8CVjaLJGuSKMVTxJ2DpBl5XnlNDiT4cQFeuCJJrvJmts9YrTZDizTX7PjC2s6W4x+MBGZeEY6dGMrF04/6Hgqg==" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "node_modules/radash": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/radash/-/radash-9.5.0.tgz", + "integrity": "sha512-t0s8BJlvrk8YPaOS8X0J2xzqAsBlXAUkDEjoBXwlzaXsXNCpBILjT9OvWlabLa2KB/r4XrhThdXjxMs7SiCyIw==", + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/type-fest": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz", + "integrity": "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/zod": { + "version": "3.22.2", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.2.tgz", + "integrity": "sha512-wvWkphh5WQsJbVk1tbx1l1Ly4yg+XecD+Mq280uBGt9wa5BKSWf4Mhp6GmrkPixhMxmabYY7RbzlwVP32pbGCg==", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } +} diff --git a/integrations/airtable/package.json b/integrations/airtable/package.json new file mode 100644 index 00000000000..dce1423c6af --- /dev/null +++ b/integrations/airtable/package.json @@ -0,0 +1,22 @@ +{ + "name": "airtable", + "scripts": { + "type:check": "tsc --noEmit" + }, + "keywords": [], + "private": true, + "author": "", + "license": "MIT", + "dependencies": { + "@botpress/client": "0.3.8", + "@botpress/sdk": "0.4.4", + "airtable": "^0.12.2", + "axios": "^1.5.0", + "zod": "^3.20.6" + }, + "devDependencies": { + "@types/node": "^18.11.17", + "ts-node": "^10.9.1", + "typescript": "^4.9.4" + } +} diff --git a/integrations/airtable/readme.md b/integrations/airtable/readme.md new file mode 100644 index 00000000000..f417e7bd56a --- /dev/null +++ b/integrations/airtable/readme.md @@ -0,0 +1,58 @@ +# Botpress Airtable Integration + +This integration allows you to connect your Botpress chatbot with Airtable, a popular cloud-based database and collaboration platform. With this integration, you can easily manage your Airtable bases, tables, and records directly from your chatbot. + +## Setup + +To set up the integration, you will need to provide your Airtable `accessToken`, `baseId`, and `endpointUrl` (Optional). Once the integration is set up, you can use the built-in actions to manage your Airtable data. + +For more detailed instructions on how to set up and use the Botpress Airtable integration, please refer to our documentation. + +### Prerequisites + +Before enabling the Botpress Airtable Integration, please ensure that you have the following: + +- A Botpress cloud account. +- `accessToken`, `baseId`, and `endpointUrl` (Optional) generated from Airtable. + +### Enable Integration + +To enable the Airtable integration in Botpress, follow these steps: + +1. Access your Botpress admin panel. +2. Navigate to the “Integrations” section. +3. Locate the Airtable integration and click on “Enable” or “Configure.” +4. Provide the required `accessToken`, `baseId`, and `endpointUrl` (Optional). +5. Save the configuration. + +### Scope and resources/access of the Personal Access Token + +Personal Access Token act as the user account granting access, with the following limitations: + +- Scope: What actions the token can perform. +- Resources/access: Which bases and workspaces the token can access. Tokens may be granted access to individual or all bases/workspaces. These can be listed using the list bases endpoint. + +For example, to update a record in a base via the API, the user who granted the token must have editor access to the base. In addition, the token must have both the correct scope (**data.records:write**) and the base added as a resource. + +For personal access tokens, scopes and resources/access are configured individually from **/create/tokens**. + +## Usage + +Once the integration is enabled, you can start using Airtable features from your Botpress chatbot. The integration offers several actions for interacting with Airtable, such as `getBaseTables`, `getTableRecords`, `createTable`, `updateTable`, `createRecord`, and `updateRecord`. These actions allow you to get tables and records from a base, create and update tables, and create and update records. + +For more details and examples, refer to the Botpress and Airtable documentation. + +## Limitations + +- Free Plan Limits: + - Records: Limited to **1,000 records per base**. + - API: Limited to **1,000 API calls per month**. + - Commenters: Limited to **50 commenters per workspace**. + - Sync and extensions: Available on the **Team plan and above**. To continue using Airtable with higher limits, you can upgrade to the Team plan. +- Rate limiting: Airtable employs a number of safeguards against bursts of incoming traffic to help maximize its stability. The API is limited to **5 requests per second per base**. If you exceed this rate, you will receive a **429 status code** and will need to wait **30 seconds** before subsequent requests will succeed. Airtable may change the enforced API rate limits or enforce additional types of limits in their sole discretion, including tiered based on pricing plan. Upon receiving a 429 status code, API integrations should back-off and wait before retrying the API request. The official JavaScript client has built-in back-off and retry logic. If you anticipate a higher read volume, it is recommended to use a caching proxy. + +## Contributing + +Contributions are welcome! Please submit issues and pull requests. + +Enjoy seamless helpdesk and customer support integration between Botpress and Airtable! diff --git a/integrations/airtable/src/actions/create-record.ts b/integrations/airtable/src/actions/create-record.ts new file mode 100644 index 00000000000..d929d716dc1 --- /dev/null +++ b/integrations/airtable/src/actions/create-record.ts @@ -0,0 +1,32 @@ +import type { Implementation } from '../misc/types' +import { createRecordInputSchema } from '../misc/custom-schemas' +import { getClient } from '../utils' + +export const createRecord: Implementation['actions']['createRecord'] = async ({ + ctx, + logger, + input, +}) => { + const validatedInput = createRecordInputSchema.parse(input) + const AirtableClient = getClient(ctx.configuration) + let record + try { + record = await AirtableClient.createRecord( + validatedInput.tableIdOrName, + JSON.parse(validatedInput.fields) + ) + record = { + _rawJson: record.fields, + id: record.id, + } + logger.forBot().info(`Successful - Create Record - ${record.id}`) + } catch (error) { + record = { + _rawJson: {}, + id: '', + } + logger.forBot().debug(`'Create Record' exception ${JSON.stringify(error)}`) + } + + return record +} diff --git a/integrations/airtable/src/actions/create-table.ts b/integrations/airtable/src/actions/create-table.ts new file mode 100644 index 00000000000..d2d30ebcfe8 --- /dev/null +++ b/integrations/airtable/src/actions/create-table.ts @@ -0,0 +1,28 @@ +import type { Implementation } from '../misc/types' +import { createTableInputSchema } from '../misc/custom-schemas' +import { fieldsStringToArray, getClient } from '../utils' + +export const createTable: Implementation['actions']['createTable'] = async ({ + ctx, + logger, + input, +}) => { + const validatedInput = createTableInputSchema.parse(input) + const AirtableClient = getClient(ctx.configuration) + let table + try { + table = await AirtableClient.createTable( + validatedInput.name, + fieldsStringToArray(validatedInput.fields), + validatedInput.description + ) + logger + .forBot() + .info(`Successful - Create Table - ${table.id} - ${table.name}`) + } catch (error) { + table = {} + logger.forBot().debug(`'Create Table' exception ${JSON.stringify(error)}`) + } + + return table +} diff --git a/integrations/airtable/src/actions/get-base-tables.ts b/integrations/airtable/src/actions/get-base-tables.ts new file mode 100644 index 00000000000..444a4f1cc18 --- /dev/null +++ b/integrations/airtable/src/actions/get-base-tables.ts @@ -0,0 +1,20 @@ +import type { Implementation } from '../misc/types' +import { getClient } from '../utils' + +export const getBaseTables: Implementation['actions']['getBaseTables'] = + async ({ ctx, logger }) => { + const AirtableClient = getClient(ctx.configuration) + let tables + try { + tables = await AirtableClient.getBaseTables() + logger.forBot().info(`Successful - Get Base Tables`) + } catch (error) { + logger + .forBot() + .debug(`'Get Base Tables' exception ${JSON.stringify(error)}`) + } + + return { + tables, + } + } diff --git a/integrations/airtable/src/actions/get-table-records.ts b/integrations/airtable/src/actions/get-table-records.ts new file mode 100644 index 00000000000..50d30a4f605 --- /dev/null +++ b/integrations/airtable/src/actions/get-table-records.ts @@ -0,0 +1,35 @@ +import type { Implementation } from '../misc/types' +import { + getTableRecordsInputSchema, + getTableRecordsOutputSchema, +} from '../misc/custom-schemas' +import { getClient } from '../utils' + +export const getTableRecords: Implementation['actions']['getTableRecords'] = + async ({ ctx, logger, input }) => { + const validatedInput = getTableRecordsInputSchema.parse(input) + const AirtableClient = getClient(ctx.configuration) + let records + try { + records = await AirtableClient.getTableRecords( + validatedInput.tableIdOrName + ) + records = records.map((record) => { + return { + _rawJson: record.fields, + id: record.id, + } + }) + logger + .forBot() + .info( + `Successful - Get Table Records - ${validatedInput.tableIdOrName}` + ) + } catch (error) { + logger + .forBot() + .debug(`'Get Table Records' exception ${JSON.stringify(error)}`) + } + + return getTableRecordsOutputSchema.parse({ records }) + } diff --git a/integrations/airtable/src/actions/index.ts b/integrations/airtable/src/actions/index.ts new file mode 100644 index 00000000000..1273397b128 --- /dev/null +++ b/integrations/airtable/src/actions/index.ts @@ -0,0 +1,15 @@ +import { getBaseTables } from './get-base-tables' +import { getTableRecords } from './get-table-records' +import { createTable } from './create-table' +import { updateTable } from './update-table' +import { createRecord } from './create-record' +import { updateRecord } from './update-record' + +export default { + getBaseTables, + getTableRecords, + createTable, + updateTable, + createRecord, + updateRecord, +} diff --git a/integrations/airtable/src/actions/update-record.ts b/integrations/airtable/src/actions/update-record.ts new file mode 100644 index 00000000000..fad2deb29c3 --- /dev/null +++ b/integrations/airtable/src/actions/update-record.ts @@ -0,0 +1,33 @@ +import type { Implementation } from '../misc/types' +import { updateRecordInputSchema } from '../misc/custom-schemas' +import { getClient } from '../utils' + +export const updateRecord: Implementation['actions']['updateRecord'] = async ({ + ctx, + logger, + input, +}) => { + const validatedInput = updateRecordInputSchema.parse(input) + const AirtableClient = getClient(ctx.configuration) + let record + try { + record = await AirtableClient.updateRecord( + validatedInput.tableIdOrName, + validatedInput.recordId, + JSON.parse(validatedInput.fields) + ) + record = { + _rawJson: record.fields, + id: record.id, + } + logger.forBot().info(`Successful - Update Record - ${record.id}`) + } catch (error) { + record = { + _rawJson: {}, + id: '', + } + logger.forBot().debug(`'Update Record' exception ${JSON.stringify(error)}`) + } + + return record +} diff --git a/integrations/airtable/src/actions/update-table.ts b/integrations/airtable/src/actions/update-table.ts new file mode 100644 index 00000000000..03069fe7a69 --- /dev/null +++ b/integrations/airtable/src/actions/update-table.ts @@ -0,0 +1,28 @@ +import type { Implementation } from '../misc/types' +import { updateTableInputSchema } from '../misc/custom-schemas' +import { getClient } from '../utils' + +export const updateTable: Implementation['actions']['updateTable'] = async ({ + ctx, + logger, + input, +}) => { + const validatedInput = updateTableInputSchema.parse(input) + const AirtableClient = getClient(ctx.configuration) + let table + try { + table = await AirtableClient.updateTable( + validatedInput.tableIdOrName, + validatedInput.name, + validatedInput.description + ) + logger + .forBot() + .info(`Successful - Update Table - ${table.id} - ${table.name}`) + } catch (error) { + table = {} + logger.forBot().debug(`'Update Table' exception ${JSON.stringify(error)}`) + } + + return table +} diff --git a/integrations/airtable/src/client/index.ts b/integrations/airtable/src/client/index.ts new file mode 100644 index 00000000000..5a9dbfca767 --- /dev/null +++ b/integrations/airtable/src/client/index.ts @@ -0,0 +1,70 @@ +import Airtable from 'airtable' +import axios, { AxiosInstance } from 'axios' +import { tableFields } from 'src/misc/custom-types' + +export class AirtableApi { + private base: Airtable.Base + private axiosClient: AxiosInstance + private baseId: string + + constructor(apiKey: string, baseId: string, endpointUrl?: string) { + this.baseId = baseId + this.base = new Airtable({ apiKey, endpointUrl }).base(baseId) + this.axiosClient = axios.create({ + baseURL: endpointUrl || 'https://api.airtable.com/v0/', + headers: { Authorization: `Bearer ${apiKey}` }, + }) + } + + async getTableRecords(tableIdOrName: string) { + const records = await this.base(tableIdOrName).select().all() + return records + } + + async createRecord(tableIdOrName: string, fields: object) { + const record = await this.base(tableIdOrName).create(fields) + return record + } + + async updateRecord(tableIdOrName: string, recordId: string, fields: object) { + const record = await this.base(tableIdOrName).update(recordId, fields) + return record + } + + async getBaseTables() { + const response = await this.axiosClient.get( + `/meta/bases/${this.baseId}/tables` + ) + return response.data.tables + } + + async createTable(name: string, fields: tableFields, description?: string) { + const descriptionLimit = 20000 + const validDescription = description?.slice(0, descriptionLimit) + const payload = { + name, + description: validDescription, + fields, + } + const response = await this.axiosClient.post( + `/meta/bases/${this.baseId}/tables`, + payload + ) + return response.data + } + + async updateTable( + tableIdOrName: string, + name?: string, + description?: string + ) { + const response = await this.axiosClient.patch( + `/meta/bases/${this.baseId}/tables/${tableIdOrName}`, + { + name, + description, + } + ) + return response.data + } +} diff --git a/integrations/airtable/src/definitions/actions.ts b/integrations/airtable/src/definitions/actions.ts new file mode 100644 index 00000000000..da8d97d84f3 --- /dev/null +++ b/integrations/airtable/src/definitions/actions.ts @@ -0,0 +1,98 @@ +import { + createRecordInputSchema, + createRecordOutputSchema, + createTableInputSchema, + createTableOutputSchema, + getBaseTablesInputSchema, + getBaseTablesOutputSchema, + getTableRecordsInputSchema, + getTableRecordsOutputSchema, + updateRecordInputSchema, + updateRecordOutputSchema, + updateTableInputSchema, + updateTableOutputSchema, +} from '../misc/custom-schemas' + +import { + createRecordUi, + createTableUi, + getBaseTablesUi, + getTableRecordsUi, + updateRecordUi, + updateTableUi, +} from '../misc/custom-uis' + +const getBaseTables = { + title: 'Get Tables of the Base', + input: { + schema: getBaseTablesInputSchema, + ui: getBaseTablesUi, + }, + output: { + schema: getBaseTablesOutputSchema, + }, +} + +const getTableRecords = { + title: 'Get Records of the Table', + input: { + schema: getTableRecordsInputSchema, + ui: getTableRecordsUi, + }, + output: { + schema: getTableRecordsOutputSchema, + }, +} + +const createTable = { + title: 'Create Table', + input: { + schema: createTableInputSchema, + ui: createTableUi, + }, + output: { + schema: createTableOutputSchema, + }, +} + +const updateTable = { + title: 'Update Table', + input: { + schema: updateTableInputSchema, + ui: updateTableUi, + }, + output: { + schema: updateTableOutputSchema, + }, +} + +const createRecord = { + title: 'Create Record', + input: { + schema: createRecordInputSchema, + ui: createRecordUi, + }, + output: { + schema: createRecordOutputSchema, + }, +} + +const updateRecord = { + title: 'Update Record', + input: { + schema: updateRecordInputSchema, + ui: updateRecordUi, + }, + output: { + schema: updateRecordOutputSchema, + }, +} + +export const actions = { + getBaseTables, + getTableRecords, + createTable, + updateTable, + createRecord, + updateRecord, +} diff --git a/integrations/airtable/src/definitions/channels.ts b/integrations/airtable/src/definitions/channels.ts new file mode 100644 index 00000000000..7503e93c677 --- /dev/null +++ b/integrations/airtable/src/definitions/channels.ts @@ -0,0 +1,7 @@ +import { IntegrationDefinitionProps, messages } from '@botpress/sdk' + +export const channels = { + channel: { + messages: { ...messages.defaults }, + }, +} satisfies IntegrationDefinitionProps['channels'] diff --git a/integrations/airtable/src/definitions/index.ts b/integrations/airtable/src/definitions/index.ts new file mode 100644 index 00000000000..d51189c0297 --- /dev/null +++ b/integrations/airtable/src/definitions/index.ts @@ -0,0 +1,26 @@ +import type { IntegrationDefinitionProps } from '@botpress/sdk' +import z from 'zod' + +import { actions } from './actions' +import { channels } from './channels' + +export { actions } +export { channels } + +export const configuration = { + schema: z.object({ + accessToken: z.string().describe('Personal Access Token'), + baseId: z.string().describe('Base ID'), + endpointUrl: z + .string() + .optional() + .default('https://api.airtable.com/v0/') + .describe('API endpoint to hit (Default: https://api.airtable.com/v0/)'), + }), +} + +export const states: IntegrationDefinitionProps['states'] = {} + +export const user = { + tags: {}, +} diff --git a/integrations/airtable/src/index.ts b/integrations/airtable/src/index.ts new file mode 100644 index 00000000000..8b77391a01b --- /dev/null +++ b/integrations/airtable/src/index.ts @@ -0,0 +1,14 @@ +import * as botpress from '.botpress' + +import actions from './actions' +import { register, unregister, channels, handler } from './setup' + +console.info('starting integration') + +export default new botpress.Integration({ + register, + unregister, + actions, + channels, + handler, +}) diff --git a/integrations/airtable/src/misc/custom-schemas.ts b/integrations/airtable/src/misc/custom-schemas.ts new file mode 100644 index 00000000000..46e2df3415a --- /dev/null +++ b/integrations/airtable/src/misc/custom-schemas.ts @@ -0,0 +1,89 @@ +import z from 'zod' + +import { tableSchema, recordSchema } from './sub-schemas' + +export const getBaseTablesInputSchema = z.object({}) + +export const getBaseTablesOutputSchema = z + .object({ + tables: z.array(tableSchema), + }) + .passthrough() + +export const getTableRecordsInputSchema = z.object({ + tableIdOrName: z + .string() + .describe( + 'The ID or Name of the table (e.g. tblFnqcm4zLVKn85A or articles)' + ), +}) + +export const getTableRecordsOutputSchema = z + .object({ + records: z.array(recordSchema), + }) + .passthrough() + +export const createTableInputSchema = z.object({ + name: z.string().describe('Name of the Table (e.g. MyTable)'), + fields: z + .string() + .describe( + 'The Table\'s fields, separated by commas. Each field should be in the format "type_name" (e.g. "phoneNumber_Customer Phone, singleLineText_Address").' + ), + description: z + .string() + .optional() + .describe('Description of the Table (e.g. This is my table) (Optional)'), +}) + +export const createTableOutputSchema = tableSchema.passthrough() + +export const updateTableInputSchema = z.object({ + tableIdOrName: z + .string() + .describe( + 'The ID or Name of the table (e.g. tblFnqcm4zLVKn85A or articles)' + ), + name: z + .string() + .optional() + .describe('Name of the Table (e.g. MyTable) (Optional)'), + description: z + .string() + .optional() + .describe('Description of the Table (e.g. This is my table) (Optional)'), +}) + +export const updateTableOutputSchema = tableSchema.passthrough() + +export const createRecordInputSchema = z.object({ + tableIdOrName: z + .string() + .describe( + 'The ID or Name of the table (e.g. tblFnqcm4zLVKn85A or articles)' + ), + fields: z + .string() + .describe( + 'The fields and their values for the new record, in a JSON format (e.g. {"Name":"John Doe","City":"In the moon","Verify":true})' + ), +}) + +export const createRecordOutputSchema = recordSchema.passthrough() + +export const updateRecordInputSchema = z.object({ + tableIdOrName: z + .string() + .describe( + 'The ID or Name of the table (e.g. tblFnqcm4zLVKn85A or articles)' + ), + recordId: z.string().describe('The ID of the Record to be updated'), + fields: z + .string() + .describe( + 'The fields and their values for the record to be updated, in a JSON format (e.g. {"Name":"John Doe","Verify":true})' + ), +}) + +export const updateRecordOutputSchema = recordSchema.passthrough() diff --git a/integrations/airtable/src/misc/custom-types.ts b/integrations/airtable/src/misc/custom-types.ts new file mode 100644 index 00000000000..eaa142d39a4 --- /dev/null +++ b/integrations/airtable/src/misc/custom-types.ts @@ -0,0 +1,5 @@ +import {} from './sub-types' + +type tableFields = Array<{ name: string; type: string }> + +export { tableFields } diff --git a/integrations/airtable/src/misc/custom-uis.ts b/integrations/airtable/src/misc/custom-uis.ts new file mode 100644 index 00000000000..85a06594e72 --- /dev/null +++ b/integrations/airtable/src/misc/custom-uis.ts @@ -0,0 +1,53 @@ +export const getBaseTablesUi = {} + +export const getTableRecordsUi = { + tableIdOrName: { + title: 'The ID or Name of the table (e.g. tblFnqcm4zLVKn85A or articles)', + }, +} + +export const createTableUi = { + name: { title: 'Name of the Table (e.g. MyTable)' }, + fields: { + title: + 'The Table\'s fields, separated by commas. Each field should be in the format "type_name" (e.g. "phoneNumber_Customer Phone, singleLineText_Address").', + }, + description: { + title: 'Description of the Table (e.g. This is my table) (Optional)', + }, +} + +export const updateTableUi = { + tableIdOrName: { + title: 'The ID or Name of the table (e.g. tblFnqcm4zLVKn85A or articles)', + }, + name: { + title: 'Name of the Table (e.g. MyTable) (Optional)', + }, + description: { + title: 'Description of the Table (e.g. This is my table) (Optional)', + }, +} + +export const createRecordUi = { + tableIdOrName: { + title: 'The ID or Name of the table (e.g. tblFnqcm4zLVKn85A or articles)', + }, + fields: { + title: + 'The fields and their values for the new record, in a JSON format (e.g. {"Name":"John Doe","City":"In the moon","Verify":true})', + }, +} + +export const updateRecordUi = { + tableIdOrName: { + title: 'The ID or Name of the table (e.g. tblFnqcm4zLVKn85A or articles)', + }, + recordId: { + title: 'The ID of the Record to be updated', + }, + fields: { + title: + 'The fields and their values for the new record, in a JSON format (e.g. {"Name":"John Doe","Verify":true})', + }, +} diff --git a/integrations/airtable/src/misc/sub-schemas/index.ts b/integrations/airtable/src/misc/sub-schemas/index.ts new file mode 100644 index 00000000000..321544f2e2d --- /dev/null +++ b/integrations/airtable/src/misc/sub-schemas/index.ts @@ -0,0 +1,25 @@ +import z from 'zod' + +const fieldSchema = z + .object({ name: z.string(), type: z.string() }) + .passthrough() + +const viewSchema = z + .object({ id: z.string(), name: z.string(), type: z.string() }) + .passthrough() + +const tableSchema = z.object({ + description: z.string().optional(), + fields: z.array(fieldSchema), + id: z.string(), + name: z.string(), + primaryFieldId: z.string(), + views: z.array(viewSchema), +}) + +const recordSchema = z.object({ + _rawJson: z.object({}).passthrough(), + id: z.string(), +}) + +export { tableSchema, recordSchema } diff --git a/integrations/airtable/src/misc/sub-types/index.ts b/integrations/airtable/src/misc/sub-types/index.ts new file mode 100644 index 00000000000..336ce12bb91 --- /dev/null +++ b/integrations/airtable/src/misc/sub-types/index.ts @@ -0,0 +1 @@ +export {} diff --git a/integrations/airtable/src/misc/types.ts b/integrations/airtable/src/misc/types.ts new file mode 100644 index 00000000000..fc2ccc80b71 --- /dev/null +++ b/integrations/airtable/src/misc/types.ts @@ -0,0 +1,14 @@ +import type { IntegrationContext } from '@botpress/sdk' +import type * as botpress from '.botpress' +import type { Configuration } from '.botpress/implementation/configuration' + +export type Config = botpress.configuration.Configuration +export type Implementation = ConstructorParameters< + typeof botpress.Integration +>[0] +export type IntegrationCtx = IntegrationContext + +export type RegisterFunction = Implementation['register'] +export type UnregisterFunction = Implementation['unregister'] +export type Channels = Implementation['channels'] +export type Handler = Implementation['handler'] diff --git a/integrations/airtable/src/setup/channels.ts b/integrations/airtable/src/setup/channels.ts new file mode 100644 index 00000000000..47c29f52ab3 --- /dev/null +++ b/integrations/airtable/src/setup/channels.ts @@ -0,0 +1,47 @@ +import type { Channels } from '../misc/types' + +class NotImplementedError extends Error { + constructor() { + super('Not implemented') + } +} + +export const channels: Channels = { + channel: { + messages: { + text: async () => { + throw new NotImplementedError() + }, + image: async () => { + throw new NotImplementedError() + }, + markdown: async () => { + throw new NotImplementedError() + }, + audio: async () => { + throw new NotImplementedError() + }, + video: async () => { + throw new NotImplementedError() + }, + file: async () => { + throw new NotImplementedError() + }, + location: async () => { + throw new NotImplementedError() + }, + carousel: async () => { + throw new NotImplementedError() + }, + card: async () => { + throw new NotImplementedError() + }, + choice: async () => { + throw new NotImplementedError() + }, + dropdown: async () => { + throw new NotImplementedError() + }, + }, + }, +} diff --git a/integrations/airtable/src/setup/handler.ts b/integrations/airtable/src/setup/handler.ts new file mode 100644 index 00000000000..01d0e2aabfc --- /dev/null +++ b/integrations/airtable/src/setup/handler.ts @@ -0,0 +1,11 @@ +import type { Handler } from '../misc/types' + +class NotImplementedError extends Error { + constructor() { + super('Not implemented') + } +} + +export const handler: Handler = async () => { + throw new NotImplementedError() +} diff --git a/integrations/airtable/src/setup/index.ts b/integrations/airtable/src/setup/index.ts new file mode 100644 index 00000000000..942ecedd0c6 --- /dev/null +++ b/integrations/airtable/src/setup/index.ts @@ -0,0 +1,4 @@ +export { register } from './register' +export { unregister } from './unregister' +export { channels } from './channels' +export { handler } from './handler' diff --git a/integrations/airtable/src/setup/register.ts b/integrations/airtable/src/setup/register.ts new file mode 100644 index 00000000000..221ca7a73b6 --- /dev/null +++ b/integrations/airtable/src/setup/register.ts @@ -0,0 +1,3 @@ +import type { RegisterFunction } from '../misc/types' + +export const register: RegisterFunction = async () => {} diff --git a/integrations/airtable/src/setup/unregister.ts b/integrations/airtable/src/setup/unregister.ts new file mode 100644 index 00000000000..48967dfd5e4 --- /dev/null +++ b/integrations/airtable/src/setup/unregister.ts @@ -0,0 +1,3 @@ +import type { UnregisterFunction } from '../misc/types' + +export const unregister: UnregisterFunction = async () => {} diff --git a/integrations/airtable/src/utils/index.ts b/integrations/airtable/src/utils/index.ts new file mode 100644 index 00000000000..2eae4ff766c --- /dev/null +++ b/integrations/airtable/src/utils/index.ts @@ -0,0 +1,25 @@ +import { Config } from '../misc/types' +import { tableFields } from 'src/misc/custom-types' +import { AirtableApi } from '../client' + +export function getClient(config: Config) { + return new AirtableApi(config.accessToken, config.baseId, config.endpointUrl) +} + +export function fieldsStringToArray(fieldsString: string) { + let fields: tableFields + try { + fields = fieldsString.split(',').map((fieldString) => { + const [type, name] = fieldString.trim().split('_') + if (type === '' || type === undefined) throw new Error('Type is Required') + if (name === '' || name === undefined) throw new Error('Name is Required') + return { + type: type, + name: name, + } + }) + } catch (error) { + fields = [] + } + return fields +} diff --git a/integrations/airtable/tsconfig.json b/integrations/airtable/tsconfig.json new file mode 100644 index 00000000000..0f0a90a180d --- /dev/null +++ b/integrations/airtable/tsconfig.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "lib": ["es2022"], + "module": "commonjs", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "moduleResolution": "node", + "allowUnusedLabels": false, + "allowUnreachableCode": false, + "noFallthroughCasesInSwitch": true, + "noImplicitOverride": true, + "noImplicitReturns": true, + "noUncheckedIndexedAccess": true, + "noUnusedParameters": true, + "target": "es2017", + "baseUrl": ".", + "outDir": "dist", + "checkJs": false, + "incremental": true, + "exactOptionalPropertyTypes": false, + "resolveJsonModule": true, + "noPropertyAccessFromIndexSignature": false, + "noUnusedLocals": false + }, + "include": [".botpress/**/*", "src/**/*", "./*.ts", "./*.json"] +} From 00db1df99a3c6c27695350cda72fb65cacd6697e Mon Sep 17 00:00:00 2001 From: Charles Catta Date: Tue, 9 Jan 2024 15:54:29 -0500 Subject: [PATCH 02/10] Initial commit --- integrations/airtable/package-lock.json | 458 ------------------------ integrations/airtable/package.json | 6 +- integrations/airtable/src/index.ts | 5 +- pnpm-lock.yaml | 75 +++- 4 files changed, 76 insertions(+), 468 deletions(-) delete mode 100644 integrations/airtable/package-lock.json diff --git a/integrations/airtable/package-lock.json b/integrations/airtable/package-lock.json deleted file mode 100644 index f581ea18d5b..00000000000 --- a/integrations/airtable/package-lock.json +++ /dev/null @@ -1,458 +0,0 @@ -{ - "name": "airtable", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "airtable", - "license": "MIT", - "dependencies": { - "@botpress/client": "0.3.8", - "@botpress/sdk": "0.4.4", - "airtable": "^0.12.2", - "axios": "^1.5.0", - "zod": "^3.20.6" - }, - "devDependencies": { - "@types/node": "^18.11.17", - "ts-node": "^10.9.1", - "typescript": "^4.9.4" - } - }, - "node_modules/@botpress/client": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/@botpress/client/-/client-0.3.8.tgz", - "integrity": "sha512-y31l2AkM1HzVYNhA2NaHY7UnZ7DoUJudMIMssEBUmU6CcAH2whrENeLqtpRyv+mc3AOB/kpOf1N14RwCWpz5Bg==", - "dependencies": { - "axios": "1.2.5", - "browser-or-node": "^2.1.1", - "type-fest": "^3.4.0" - } - }, - "node_modules/@botpress/client/node_modules/axios": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.2.5.tgz", - "integrity": "sha512-9pU/8mmjSSOb4CXVsvGIevN+MlO/t9OWtKadTaLuN85Gge3HGorUckgp8A/2FH4V4hJ7JuQ3LIeI7KAV9ITZrQ==", - "dependencies": { - "follow-redirects": "^1.15.0", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" - } - }, - "node_modules/@botpress/sdk": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/@botpress/sdk/-/sdk-0.4.4.tgz", - "integrity": "sha512-B57YNwDgxk5vJBuGdMm/vO0STBGuZPipWxrEDptylXuLTaa8xR0SjTa1EKfVZX5oJR4vb524DeFrNC9Vh9+oDA==", - "dependencies": { - "@botpress/client": "0.3.8", - "axios": "0.27.2", - "radash": "^9.5.0", - "zod": "^3.20.6" - } - }, - "node_modules/@botpress/sdk/node_modules/axios": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", - "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", - "dependencies": { - "follow-redirects": "^1.14.9", - "form-data": "^4.0.0" - } - }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", - "dev": true - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true - }, - "node_modules/@types/node": { - "version": "18.17.14", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.17.14.tgz", - "integrity": "sha512-ZE/5aB73CyGqgQULkLG87N9GnyGe5TcQjv34pwS8tfBs1IkCh0ASM69mydb2znqd6v0eX+9Ytvk6oQRqu8T1Vw==", - "dev": true - }, - "node_modules/abort-controller": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "dependencies": { - "event-target-shim": "^5.0.0" - }, - "engines": { - "node": ">=6.5" - } - }, - "node_modules/abortcontroller-polyfill": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.5.tgz", - "integrity": "sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ==" - }, - "node_modules/acorn": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", - "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/airtable": { - "version": "0.12.2", - "resolved": "https://registry.npmjs.org/airtable/-/airtable-0.12.2.tgz", - "integrity": "sha512-HS3VytUBTKj8A0vPl7DDr5p/w3IOGv6RXL0fv7eczOWAtj9Xe8ri4TAiZRXoOyo+Z/COADCj+oARFenbxhmkIg==", - "dependencies": { - "@types/node": ">=8.0.0 <15", - "abort-controller": "^3.0.0", - "abortcontroller-polyfill": "^1.4.0", - "lodash": "^4.17.21", - "node-fetch": "^2.6.7" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/airtable/node_modules/@types/node": { - "version": "14.18.58", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.58.tgz", - "integrity": "sha512-Y8ETZc8afYf6lQ/mVp096phIVsgD/GmDxtm3YaPcc+71jmi/J6zdwbwaUU4JvS56mq6aSfbpkcKhQ5WugrWFPw==" - }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" - }, - "node_modules/axios": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.5.0.tgz", - "integrity": "sha512-D4DdjDo5CY50Qms0qGQTTw6Q44jl7zRwY7bthds06pUGfChBCTcQs+N743eFWGEd6pRTMd6A+I87aWyFV5wiZQ==", - "dependencies": { - "follow-redirects": "^1.15.0", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" - } - }, - "node_modules/browser-or-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/browser-or-node/-/browser-or-node-2.1.1.tgz", - "integrity": "sha512-8CVjaLJGuSKMVTxJ2DpBl5XnlNDiT4cQFeuCJJrvJmts9YrTZDizTX7PjC2s6W4x+MBGZeEY6dGMrF04/6Hgqg==" - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/event-target-shim": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", - "engines": { - "node": ">=6" - } - }, - "node_modules/follow-redirects": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" - }, - "node_modules/radash": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/radash/-/radash-9.5.0.tgz", - "integrity": "sha512-t0s8BJlvrk8YPaOS8X0J2xzqAsBlXAUkDEjoBXwlzaXsXNCpBILjT9OvWlabLa2KB/r4XrhThdXjxMs7SiCyIw==", - "engines": { - "node": ">=14.18.0" - } - }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, - "node_modules/ts-node": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", - "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", - "dev": true, - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/type-fest": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz", - "integrity": "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==", - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true - }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/zod": { - "version": "3.22.2", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.2.tgz", - "integrity": "sha512-wvWkphh5WQsJbVk1tbx1l1Ly4yg+XecD+Mq280uBGt9wa5BKSWf4Mhp6GmrkPixhMxmabYY7RbzlwVP32pbGCg==", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - } - } -} diff --git a/integrations/airtable/package.json b/integrations/airtable/package.json index dce1423c6af..526f94dc07a 100644 --- a/integrations/airtable/package.json +++ b/integrations/airtable/package.json @@ -8,11 +8,11 @@ "author": "", "license": "MIT", "dependencies": { - "@botpress/client": "0.3.8", - "@botpress/sdk": "0.4.4", + "@botpress/client": "workspace:*", + "@botpress/sdk": "workspace:*", "airtable": "^0.12.2", "axios": "^1.5.0", - "zod": "^3.20.6" + "zod": "3.20.6" }, "devDependencies": { "@types/node": "^18.11.17", diff --git a/integrations/airtable/src/index.ts b/integrations/airtable/src/index.ts index 8b77391a01b..d94e88179de 100644 --- a/integrations/airtable/src/index.ts +++ b/integrations/airtable/src/index.ts @@ -1,9 +1,6 @@ -import * as botpress from '.botpress' - import actions from './actions' import { register, unregister, channels, handler } from './setup' - -console.info('starting integration') +import * as botpress from '.botpress' export default new botpress.Integration({ register, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 936e81c66ad..04938a36809 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -141,6 +141,34 @@ importers: specifier: ^4.9.4 version: 4.9.5 + integrations/airtable: + dependencies: + '@botpress/client': + specifier: workspace:* + version: link:../../packages/client + '@botpress/sdk': + specifier: workspace:* + version: link:../../packages/sdk + airtable: + specifier: ^0.12.2 + version: 0.12.2 + axios: + specifier: ^1.5.0 + version: 1.6.5 + zod: + specifier: 3.20.6 + version: 3.20.6 + devDependencies: + '@types/node': + specifier: ^18.11.17 + version: 18.16.16 + ts-node: + specifier: ^10.9.1 + version: 10.9.1(@types/node@18.16.16)(typescript@4.9.5) + typescript: + specifier: ^4.9.4 + version: 4.9.5 + integrations/asana: dependencies: '@botpress/sdk': @@ -1930,7 +1958,7 @@ packages: dependencies: '@anatine/zod-openapi': 1.14.0(openapi3-ts@2.0.2)(zod@3.21.4) '@readme/openapi-parser': 2.5.0(openapi-types@12.1.3) - axios: 1.4.0 + axios: 1.6.5 chalk: 4.1.2 decompress: 4.2.1 execa: 6.1.0 @@ -3899,6 +3927,10 @@ packages: event-target-shim: 5.0.1 dev: false + /abortcontroller-polyfill@1.7.5: + resolution: {integrity: sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ==} + dev: false + /accepts@1.3.8: resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} engines: {node: '>= 0.6'} @@ -3961,6 +3993,19 @@ packages: indent-string: 4.0.0 dev: false + /airtable@0.12.2: + resolution: {integrity: sha512-HS3VytUBTKj8A0vPl7DDr5p/w3IOGv6RXL0fv7eczOWAtj9Xe8ri4TAiZRXoOyo+Z/COADCj+oARFenbxhmkIg==} + engines: {node: '>=8.0.0'} + dependencies: + '@types/node': 10.17.60 + abort-controller: 3.0.0 + abortcontroller-polyfill: 1.7.5 + lodash: 4.17.21 + node-fetch: 2.6.11 + transitivePeerDependencies: + - encoding + dev: false + /ajv-draft-04@1.0.0(ajv@8.12.0): resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==} peerDependencies: @@ -4240,6 +4285,16 @@ packages: proxy-from-env: 1.1.0 transitivePeerDependencies: - debug + dev: false + + /axios@1.6.5: + resolution: {integrity: sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg==} + dependencies: + follow-redirects: 1.15.4 + form-data: 4.0.0 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug /babel-jest@29.5.0(@babel/core@7.22.5): resolution: {integrity: sha512-mA4eCDh5mSo2EcA9xQjVTpmbbNk32Zb3Q3QFQsNhaK56Q+yoXowzFodLux30HRgyOho5rsQ6B0P9QpMkvvnJ0Q==} @@ -6222,6 +6277,16 @@ packages: optional: true dependencies: debug: 4.3.4 + dev: false + + /follow-redirects@1.15.4: + resolution: {integrity: sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true /for-each@0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} @@ -9732,7 +9797,7 @@ packages: /trello.js@1.2.6: resolution: {integrity: sha512-ds7prbYHRp1SeNsDHTbLLfN1dOTBfg1AZ+/hnov25aglveFTNK7q/1KSRC533Fcyep7PdngjpWUKpjlGlkFl/Q==} dependencies: - axios: 1.4.0 + axios: 1.6.5 form-data: 4.0.0 tslib: 2.6.2 transitivePeerDependencies: @@ -9815,7 +9880,7 @@ packages: '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 '@types/node': 18.16.0 - acorn: 8.8.2 + acorn: 8.10.0 acorn-walk: 8.2.0 arg: 4.1.3 create-require: 1.1.1 @@ -10520,5 +10585,9 @@ packages: resolution: {integrity: sha512-UzIwO92D0dSFwIRyyqAfRXICITLjF0IP8tRbEK/un7adirMssWZx8xF/1hZNE7t61knWZ+lhEuUvxlu2MO8qqA==} dev: false + /zod@3.20.6: + resolution: {integrity: sha512-oyu0m54SGCtzh6EClBVqDDlAYRz4jrVtKwQ7ZnsEmMI9HnzuZFj8QFwAY1M5uniIYACdGvv0PBWPF2kO0aNofA==} + dev: false + /zod@3.21.4: resolution: {integrity: sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==} From 0a66de92d82b82901c9dbef78ebcb84d59487122 Mon Sep 17 00:00:00 2001 From: Charles Catta Date: Tue, 9 Jan 2024 17:01:52 -0500 Subject: [PATCH 03/10] Clean styling, remove get tables --- integrations/airtable/package.json | 2 +- .../airtable/src/actions/create-record.ts | 2 +- .../airtable/src/actions/create-table.ts | 2 +- .../airtable/src/actions/get-base-tables.ts | 20 ------ .../airtable/src/actions/get-table-records.ts | 2 +- integrations/airtable/src/actions/index.ts | 8 +-- .../airtable/src/actions/update-record.ts | 2 +- .../airtable/src/actions/update-table.ts | 2 +- integrations/airtable/src/client/index.ts | 17 ++--- .../airtable/src/definitions/actions.ts | 15 ---- .../airtable/src/misc/custom-schemas.ts | 9 --- .../airtable/src/misc/custom-types.ts | 5 -- .../airtable/src/misc/sub-types/index.ts | 1 - integrations/airtable/src/misc/types.ts | 1 + integrations/airtable/src/utils/index.ts | 11 +-- pnpm-lock.yaml | 69 +++++++++++++------ 16 files changed, 72 insertions(+), 96 deletions(-) delete mode 100644 integrations/airtable/src/actions/get-base-tables.ts delete mode 100644 integrations/airtable/src/misc/custom-types.ts delete mode 100644 integrations/airtable/src/misc/sub-types/index.ts diff --git a/integrations/airtable/package.json b/integrations/airtable/package.json index 526f94dc07a..8364db56103 100644 --- a/integrations/airtable/package.json +++ b/integrations/airtable/package.json @@ -1,5 +1,5 @@ { - "name": "airtable", + "name": "airtable2", "scripts": { "type:check": "tsc --noEmit" }, diff --git a/integrations/airtable/src/actions/create-record.ts b/integrations/airtable/src/actions/create-record.ts index d929d716dc1..9c89724e132 100644 --- a/integrations/airtable/src/actions/create-record.ts +++ b/integrations/airtable/src/actions/create-record.ts @@ -1,5 +1,5 @@ -import type { Implementation } from '../misc/types' import { createRecordInputSchema } from '../misc/custom-schemas' +import type { Implementation } from '../misc/types' import { getClient } from '../utils' export const createRecord: Implementation['actions']['createRecord'] = async ({ diff --git a/integrations/airtable/src/actions/create-table.ts b/integrations/airtable/src/actions/create-table.ts index d2d30ebcfe8..e4a9a14d4eb 100644 --- a/integrations/airtable/src/actions/create-table.ts +++ b/integrations/airtable/src/actions/create-table.ts @@ -1,5 +1,5 @@ -import type { Implementation } from '../misc/types' import { createTableInputSchema } from '../misc/custom-schemas' +import type { Implementation } from '../misc/types' import { fieldsStringToArray, getClient } from '../utils' export const createTable: Implementation['actions']['createTable'] = async ({ diff --git a/integrations/airtable/src/actions/get-base-tables.ts b/integrations/airtable/src/actions/get-base-tables.ts deleted file mode 100644 index 444a4f1cc18..00000000000 --- a/integrations/airtable/src/actions/get-base-tables.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { Implementation } from '../misc/types' -import { getClient } from '../utils' - -export const getBaseTables: Implementation['actions']['getBaseTables'] = - async ({ ctx, logger }) => { - const AirtableClient = getClient(ctx.configuration) - let tables - try { - tables = await AirtableClient.getBaseTables() - logger.forBot().info(`Successful - Get Base Tables`) - } catch (error) { - logger - .forBot() - .debug(`'Get Base Tables' exception ${JSON.stringify(error)}`) - } - - return { - tables, - } - } diff --git a/integrations/airtable/src/actions/get-table-records.ts b/integrations/airtable/src/actions/get-table-records.ts index 50d30a4f605..534afcdff9c 100644 --- a/integrations/airtable/src/actions/get-table-records.ts +++ b/integrations/airtable/src/actions/get-table-records.ts @@ -1,8 +1,8 @@ -import type { Implementation } from '../misc/types' import { getTableRecordsInputSchema, getTableRecordsOutputSchema, } from '../misc/custom-schemas' +import type { Implementation } from '../misc/types' import { getClient } from '../utils' export const getTableRecords: Implementation['actions']['getTableRecords'] = diff --git a/integrations/airtable/src/actions/index.ts b/integrations/airtable/src/actions/index.ts index 1273397b128..3ba9bc773a3 100644 --- a/integrations/airtable/src/actions/index.ts +++ b/integrations/airtable/src/actions/index.ts @@ -1,12 +1,10 @@ -import { getBaseTables } from './get-base-tables' -import { getTableRecords } from './get-table-records' -import { createTable } from './create-table' -import { updateTable } from './update-table' import { createRecord } from './create-record' +import { createTable } from './create-table' +import { getTableRecords } from './get-table-records' import { updateRecord } from './update-record' +import { updateTable } from './update-table' export default { - getBaseTables, getTableRecords, createTable, updateTable, diff --git a/integrations/airtable/src/actions/update-record.ts b/integrations/airtable/src/actions/update-record.ts index fad2deb29c3..1e5962d3a99 100644 --- a/integrations/airtable/src/actions/update-record.ts +++ b/integrations/airtable/src/actions/update-record.ts @@ -1,5 +1,5 @@ -import type { Implementation } from '../misc/types' import { updateRecordInputSchema } from '../misc/custom-schemas' +import type { Implementation } from '../misc/types' import { getClient } from '../utils' export const updateRecord: Implementation['actions']['updateRecord'] = async ({ diff --git a/integrations/airtable/src/actions/update-table.ts b/integrations/airtable/src/actions/update-table.ts index 03069fe7a69..ac7e7949339 100644 --- a/integrations/airtable/src/actions/update-table.ts +++ b/integrations/airtable/src/actions/update-table.ts @@ -1,5 +1,5 @@ -import type { Implementation } from '../misc/types' import { updateTableInputSchema } from '../misc/custom-schemas' +import type { Implementation } from '../misc/types' import { getClient } from '../utils' export const updateTable: Implementation['actions']['updateTable'] = async ({ diff --git a/integrations/airtable/src/client/index.ts b/integrations/airtable/src/client/index.ts index 5a9dbfca767..b628f1e333a 100644 --- a/integrations/airtable/src/client/index.ts +++ b/integrations/airtable/src/client/index.ts @@ -1,6 +1,6 @@ import Airtable from 'airtable' import axios, { AxiosInstance } from 'axios' -import { tableFields } from 'src/misc/custom-types' +import { TableFields } from '../misc/types' export class AirtableApi { private base: Airtable.Base @@ -12,7 +12,10 @@ export class AirtableApi { this.base = new Airtable({ apiKey, endpointUrl }).base(baseId) this.axiosClient = axios.create({ baseURL: endpointUrl || 'https://api.airtable.com/v0/', - headers: { Authorization: `Bearer ${apiKey}` }, + headers: { + Authorization: `Bearer ${apiKey}`, + 'Content-Type': 'application/json', + }, }) } @@ -31,14 +34,7 @@ export class AirtableApi { return record } - async getBaseTables() { - const response = await this.axiosClient.get( - `/meta/bases/${this.baseId}/tables` - ) - return response.data.tables - } - - async createTable(name: string, fields: tableFields, description?: string) { + async createTable(name: string, fields: TableFields, description?: string) { const descriptionLimit = 20000 const validDescription = description?.slice(0, descriptionLimit) const payload = { @@ -46,6 +42,7 @@ export class AirtableApi { description: validDescription, fields, } + const response = await this.axiosClient.post( `/meta/bases/${this.baseId}/tables`, payload diff --git a/integrations/airtable/src/definitions/actions.ts b/integrations/airtable/src/definitions/actions.ts index da8d97d84f3..083f7c71b2c 100644 --- a/integrations/airtable/src/definitions/actions.ts +++ b/integrations/airtable/src/definitions/actions.ts @@ -3,8 +3,6 @@ import { createRecordOutputSchema, createTableInputSchema, createTableOutputSchema, - getBaseTablesInputSchema, - getBaseTablesOutputSchema, getTableRecordsInputSchema, getTableRecordsOutputSchema, updateRecordInputSchema, @@ -16,23 +14,11 @@ import { import { createRecordUi, createTableUi, - getBaseTablesUi, getTableRecordsUi, updateRecordUi, updateTableUi, } from '../misc/custom-uis' -const getBaseTables = { - title: 'Get Tables of the Base', - input: { - schema: getBaseTablesInputSchema, - ui: getBaseTablesUi, - }, - output: { - schema: getBaseTablesOutputSchema, - }, -} - const getTableRecords = { title: 'Get Records of the Table', input: { @@ -89,7 +75,6 @@ const updateRecord = { } export const actions = { - getBaseTables, getTableRecords, createTable, updateTable, diff --git a/integrations/airtable/src/misc/custom-schemas.ts b/integrations/airtable/src/misc/custom-schemas.ts index 46e2df3415a..9611a43b5d8 100644 --- a/integrations/airtable/src/misc/custom-schemas.ts +++ b/integrations/airtable/src/misc/custom-schemas.ts @@ -1,15 +1,6 @@ import z from 'zod' - import { tableSchema, recordSchema } from './sub-schemas' -export const getBaseTablesInputSchema = z.object({}) - -export const getBaseTablesOutputSchema = z - .object({ - tables: z.array(tableSchema), - }) - .passthrough() - export const getTableRecordsInputSchema = z.object({ tableIdOrName: z .string() diff --git a/integrations/airtable/src/misc/custom-types.ts b/integrations/airtable/src/misc/custom-types.ts deleted file mode 100644 index eaa142d39a4..00000000000 --- a/integrations/airtable/src/misc/custom-types.ts +++ /dev/null @@ -1,5 +0,0 @@ -import {} from './sub-types' - -type tableFields = Array<{ name: string; type: string }> - -export { tableFields } diff --git a/integrations/airtable/src/misc/sub-types/index.ts b/integrations/airtable/src/misc/sub-types/index.ts deleted file mode 100644 index 336ce12bb91..00000000000 --- a/integrations/airtable/src/misc/sub-types/index.ts +++ /dev/null @@ -1 +0,0 @@ -export {} diff --git a/integrations/airtable/src/misc/types.ts b/integrations/airtable/src/misc/types.ts index fc2ccc80b71..5e986646ae0 100644 --- a/integrations/airtable/src/misc/types.ts +++ b/integrations/airtable/src/misc/types.ts @@ -12,3 +12,4 @@ export type RegisterFunction = Implementation['register'] export type UnregisterFunction = Implementation['unregister'] export type Channels = Implementation['channels'] export type Handler = Implementation['handler'] +export type TableFields = Array<{ name: string; type: string }> diff --git a/integrations/airtable/src/utils/index.ts b/integrations/airtable/src/utils/index.ts index 2eae4ff766c..1e2cc361379 100644 --- a/integrations/airtable/src/utils/index.ts +++ b/integrations/airtable/src/utils/index.ts @@ -1,21 +1,22 @@ -import { Config } from '../misc/types' -import { tableFields } from 'src/misc/custom-types' +import { TableFields } from 'src/misc/types' import { AirtableApi } from '../client' +import { Config } from '../misc/types' export function getClient(config: Config) { return new AirtableApi(config.accessToken, config.baseId, config.endpointUrl) } export function fieldsStringToArray(fieldsString: string) { - let fields: tableFields + let fields: TableFields try { fields = fieldsString.split(',').map((fieldString) => { const [type, name] = fieldString.trim().split('_') if (type === '' || type === undefined) throw new Error('Type is Required') if (name === '' || name === undefined) throw new Error('Name is Required') + return { - type: type, - name: name, + type, + name, } }) } catch (error) { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c0989d814a7..99b2b2e424e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -166,6 +166,34 @@ importers: specifier: ^4.9.4 version: 4.9.5 + integrations/airtable: + dependencies: + '@botpress/client': + specifier: workspace:* + version: link:../../packages/client + '@botpress/sdk': + specifier: workspace:* + version: link:../../packages/sdk + airtable: + specifier: ^0.12.2 + version: 0.12.2 + axios: + specifier: ^1.5.0 + version: 1.6.5 + zod: + specifier: 3.20.6 + version: 3.20.6 + devDependencies: + '@types/node': + specifier: ^18.11.17 + version: 18.16.16 + ts-node: + specifier: ^10.9.1 + version: 10.9.1(@types/node@18.16.16)(typescript@4.9.5) + typescript: + specifier: ^4.9.4 + version: 4.9.5 + integrations/asana: dependencies: '@botpress/sdk': @@ -1452,7 +1480,7 @@ packages: '@jridgewell/gen-mapping': 0.3.3 '@jridgewell/trace-mapping': 0.3.18 - /@anatine/zod-openapi@1.14.0(openapi3-ts@2.0.2)(zod@3.21.4): + /@anatine/zod-openapi@1.14.0(openapi3-ts@2.0.2)(zod@3.20.6): resolution: {integrity: sha512-fNpzgdrqTdHLK2/rZjALyZbyZAua+cXm9kKug2TZ1ly2szSu9G1eH4YrnR6p2uHME/5/BOfCebUjWTVm83hJIg==} peerDependencies: openapi3-ts: ^2.0.0 || ^3.0.0 @@ -1460,7 +1488,7 @@ packages: dependencies: openapi3-ts: 2.0.2 ts-deepmerge: 6.0.3 - zod: 3.21.4 + zod: 3.20.6 dev: true /@apidevtools/openapi-schemas@2.1.0: @@ -2021,9 +2049,9 @@ packages: /@bpinternal/opapi@0.6.3(openapi-types@12.1.3): resolution: {integrity: sha512-XVzxAtc6sOLPUDBjln50QCk73YrMfFFbec1PJ1Qb0dDRxaNI/dAdNDTtY9yZlrQUSxLV+PKJHcbyUTtDZ34mXQ==} dependencies: - '@anatine/zod-openapi': 1.14.0(openapi3-ts@2.0.2)(zod@3.21.4) + '@anatine/zod-openapi': 1.14.0(openapi3-ts@2.0.2)(zod@3.20.6) '@readme/openapi-parser': 2.5.0(openapi-types@12.1.3) - axios: 1.6.3 + axios: 1.6.5 chalk: 4.1.2 decompress: 4.2.1 execa: 6.1.0 @@ -2035,7 +2063,7 @@ packages: tsconfig-paths: 4.2.0 verror: 1.10.1 winston: 3.9.0 - zod: 3.21.4 + zod: 3.20.6 transitivePeerDependencies: - debug - openapi-types @@ -2065,7 +2093,7 @@ packages: browser-or-node: 2.1.1 isomorphic-ws: 5.0.0(ws@8.13.0) ws: 8.13.0 - zod: 3.21.4 + zod: 3.20.6 transitivePeerDependencies: - bufferutil - utf-8-validate @@ -4340,7 +4368,7 @@ packages: /axios@0.21.4(debug@4.3.4): resolution: {integrity: sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==} dependencies: - follow-redirects: 1.15.2(debug@4.3.4) + follow-redirects: 1.15.4(debug@4.3.4) transitivePeerDependencies: - debug dev: false @@ -4348,7 +4376,7 @@ packages: /axios@0.24.0: resolution: {integrity: sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==} dependencies: - follow-redirects: 1.15.2(debug@4.3.4) + follow-redirects: 1.15.4(debug@4.3.4) transitivePeerDependencies: - debug dev: false @@ -4356,7 +4384,7 @@ packages: /axios@0.25.0: resolution: {integrity: sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==} dependencies: - follow-redirects: 1.15.2(debug@4.3.4) + follow-redirects: 1.15.4(debug@4.3.4) transitivePeerDependencies: - debug dev: false @@ -4364,7 +4392,7 @@ packages: /axios@0.26.1: resolution: {integrity: sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==} dependencies: - follow-redirects: 1.15.2(debug@4.3.4) + follow-redirects: 1.15.4(debug@4.3.4) transitivePeerDependencies: - debug dev: false @@ -4372,7 +4400,7 @@ packages: /axios@0.27.2: resolution: {integrity: sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==} dependencies: - follow-redirects: 1.15.2(debug@4.3.4) + follow-redirects: 1.15.2 form-data: 4.0.0 transitivePeerDependencies: - debug @@ -4381,7 +4409,7 @@ packages: /axios@1.4.0: resolution: {integrity: sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==} dependencies: - follow-redirects: 1.15.2(debug@4.3.4) + follow-redirects: 1.15.2 form-data: 4.0.0 proxy-from-env: 1.1.0 transitivePeerDependencies: @@ -4391,7 +4419,7 @@ packages: /axios@1.5.1: resolution: {integrity: sha512-Q28iYCWzNHjAm+yEAot5QaAMxhMghWLFVf7rRdwhUI+c2jix2DUXjAHXVi+s1ibs3mjPO/cCgbA++3BjD0vP/A==} dependencies: - follow-redirects: 1.15.2(debug@4.3.4) + follow-redirects: 1.15.2 form-data: 4.0.0 proxy-from-env: 1.1.0 transitivePeerDependencies: @@ -4401,7 +4429,7 @@ packages: /axios@1.6.1: resolution: {integrity: sha512-vfBmhDpKafglh0EldBEbVuoe7DyAavGSLWhuSm5ZSEKQnHhBf0xAAwybbNH1IkrJNGnS/VG4I5yxig1pCEXE4g==} dependencies: - follow-redirects: 1.15.2(debug@4.3.4) + follow-redirects: 1.15.2 form-data: 4.0.0 proxy-from-env: 1.1.0 transitivePeerDependencies: @@ -4411,7 +4439,7 @@ packages: /axios@1.6.3: resolution: {integrity: sha512-fWyNdeawGam70jXSVlKl+SUNVcL6j6W79CuSIPfi6HnDUmSCH6gyUys/HrqHeA/wU0Az41rRgean494d0Jb+ww==} dependencies: - follow-redirects: 1.15.2(debug@4.3.4) + follow-redirects: 1.15.2 form-data: 4.0.0 proxy-from-env: 1.1.0 transitivePeerDependencies: @@ -4421,7 +4449,7 @@ packages: /axios@1.6.5: resolution: {integrity: sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg==} dependencies: - follow-redirects: 1.15.4 + follow-redirects: 1.15.4(debug@4.3.4) form-data: 4.0.0 proxy-from-env: 1.1.0 transitivePeerDependencies: @@ -6417,7 +6445,7 @@ packages: /fn.name@1.1.0: resolution: {integrity: sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==} - /follow-redirects@1.15.2(debug@4.3.4): + /follow-redirects@1.15.2: resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==} engines: {node: '>=4.0'} peerDependencies: @@ -6425,11 +6453,9 @@ packages: peerDependenciesMeta: debug: optional: true - dependencies: - debug: 4.3.4 dev: false - /follow-redirects@1.15.4: + /follow-redirects@1.15.4(debug@4.3.4): resolution: {integrity: sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==} engines: {node: '>=4.0'} peerDependencies: @@ -6437,6 +6463,8 @@ packages: peerDependenciesMeta: debug: optional: true + dependencies: + debug: 4.3.4 /for-each@0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} @@ -10993,3 +11021,4 @@ packages: /zod@3.21.4: resolution: {integrity: sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==} + dev: false From 90d34b01e6ef6f15c34dd4719f84b55e05acf67f Mon Sep 17 00:00:00 2001 From: Charles Catta Date: Tue, 9 Jan 2024 17:06:12 -0500 Subject: [PATCH 04/10] Make CI build --- integrations/airtable/integration.definition.ts | 2 +- integrations/airtable/package.json | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/integrations/airtable/integration.definition.ts b/integrations/airtable/integration.definition.ts index 4bdc4a541d8..1d6e164aaca 100644 --- a/integrations/airtable/integration.definition.ts +++ b/integrations/airtable/integration.definition.ts @@ -20,4 +20,4 @@ export default new IntegrationDefinition({ actions, events: {}, states, -}) \ No newline at end of file +}) diff --git a/integrations/airtable/package.json b/integrations/airtable/package.json index 8364db56103..42492145a3c 100644 --- a/integrations/airtable/package.json +++ b/integrations/airtable/package.json @@ -1,7 +1,11 @@ { - "name": "airtable2", + "name": "@botpresshub/airtable", "scripts": { - "type:check": "tsc --noEmit" + "start": "pnpm bp serve", + "build": "pnpm bp build", + "deploy": "pnpm bp deploy", + "type:check": "tsc --noEmit", + "test": "echo \"Tests not implemented yet.\"" }, "keywords": [], "private": true, From fb24fc29082ab90b6d9d6713f01a0674f47d03d6 Mon Sep 17 00:00:00 2001 From: Charles Catta Date: Wed, 14 Feb 2024 14:05:55 -0500 Subject: [PATCH 05/10] Regenerate lockfile --- pnpm-lock.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9804d9cab9e..c6c509b31e3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -179,7 +179,7 @@ importers: version: 0.12.2 axios: specifier: ^1.5.0 - version: 1.6.5 + version: 1.6.7 zod: specifier: 3.20.6 version: 3.20.6 From a69fa42ee10d8d2533b88729c9a8f6c84aa9a69d Mon Sep 17 00:00:00 2001 From: Charles Catta Date: Mon, 19 Feb 2024 15:33:44 -0500 Subject: [PATCH 06/10] Remove extra files --- integrations/airtable/.eslintrc.js | 6 ---- integrations/airtable/.gitignore | 50 ------------------------------ integrations/airtable/.prettierrc | 4 --- 3 files changed, 60 deletions(-) delete mode 100644 integrations/airtable/.eslintrc.js delete mode 100644 integrations/airtable/.gitignore delete mode 100644 integrations/airtable/.prettierrc diff --git a/integrations/airtable/.eslintrc.js b/integrations/airtable/.eslintrc.js deleted file mode 100644 index edf84e074b1..00000000000 --- a/integrations/airtable/.eslintrc.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - extends: ['eslint:recommended', 'plugin:prettier/recommended'], - rules: { - 'prettier/prettier': 'warn', - }, -} diff --git a/integrations/airtable/.gitignore b/integrations/airtable/.gitignore deleted file mode 100644 index eb86529dabf..00000000000 --- a/integrations/airtable/.gitignore +++ /dev/null @@ -1,50 +0,0 @@ -# These are some examples of commonly ignored file patterns. -# You should customize this list as applicable to your project. -# Learn more about .gitignore: -# https://www.atlassian.com/git/tutorials/saving-changes/gitignore - -# Node artifact files -node_modules/ -dist/ - -# Compiled Java class files -*.class - -# Compiled Python bytecode -*.py[cod] - -# Log files -*.log - -# Package files -*.jar - -# Maven -target/ -dist/ - -# JetBrains IDE -.idea/ - -# Unit test reports -TEST*.xml - -# Generated by MacOS -.DS_Store - -# Generated by Windows -Thumbs.db - -# Applications -.botpress -*.app -*.exe -*.war - -# Large media files -*.mp4 -*.tiff -*.avi -*.flv -*.mov -*.wmv \ No newline at end of file diff --git a/integrations/airtable/.prettierrc b/integrations/airtable/.prettierrc deleted file mode 100644 index b2095be81e4..00000000000 --- a/integrations/airtable/.prettierrc +++ /dev/null @@ -1,4 +0,0 @@ -{ - "semi": false, - "singleQuote": true -} From a92702c2c1e536b547999c140fc4440ad5ac76e8 Mon Sep 17 00:00:00 2001 From: Charles Catta Date: Mon, 19 Feb 2024 15:34:32 -0500 Subject: [PATCH 07/10] Update readme and rename to hub --- integrations/airtable/{readme.md => hub.md} | 21 --------------------- 1 file changed, 21 deletions(-) rename integrations/airtable/{readme.md => hub.md} (52%) diff --git a/integrations/airtable/readme.md b/integrations/airtable/hub.md similarity index 52% rename from integrations/airtable/readme.md rename to integrations/airtable/hub.md index f417e7bd56a..1c286ebd7d6 100644 --- a/integrations/airtable/readme.md +++ b/integrations/airtable/hub.md @@ -35,24 +35,3 @@ Personal Access Token act as the user account granting access, with the followin For example, to update a record in a base via the API, the user who granted the token must have editor access to the base. In addition, the token must have both the correct scope (**data.records:write**) and the base added as a resource. For personal access tokens, scopes and resources/access are configured individually from **/create/tokens**. - -## Usage - -Once the integration is enabled, you can start using Airtable features from your Botpress chatbot. The integration offers several actions for interacting with Airtable, such as `getBaseTables`, `getTableRecords`, `createTable`, `updateTable`, `createRecord`, and `updateRecord`. These actions allow you to get tables and records from a base, create and update tables, and create and update records. - -For more details and examples, refer to the Botpress and Airtable documentation. - -## Limitations - -- Free Plan Limits: - - Records: Limited to **1,000 records per base**. - - API: Limited to **1,000 API calls per month**. - - Commenters: Limited to **50 commenters per workspace**. - - Sync and extensions: Available on the **Team plan and above**. To continue using Airtable with higher limits, you can upgrade to the Team plan. -- Rate limiting: Airtable employs a number of safeguards against bursts of incoming traffic to help maximize its stability. The API is limited to **5 requests per second per base**. If you exceed this rate, you will receive a **429 status code** and will need to wait **30 seconds** before subsequent requests will succeed. Airtable may change the enforced API rate limits or enforce additional types of limits in their sole discretion, including tiered based on pricing plan. Upon receiving a 429 status code, API integrations should back-off and wait before retrying the API request. The official JavaScript client has built-in back-off and retry logic. If you anticipate a higher read volume, it is recommended to use a caching proxy. - -## Contributing - -Contributions are welcome! Please submit issues and pull requests. - -Enjoy seamless helpdesk and customer support integration between Botpress and Airtable! From 38866e28f20d2cd7678b73ecc2d6d5b0c03e24b4 Mon Sep 17 00:00:00 2001 From: Charles Catta Date: Mon, 19 Feb 2024 15:35:59 -0500 Subject: [PATCH 08/10] Move sub-schemas --- .../airtable/src/misc/{sub-schemas/index.ts => sub-schemas.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename integrations/airtable/src/misc/{sub-schemas/index.ts => sub-schemas.ts} (100%) diff --git a/integrations/airtable/src/misc/sub-schemas/index.ts b/integrations/airtable/src/misc/sub-schemas.ts similarity index 100% rename from integrations/airtable/src/misc/sub-schemas/index.ts rename to integrations/airtable/src/misc/sub-schemas.ts From 79f58c422c1dcf5583488a9736a371ed3906c349 Mon Sep 17 00:00:00 2001 From: Charles Catta Date: Mon, 19 Feb 2024 15:53:34 -0500 Subject: [PATCH 09/10] Cleanup --- .../airtable/integration.definition.ts | 99 ++++++++++++++++--- .../airtable/src/actions/create-record.ts | 25 ++--- .../airtable/src/actions/create-table.ts | 21 ++-- .../airtable/src/actions/get-table-records.ts | 51 ++++------ .../airtable/src/actions/update-record.ts | 25 ++--- .../airtable/src/actions/update-table.ts | 21 ++-- .../src/{client/index.ts => client.ts} | 24 ++--- .../airtable/src/definitions/actions.ts | 83 ---------------- .../airtable/src/definitions/channels.ts | 7 -- .../airtable/src/definitions/index.ts | 26 ----- integrations/airtable/src/index.ts | 9 +- .../airtable/src/misc/custom-schemas.ts | 39 ++------ integrations/airtable/src/misc/custom-uis.ts | 3 +- integrations/airtable/src/misc/sub-schemas.ts | 8 +- integrations/airtable/src/misc/types.ts | 17 ++-- integrations/airtable/src/setup/channels.ts | 47 --------- integrations/airtable/src/setup/handler.ts | 11 --- integrations/airtable/src/setup/index.ts | 4 - integrations/airtable/src/setup/register.ts | 3 - integrations/airtable/src/setup/unregister.ts | 3 - integrations/airtable/src/utils.ts | 27 +++++ integrations/airtable/src/utils/index.ts | 26 ----- integrations/airtable/tsconfig.json | 24 +---- 23 files changed, 194 insertions(+), 409 deletions(-) rename integrations/airtable/src/{client/index.ts => client.ts} (76%) delete mode 100644 integrations/airtable/src/definitions/actions.ts delete mode 100644 integrations/airtable/src/definitions/channels.ts delete mode 100644 integrations/airtable/src/definitions/index.ts delete mode 100644 integrations/airtable/src/setup/channels.ts delete mode 100644 integrations/airtable/src/setup/handler.ts delete mode 100644 integrations/airtable/src/setup/index.ts delete mode 100644 integrations/airtable/src/setup/register.ts delete mode 100644 integrations/airtable/src/setup/unregister.ts create mode 100644 integrations/airtable/src/utils.ts delete mode 100644 integrations/airtable/src/utils/index.ts diff --git a/integrations/airtable/integration.definition.ts b/integrations/airtable/integration.definition.ts index 1d6e164aaca..1cc24d39c5e 100644 --- a/integrations/airtable/integration.definition.ts +++ b/integrations/airtable/integration.definition.ts @@ -1,23 +1,94 @@ import { IntegrationDefinition } from '@botpress/sdk' -import { name } from './package.json' - +import { z } from 'zod' import { - configuration, - states, - user, - channels, - actions, -} from './src/definitions' + createRecordInputSchema, + createRecordOutputSchema, + createTableInputSchema, + createTableOutputSchema, + getTableRecordsInputSchema, + getTableRecordsOutputSchema, + updateRecordInputSchema, + updateRecordOutputSchema, + updateTableInputSchema, + updateTableOutputSchema, +} from './src/misc/custom-schemas' +import { createRecordUi, createTableUi, getTableRecordsUi, updateRecordUi, updateTableUi } from './src/misc/custom-uis' + +const INTEGRATION_NAME = 'airtable' export default new IntegrationDefinition({ - name, + name: INTEGRATION_NAME, + title: 'Airtable', version: '0.2.0', readme: 'readme.md', icon: 'icon.svg', - configuration, - channels, - user, - actions, + configuration: { + schema: z.object({ + accessToken: z.string().describe('Personal Access Token'), + baseId: z.string().describe('Base ID'), + endpointUrl: z + .string() + .optional() + .default('https://api.airtable.com/v0/') + .describe('API endpoint to hit (Default: https://api.airtable.com/v0/)'), + }), + }, + channels: {}, + user: { + tags: {}, + }, + actions: { + getTableRecords: { + title: 'Get Records of the Table', + input: { + schema: getTableRecordsInputSchema, + ui: getTableRecordsUi, + }, + output: { + schema: getTableRecordsOutputSchema, + }, + }, + createTable: { + title: 'Create Table', + input: { + schema: createTableInputSchema, + ui: createTableUi, + }, + output: { + schema: createTableOutputSchema, + }, + }, + updateTable: { + title: 'Update Table', + input: { + schema: updateTableInputSchema, + ui: updateTableUi, + }, + output: { + schema: updateTableOutputSchema, + }, + }, + createRecord: { + title: 'Create Record', + input: { + schema: createRecordInputSchema, + ui: createRecordUi, + }, + output: { + schema: createRecordOutputSchema, + }, + }, + updateRecord: { + title: 'Update Record', + input: { + schema: updateRecordInputSchema, + ui: updateRecordUi, + }, + output: { + schema: updateRecordOutputSchema, + }, + }, + }, events: {}, - states, + states: {}, }) diff --git a/integrations/airtable/src/actions/create-record.ts b/integrations/airtable/src/actions/create-record.ts index 9c89724e132..613f601889b 100644 --- a/integrations/airtable/src/actions/create-record.ts +++ b/integrations/airtable/src/actions/create-record.ts @@ -1,32 +1,23 @@ import { createRecordInputSchema } from '../misc/custom-schemas' -import type { Implementation } from '../misc/types' +import type { IntegrationProps } from '../misc/types' import { getClient } from '../utils' -export const createRecord: Implementation['actions']['createRecord'] = async ({ - ctx, - logger, - input, -}) => { +export const createRecord: IntegrationProps['actions']['createRecord'] = async ({ ctx, logger, input }) => { const validatedInput = createRecordInputSchema.parse(input) const AirtableClient = getClient(ctx.configuration) - let record + try { - record = await AirtableClient.createRecord( - validatedInput.tableIdOrName, - JSON.parse(validatedInput.fields) - ) - record = { + const record = await AirtableClient.createRecord(validatedInput.tableIdOrName, JSON.parse(validatedInput.fields)) + logger.forBot().info(`Successful - Create Record - ${record.id}`) + return { _rawJson: record.fields, id: record.id, } - logger.forBot().info(`Successful - Create Record - ${record.id}`) } catch (error) { - record = { + logger.forBot().debug(`'Create Record' exception ${JSON.stringify(error)}`) + return { _rawJson: {}, id: '', } - logger.forBot().debug(`'Create Record' exception ${JSON.stringify(error)}`) } - - return record } diff --git a/integrations/airtable/src/actions/create-table.ts b/integrations/airtable/src/actions/create-table.ts index e4a9a14d4eb..87973b10af4 100644 --- a/integrations/airtable/src/actions/create-table.ts +++ b/integrations/airtable/src/actions/create-table.ts @@ -1,28 +1,21 @@ import { createTableInputSchema } from '../misc/custom-schemas' -import type { Implementation } from '../misc/types' +import type { IntegrationProps } from '../misc/types' import { fieldsStringToArray, getClient } from '../utils' -export const createTable: Implementation['actions']['createTable'] = async ({ - ctx, - logger, - input, -}) => { +export const createTable: IntegrationProps['actions']['createTable'] = async ({ ctx, logger, input }) => { const validatedInput = createTableInputSchema.parse(input) const AirtableClient = getClient(ctx.configuration) - let table + try { - table = await AirtableClient.createTable( + const table = await AirtableClient.createTable( validatedInput.name, fieldsStringToArray(validatedInput.fields), validatedInput.description ) - logger - .forBot() - .info(`Successful - Create Table - ${table.id} - ${table.name}`) + logger.forBot().info(`Successful - Create Table - ${table.id} - ${table.name}`) + return table } catch (error) { - table = {} logger.forBot().debug(`'Create Table' exception ${JSON.stringify(error)}`) + return {} } - - return table } diff --git a/integrations/airtable/src/actions/get-table-records.ts b/integrations/airtable/src/actions/get-table-records.ts index 534afcdff9c..0ea0042ec49 100644 --- a/integrations/airtable/src/actions/get-table-records.ts +++ b/integrations/airtable/src/actions/get-table-records.ts @@ -1,35 +1,22 @@ -import { - getTableRecordsInputSchema, - getTableRecordsOutputSchema, -} from '../misc/custom-schemas' -import type { Implementation } from '../misc/types' +import { getTableRecordsInputSchema } from '../misc/custom-schemas' +import type { IntegrationProps } from '../misc/types' import { getClient } from '../utils' -export const getTableRecords: Implementation['actions']['getTableRecords'] = - async ({ ctx, logger, input }) => { - const validatedInput = getTableRecordsInputSchema.parse(input) - const AirtableClient = getClient(ctx.configuration) - let records - try { - records = await AirtableClient.getTableRecords( - validatedInput.tableIdOrName - ) - records = records.map((record) => { - return { - _rawJson: record.fields, - id: record.id, - } - }) - logger - .forBot() - .info( - `Successful - Get Table Records - ${validatedInput.tableIdOrName}` - ) - } catch (error) { - logger - .forBot() - .debug(`'Get Table Records' exception ${JSON.stringify(error)}`) - } - - return getTableRecordsOutputSchema.parse({ records }) +export const getTableRecords: IntegrationProps['actions']['getTableRecords'] = async ({ ctx, logger, input }) => { + const validatedInput = getTableRecordsInputSchema.parse(input) + const AirtableClient = getClient(ctx.configuration) + try { + const output = await AirtableClient.getTableRecords(validatedInput.tableIdOrName) + const records = output.map((record) => { + return { + _rawJson: record.fields, + id: record.id, + } + }) + logger.forBot().info(`Successful - Get Table Records - ${validatedInput.tableIdOrName}`) + return { records } + } catch (error) { + logger.forBot().debug(`'Get Table Records' exception ${JSON.stringify(error)}`) + return { records: [] } } +} diff --git a/integrations/airtable/src/actions/update-record.ts b/integrations/airtable/src/actions/update-record.ts index 1e5962d3a99..c8791e4b73d 100644 --- a/integrations/airtable/src/actions/update-record.ts +++ b/integrations/airtable/src/actions/update-record.ts @@ -1,33 +1,28 @@ import { updateRecordInputSchema } from '../misc/custom-schemas' -import type { Implementation } from '../misc/types' +import type { IntegrationProps } from '../misc/types' import { getClient } from '../utils' -export const updateRecord: Implementation['actions']['updateRecord'] = async ({ - ctx, - logger, - input, -}) => { +export const updateRecord: IntegrationProps['actions']['updateRecord'] = async ({ ctx, logger, input }) => { const validatedInput = updateRecordInputSchema.parse(input) const AirtableClient = getClient(ctx.configuration) - let record + try { - record = await AirtableClient.updateRecord( + const output = await AirtableClient.updateRecord( validatedInput.tableIdOrName, validatedInput.recordId, JSON.parse(validatedInput.fields) ) - record = { - _rawJson: record.fields, - id: record.id, + const record = { + _rawJson: output.fields, + id: output.id, } logger.forBot().info(`Successful - Update Record - ${record.id}`) + return record } catch (error) { - record = { + logger.forBot().debug(`'Update Record' exception ${JSON.stringify(error)}`) + return { _rawJson: {}, id: '', } - logger.forBot().debug(`'Update Record' exception ${JSON.stringify(error)}`) } - - return record } diff --git a/integrations/airtable/src/actions/update-table.ts b/integrations/airtable/src/actions/update-table.ts index ac7e7949339..74fdc7e2ec8 100644 --- a/integrations/airtable/src/actions/update-table.ts +++ b/integrations/airtable/src/actions/update-table.ts @@ -1,28 +1,21 @@ import { updateTableInputSchema } from '../misc/custom-schemas' -import type { Implementation } from '../misc/types' +import type { IntegrationProps } from '../misc/types' import { getClient } from '../utils' -export const updateTable: Implementation['actions']['updateTable'] = async ({ - ctx, - logger, - input, -}) => { +export const updateTable: IntegrationProps['actions']['updateTable'] = async ({ ctx, logger, input }) => { const validatedInput = updateTableInputSchema.parse(input) const AirtableClient = getClient(ctx.configuration) - let table + try { - table = await AirtableClient.updateTable( + const table = await AirtableClient.updateTable( validatedInput.tableIdOrName, validatedInput.name, validatedInput.description ) - logger - .forBot() - .info(`Successful - Update Table - ${table.id} - ${table.name}`) + logger.forBot().info(`Successful - Update Table - ${table.id} - ${table.name}`) + return table } catch (error) { - table = {} logger.forBot().debug(`'Update Table' exception ${JSON.stringify(error)}`) + return {} } - - return table } diff --git a/integrations/airtable/src/client/index.ts b/integrations/airtable/src/client.ts similarity index 76% rename from integrations/airtable/src/client/index.ts rename to integrations/airtable/src/client.ts index b628f1e333a..36ce20d81d9 100644 --- a/integrations/airtable/src/client/index.ts +++ b/integrations/airtable/src/client.ts @@ -1,6 +1,6 @@ import Airtable from 'airtable' import axios, { AxiosInstance } from 'axios' -import { TableFields } from '../misc/types' +import { TableFields } from './misc/types' export class AirtableApi { private base: Airtable.Base @@ -43,25 +43,15 @@ export class AirtableApi { fields, } - const response = await this.axiosClient.post( - `/meta/bases/${this.baseId}/tables`, - payload - ) + const response = await this.axiosClient.post(`/meta/bases/${this.baseId}/tables`, payload) return response.data } - async updateTable( - tableIdOrName: string, - name?: string, - description?: string - ) { - const response = await this.axiosClient.patch( - `/meta/bases/${this.baseId}/tables/${tableIdOrName}`, - { - name, - description, - } - ) + async updateTable(tableIdOrName: string, name?: string, description?: string) { + const response = await this.axiosClient.patch(`/meta/bases/${this.baseId}/tables/${tableIdOrName}`, { + name, + description, + }) return response.data } } diff --git a/integrations/airtable/src/definitions/actions.ts b/integrations/airtable/src/definitions/actions.ts deleted file mode 100644 index 083f7c71b2c..00000000000 --- a/integrations/airtable/src/definitions/actions.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { - createRecordInputSchema, - createRecordOutputSchema, - createTableInputSchema, - createTableOutputSchema, - getTableRecordsInputSchema, - getTableRecordsOutputSchema, - updateRecordInputSchema, - updateRecordOutputSchema, - updateTableInputSchema, - updateTableOutputSchema, -} from '../misc/custom-schemas' - -import { - createRecordUi, - createTableUi, - getTableRecordsUi, - updateRecordUi, - updateTableUi, -} from '../misc/custom-uis' - -const getTableRecords = { - title: 'Get Records of the Table', - input: { - schema: getTableRecordsInputSchema, - ui: getTableRecordsUi, - }, - output: { - schema: getTableRecordsOutputSchema, - }, -} - -const createTable = { - title: 'Create Table', - input: { - schema: createTableInputSchema, - ui: createTableUi, - }, - output: { - schema: createTableOutputSchema, - }, -} - -const updateTable = { - title: 'Update Table', - input: { - schema: updateTableInputSchema, - ui: updateTableUi, - }, - output: { - schema: updateTableOutputSchema, - }, -} - -const createRecord = { - title: 'Create Record', - input: { - schema: createRecordInputSchema, - ui: createRecordUi, - }, - output: { - schema: createRecordOutputSchema, - }, -} - -const updateRecord = { - title: 'Update Record', - input: { - schema: updateRecordInputSchema, - ui: updateRecordUi, - }, - output: { - schema: updateRecordOutputSchema, - }, -} - -export const actions = { - getTableRecords, - createTable, - updateTable, - createRecord, - updateRecord, -} diff --git a/integrations/airtable/src/definitions/channels.ts b/integrations/airtable/src/definitions/channels.ts deleted file mode 100644 index 7503e93c677..00000000000 --- a/integrations/airtable/src/definitions/channels.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { IntegrationDefinitionProps, messages } from '@botpress/sdk' - -export const channels = { - channel: { - messages: { ...messages.defaults }, - }, -} satisfies IntegrationDefinitionProps['channels'] diff --git a/integrations/airtable/src/definitions/index.ts b/integrations/airtable/src/definitions/index.ts deleted file mode 100644 index d51189c0297..00000000000 --- a/integrations/airtable/src/definitions/index.ts +++ /dev/null @@ -1,26 +0,0 @@ -import type { IntegrationDefinitionProps } from '@botpress/sdk' -import z from 'zod' - -import { actions } from './actions' -import { channels } from './channels' - -export { actions } -export { channels } - -export const configuration = { - schema: z.object({ - accessToken: z.string().describe('Personal Access Token'), - baseId: z.string().describe('Base ID'), - endpointUrl: z - .string() - .optional() - .default('https://api.airtable.com/v0/') - .describe('API endpoint to hit (Default: https://api.airtable.com/v0/)'), - }), -} - -export const states: IntegrationDefinitionProps['states'] = {} - -export const user = { - tags: {}, -} diff --git a/integrations/airtable/src/index.ts b/integrations/airtable/src/index.ts index d94e88179de..d5690775675 100644 --- a/integrations/airtable/src/index.ts +++ b/integrations/airtable/src/index.ts @@ -1,11 +1,10 @@ import actions from './actions' -import { register, unregister, channels, handler } from './setup' import * as botpress from '.botpress' export default new botpress.Integration({ - register, - unregister, + register: async () => {}, + unregister: async () => {}, actions, - channels, - handler, + channels: {}, + handler: async () => {}, }) diff --git a/integrations/airtable/src/misc/custom-schemas.ts b/integrations/airtable/src/misc/custom-schemas.ts index 9611a43b5d8..f9436ae193f 100644 --- a/integrations/airtable/src/misc/custom-schemas.ts +++ b/integrations/airtable/src/misc/custom-schemas.ts @@ -2,11 +2,7 @@ import z from 'zod' import { tableSchema, recordSchema } from './sub-schemas' export const getTableRecordsInputSchema = z.object({ - tableIdOrName: z - .string() - .describe( - 'The ID or Name of the table (e.g. tblFnqcm4zLVKn85A or articles)' - ), + tableIdOrName: z.string().describe('The ID or Name of the table (e.g. tblFnqcm4zLVKn85A or articles)'), }) export const getTableRecordsOutputSchema = z @@ -22,38 +18,21 @@ export const createTableInputSchema = z.object({ .describe( 'The Table\'s fields, separated by commas. Each field should be in the format "type_name" (e.g. "phoneNumber_Customer Phone, singleLineText_Address").' ), - description: z - .string() - .optional() - .describe('Description of the Table (e.g. This is my table) (Optional)'), + description: z.string().optional().describe('Description of the Table (e.g. This is my table) (Optional)'), }) export const createTableOutputSchema = tableSchema.passthrough() export const updateTableInputSchema = z.object({ - tableIdOrName: z - .string() - .describe( - 'The ID or Name of the table (e.g. tblFnqcm4zLVKn85A or articles)' - ), - name: z - .string() - .optional() - .describe('Name of the Table (e.g. MyTable) (Optional)'), - description: z - .string() - .optional() - .describe('Description of the Table (e.g. This is my table) (Optional)'), + tableIdOrName: z.string().describe('The ID or Name of the table (e.g. tblFnqcm4zLVKn85A or articles)'), + name: z.string().optional().describe('Name of the Table (e.g. MyTable) (Optional)'), + description: z.string().optional().describe('Description of the Table (e.g. This is my table) (Optional)'), }) export const updateTableOutputSchema = tableSchema.passthrough() export const createRecordInputSchema = z.object({ - tableIdOrName: z - .string() - .describe( - 'The ID or Name of the table (e.g. tblFnqcm4zLVKn85A or articles)' - ), + tableIdOrName: z.string().describe('The ID or Name of the table (e.g. tblFnqcm4zLVKn85A or articles)'), fields: z .string() .describe( @@ -64,11 +43,7 @@ export const createRecordInputSchema = z.object({ export const createRecordOutputSchema = recordSchema.passthrough() export const updateRecordInputSchema = z.object({ - tableIdOrName: z - .string() - .describe( - 'The ID or Name of the table (e.g. tblFnqcm4zLVKn85A or articles)' - ), + tableIdOrName: z.string().describe('The ID or Name of the table (e.g. tblFnqcm4zLVKn85A or articles)'), recordId: z.string().describe('The ID of the Record to be updated'), fields: z .string() diff --git a/integrations/airtable/src/misc/custom-uis.ts b/integrations/airtable/src/misc/custom-uis.ts index 85a06594e72..dad8bdc508b 100644 --- a/integrations/airtable/src/misc/custom-uis.ts +++ b/integrations/airtable/src/misc/custom-uis.ts @@ -47,7 +47,6 @@ export const updateRecordUi = { title: 'The ID of the Record to be updated', }, fields: { - title: - 'The fields and their values for the new record, in a JSON format (e.g. {"Name":"John Doe","Verify":true})', + title: 'The fields and their values for the new record, in a JSON format (e.g. {"Name":"John Doe","Verify":true})', }, } diff --git a/integrations/airtable/src/misc/sub-schemas.ts b/integrations/airtable/src/misc/sub-schemas.ts index 321544f2e2d..362474c9b39 100644 --- a/integrations/airtable/src/misc/sub-schemas.ts +++ b/integrations/airtable/src/misc/sub-schemas.ts @@ -1,12 +1,8 @@ import z from 'zod' -const fieldSchema = z - .object({ name: z.string(), type: z.string() }) - .passthrough() +const fieldSchema = z.object({ name: z.string(), type: z.string() }).passthrough() -const viewSchema = z - .object({ id: z.string(), name: z.string(), type: z.string() }) - .passthrough() +const viewSchema = z.object({ id: z.string(), name: z.string(), type: z.string() }).passthrough() const tableSchema = z.object({ description: z.string().optional(), diff --git a/integrations/airtable/src/misc/types.ts b/integrations/airtable/src/misc/types.ts index 5e986646ae0..cb5c05b44c5 100644 --- a/integrations/airtable/src/misc/types.ts +++ b/integrations/airtable/src/misc/types.ts @@ -1,15 +1,12 @@ import type { IntegrationContext } from '@botpress/sdk' -import type * as botpress from '.botpress' -import type { Configuration } from '.botpress/implementation/configuration' +import type * as bp from '.botpress' -export type Config = botpress.configuration.Configuration -export type Implementation = ConstructorParameters< - typeof botpress.Integration ->[0] +export type Configuration = bp.configuration.Configuration +export type IntegrationProps = ConstructorParameters[0] export type IntegrationCtx = IntegrationContext -export type RegisterFunction = Implementation['register'] -export type UnregisterFunction = Implementation['unregister'] -export type Channels = Implementation['channels'] -export type Handler = Implementation['handler'] +export type RegisterFunction = IntegrationProps['register'] +export type UnregisterFunction = IntegrationProps['unregister'] +export type Channels = IntegrationProps['channels'] +export type Handler = IntegrationProps['handler'] export type TableFields = Array<{ name: string; type: string }> diff --git a/integrations/airtable/src/setup/channels.ts b/integrations/airtable/src/setup/channels.ts deleted file mode 100644 index 47c29f52ab3..00000000000 --- a/integrations/airtable/src/setup/channels.ts +++ /dev/null @@ -1,47 +0,0 @@ -import type { Channels } from '../misc/types' - -class NotImplementedError extends Error { - constructor() { - super('Not implemented') - } -} - -export const channels: Channels = { - channel: { - messages: { - text: async () => { - throw new NotImplementedError() - }, - image: async () => { - throw new NotImplementedError() - }, - markdown: async () => { - throw new NotImplementedError() - }, - audio: async () => { - throw new NotImplementedError() - }, - video: async () => { - throw new NotImplementedError() - }, - file: async () => { - throw new NotImplementedError() - }, - location: async () => { - throw new NotImplementedError() - }, - carousel: async () => { - throw new NotImplementedError() - }, - card: async () => { - throw new NotImplementedError() - }, - choice: async () => { - throw new NotImplementedError() - }, - dropdown: async () => { - throw new NotImplementedError() - }, - }, - }, -} diff --git a/integrations/airtable/src/setup/handler.ts b/integrations/airtable/src/setup/handler.ts deleted file mode 100644 index 01d0e2aabfc..00000000000 --- a/integrations/airtable/src/setup/handler.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type { Handler } from '../misc/types' - -class NotImplementedError extends Error { - constructor() { - super('Not implemented') - } -} - -export const handler: Handler = async () => { - throw new NotImplementedError() -} diff --git a/integrations/airtable/src/setup/index.ts b/integrations/airtable/src/setup/index.ts deleted file mode 100644 index 942ecedd0c6..00000000000 --- a/integrations/airtable/src/setup/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export { register } from './register' -export { unregister } from './unregister' -export { channels } from './channels' -export { handler } from './handler' diff --git a/integrations/airtable/src/setup/register.ts b/integrations/airtable/src/setup/register.ts deleted file mode 100644 index 221ca7a73b6..00000000000 --- a/integrations/airtable/src/setup/register.ts +++ /dev/null @@ -1,3 +0,0 @@ -import type { RegisterFunction } from '../misc/types' - -export const register: RegisterFunction = async () => {} diff --git a/integrations/airtable/src/setup/unregister.ts b/integrations/airtable/src/setup/unregister.ts deleted file mode 100644 index 48967dfd5e4..00000000000 --- a/integrations/airtable/src/setup/unregister.ts +++ /dev/null @@ -1,3 +0,0 @@ -import type { UnregisterFunction } from '../misc/types' - -export const unregister: UnregisterFunction = async () => {} diff --git a/integrations/airtable/src/utils.ts b/integrations/airtable/src/utils.ts new file mode 100644 index 00000000000..a330b93b169 --- /dev/null +++ b/integrations/airtable/src/utils.ts @@ -0,0 +1,27 @@ +import { AirtableApi } from './client' +import { Configuration } from './misc/types' + +export function getClient(config: Configuration) { + return new AirtableApi(config.accessToken, config.baseId, config.endpointUrl) +} + +export function fieldsStringToArray(fieldsString: string) { + try { + return fieldsString.split(',').map((fieldString) => { + const [type, name] = fieldString.trim().split('_') + if (type === '' || type === undefined) { + throw new Error('Type is Required') + } + if (name === '' || name === undefined) { + throw new Error('Name is Required') + } + + return { + type, + name, + } + }) + } catch (error) { + return [] + } +} diff --git a/integrations/airtable/src/utils/index.ts b/integrations/airtable/src/utils/index.ts deleted file mode 100644 index 1e2cc361379..00000000000 --- a/integrations/airtable/src/utils/index.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { TableFields } from 'src/misc/types' -import { AirtableApi } from '../client' -import { Config } from '../misc/types' - -export function getClient(config: Config) { - return new AirtableApi(config.accessToken, config.baseId, config.endpointUrl) -} - -export function fieldsStringToArray(fieldsString: string) { - let fields: TableFields - try { - fields = fieldsString.split(',').map((fieldString) => { - const [type, name] = fieldString.trim().split('_') - if (type === '' || type === undefined) throw new Error('Type is Required') - if (name === '' || name === undefined) throw new Error('Name is Required') - - return { - type, - name, - } - }) - } catch (error) { - fields = [] - } - return fields -} diff --git a/integrations/airtable/tsconfig.json b/integrations/airtable/tsconfig.json index 0f0a90a180d..8ddae2134a6 100644 --- a/integrations/airtable/tsconfig.json +++ b/integrations/airtable/tsconfig.json @@ -1,28 +1,10 @@ { + "extends": "../../tsconfig.json", "compilerOptions": { - "lib": ["es2022"], - "module": "commonjs", - "strict": true, - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, - "moduleResolution": "node", - "allowUnusedLabels": false, - "allowUnreachableCode": false, - "noFallthroughCasesInSwitch": true, - "noImplicitOverride": true, - "noImplicitReturns": true, - "noUncheckedIndexedAccess": true, - "noUnusedParameters": true, "target": "es2017", "baseUrl": ".", "outDir": "dist", - "checkJs": false, - "incremental": true, - "exactOptionalPropertyTypes": false, - "resolveJsonModule": true, - "noPropertyAccessFromIndexSignature": false, - "noUnusedLocals": false + "checkJs": false }, - "include": [".botpress/**/*", "src/**/*", "./*.ts", "./*.json"] + "include": [".botpress/**/*", "src/**/*", "package.json"] } From 7595a94e59b27e21451e0c100f801c3ee857a8fc Mon Sep 17 00:00:00 2001 From: Charles Catta Date: Mon, 19 Feb 2024 15:55:43 -0500 Subject: [PATCH 10/10] Remove extra fluff from hub.md --- integrations/airtable/hub.md | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/integrations/airtable/hub.md b/integrations/airtable/hub.md index 1c286ebd7d6..bc51fa164b3 100644 --- a/integrations/airtable/hub.md +++ b/integrations/airtable/hub.md @@ -24,14 +24,3 @@ To enable the Airtable integration in Botpress, follow these steps: 3. Locate the Airtable integration and click on “Enable” or “Configure.” 4. Provide the required `accessToken`, `baseId`, and `endpointUrl` (Optional). 5. Save the configuration. - -### Scope and resources/access of the Personal Access Token - -Personal Access Token act as the user account granting access, with the following limitations: - -- Scope: What actions the token can perform. -- Resources/access: Which bases and workspaces the token can access. Tokens may be granted access to individual or all bases/workspaces. These can be listed using the list bases endpoint. - -For example, to update a record in a base via the API, the user who granted the token must have editor access to the base. In addition, the token must have both the correct scope (**data.records:write**) and the base added as a resource. - -For personal access tokens, scopes and resources/access are configured individually from **/create/tokens**.