From c48541f9795c4440d0cdff261456398ec84ca4e7 Mon Sep 17 00:00:00 2001 From: Matej Lednicky Date: Thu, 5 Oct 2023 15:43:46 +0200 Subject: [PATCH] feat(REACH-717): add bin to run the client from command line (#99) Add command line client that can be executed with `yarn typeform-api`. --- .eslintignore | 1 + README.md | 42 ++++++++++++++++++++++++++++++++- package.json | 6 ++++- rollup.config.js | 39 ++++++++++++++++++++++++++++++- src/bin.ts | 61 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 146 insertions(+), 3 deletions(-) create mode 100644 src/bin.ts diff --git a/.eslintignore b/.eslintignore index 3a2ff4b..cb058a4 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,2 +1,3 @@ # output folder dist/ +rollup.config.js diff --git a/README.md b/README.md index b9e9d14..37655e1 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ npm install @typeform/api-client --save ## Usage -### Initialize +### In your project 1. Import client library @@ -72,6 +72,46 @@ typeformAPI.forms.list().then((response) => { }) ``` +**Note:** You can also execute the client binary directly via command line in your project: + +```shell +yarn typeform-api [params] +``` + +See [next section](#via-command-line) for more details. + +### Via command line + +1. Clone this repo on your machine + +2. Install all dependencies: + +```shell +yarn install +``` + +3. Set your personal token as `TF_TOKEN` env variable + +```shell +export TF_TOKEN=tfp_XXXXXXXXXX +``` + +4. Run the client: + +```shell +yarn typeform-api [params] +``` + +See [reference](#reference) for all available method names and their params. + +Example usage: + +```shell +yarn typeform-api forms.list +yarn typeform-api forms.get '{uid:"abcd1234"}' +yarn typeform-api themes.list '{pageSize:3}' +``` + ## Reference ### `createClient({token})` diff --git a/package.json b/package.json index 06370f8..0dd3dbf 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,11 @@ "semantic-release": "semantic-release", "server": "node ./tests/integration/mockServer.js", "server:dev": "nodemon ./tests/integration/mockServer.js", - "publish:github": "npm config set '//npm.pkg.github.com/:_authToken' $GH_TOKEN && npm publish --registry https://npm.pkg.github.com" + "publish:github": "npm config set '//npm.pkg.github.com/:_authToken' $GH_TOKEN && npm publish --registry https://npm.pkg.github.com", + "typeform-api": "node ./dist/bin" + }, + "bin": { + "typeform-api": "dist/bin" }, "main": "dist/index.cjs.js", "browser": "dist/typeform-api.js", diff --git a/rollup.config.js b/rollup.config.js index 3db7c52..6182869 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -88,6 +88,43 @@ const config = [ terser(), ], }, + { + input: 'src/bin.ts', + output: [ + { + file: pkg.bin['typeform-api'], + format: 'cjs', + exports: 'named', + banner: '#!/usr/bin/env node', + }, + ], + onwarn(warning, warn) { + // supress warning on usa of eval() + // eval() in ./src/bin.ts executes code supplied by user on their own machine, which is safe + if (warning.code === 'EVAL') { + return + } + warn(warning) + }, + plugins: [ + resolveModule(), + commonjs({ + include: ['node_modules/**'], + }), + ...plugins, + ], + external: [ + 'http', + 'https', + 'url', + 'zlib', + 'assert', + 'stream', + 'tty', + 'util', + 'os', + ], + }, ] -export default config \ No newline at end of file +export default config diff --git a/src/bin.ts b/src/bin.ts new file mode 100644 index 0000000..e37bd23 --- /dev/null +++ b/src/bin.ts @@ -0,0 +1,61 @@ +import { inspect } from 'util' + +import { createClient } from './index' + +const print = (message: string) => { + // eslint-disable-next-line no-console + console.log(message) +} + +const token = process.env.TF_TOKEN + +if (!token) { + throw new Error('Add your personal token as TF_TOKEN env variable') +} + +const typeformAPI = createClient({ token }) + +const [, , ...args] = process.argv +const [methodName, methodParams] = args + +if (!methodName || methodName === '-h' || methodName === '--help') { + print('usage: typeform-api [params]') + print('examples: yarn api forms.list') + print(' yarn api forms.get \'{uid:"abc12345"}\'') + print(" yarn api themes.list '{pageSize:3}'") + process.exit(0) +} + +const [property, method] = methodName.split('.') + +// @ts-ignore +if (!typeformAPI[property]?.[method]) { + throw new Error(`Method ${methodName} does not exist`) +} + +let parsedParams = undefined + +if (methodParams) { + try { + // this eval executes code supplied by user on their own machine, this is safe + // eslint-disable-next-line no-eval + eval(`parsedParams = ${methodParams}`) + } catch (err) { + throw new Error(`Invalid params: ${methodParams}`) + } + + if (typeof parsedParams !== 'object') { + throw new Error(`Invalid params: ${methodParams}`) + } +} + +print(`API: ${methodName}():`) + +// @ts-ignore +typeformAPI[property][method](parsedParams) + .then((result: Object) => { + print(inspect(result, { showHidden: false, depth: null, colors: true })) + }) + .catch((err: Error) => { + print(`Error: ${err.message}`) + })