├── .gitignore ├── README.md ├── node ├── .env.template ├── .eslintignore ├── .eslintrc.js ├── README.md ├── bin │ └── cli.js ├── package-lock.json ├── package.json ├── prettier.config.js └── src │ ├── commands │ ├── auth.js │ ├── create.js │ ├── delete.js │ ├── get.js │ ├── properties.js │ └── update.js │ ├── config.js │ ├── helpers │ ├── common.js │ ├── constants.js │ ├── logger.js │ └── prompts.js │ └── sdk.js ├── php ├── .env.template ├── .gitignore ├── .php-cs-fixer.php ├── README.md ├── bin │ └── cli.php ├── composer.json ├── composer.lock └── src │ ├── Commands │ ├── InitCommand.php │ └── Objects │ │ ├── CreateCommand.php │ │ ├── DeleteCommand.php │ │ ├── GetCommand.php │ │ ├── ObjectsCommand.php │ │ └── UpdateCommand.php │ └── Helpers │ └── HubspotClientHelper.php ├── python ├── .env.template ├── README.md ├── cli.py └── requirements.txt └── ruby ├── .env.template ├── Gemfile ├── Gemfile.lock ├── README.md ├── cli.rb └── config.rb /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .env 3 | .env-test 4 | 5 | # Node 6 | node_modules/ 7 | 8 | #Php 9 | vendor/ 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HubSpot CRM Objects sample app 2 | 3 | This is a sample app for the HubSpot [client libraries](https://developers.hubspot.com/docs/api/overview). This sample app demonstrates how to make CRUD API calls to different CRM Objects Endpoints. 4 | 5 | ## Reference 6 | 7 | - [CRM Objects API ](https://developers.hubspot.com/docs/api/crm/understanding-the-crm) 8 | 9 | ## How to run locally 10 | 11 | 1. Copy the .env.template file into a file named .env in the folder of the language you want to use. For example: 12 | 13 | ```bash 14 | cp node/.env.template node/.env 15 | ``` 16 | 17 | 2. You'll need to create a [private app](https://developers.hubspot.com/docs/api/private-apps) to get your access token 18 | > **_NOTE:_** choose necessary scopes (if you don't choose the sample won't work) 19 | 20 | 3. Paste your access token as the value for ACCESS_TOKEN in .env 21 | 22 | 4. Follow the language instructions on how to run. For example, if you want to run the Node server: 23 | 24 | ``` 25 | cd node # there's a README in this folder with instructions 26 | npm install 27 | ./bin/cli.js 28 | ``` 29 | 30 | ## Supported languages 31 | 32 | * [JavaScript (Node)](node/README.md) 33 | * [PHP](php/README.md) 34 | * [Ruby](ruby/README.md) 35 | * [Python](python/README.md) 36 | -------------------------------------------------------------------------------- /node/.env.template: -------------------------------------------------------------------------------- 1 | ACCESS_TOKEN= 2 | -------------------------------------------------------------------------------- /node/.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /node/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: 'eslint:recommended', 3 | root: true, 4 | env: { 5 | browser: false, 6 | node: true, 7 | commonjs: true, 8 | es6: true, 9 | }, 10 | parserOptions: { 11 | ecmaVersion: 2018, 12 | }, 13 | rules: { 14 | 'no-console': 'off', 15 | 'no-return-await': 'error', 16 | }, 17 | 18 | overrides: [ 19 | { 20 | files: ['**/test/*.js'], 21 | env: { 22 | mocha: true, 23 | node: true, 24 | }, 25 | }, 26 | ], 27 | }; 28 | -------------------------------------------------------------------------------- /node/README.md: -------------------------------------------------------------------------------- 1 | # HubSpot-nodejs CRM-objects sample app 2 | 3 | ### Requirements 4 | 5 | 1. Node v10+ 6 | 2. [Configured](https://github.com/HubSpot/sample-apps-manage-crm-objects/blob/main/README.md#how-to-run-locally) .env file 7 | 8 | ### Running 9 | 10 | 1. Install dependencies 11 | 12 | ```bash 13 | npm install 14 | ``` 15 | 16 | 2. Initialize 17 | 18 | If .env config file was not configured manually there is a way to initialize the CLI and create .env file via: 19 | 20 | ```bash 21 | ./bin/cli.js init 22 | ``` 23 | 24 | It will ask for your Hubspot Api Key and will save it to the new .env config file. 25 | 26 | 3. Commands 27 | 28 | Show all commands 29 | 30 | ```bash 31 | ./bin/cli.js --help 32 | ``` 33 | 34 | Get list of objects 35 | 36 | ```bash 37 | ./bin/cli.js get [objectType] -a --query='test' [properties] 38 | ./bin/cli.js get contacts --all 39 | ./bin/cli.js get contacts --all --properties=firstname --properties=lastname --properties=state 40 | ``` 41 | 42 | Get an object by id 43 | 44 | ```bash 45 | ./bin/cli.js get [objectType] [id] [properties] 46 | ./bin/cli.js get contacts 123 47 | ./bin/cli.js get contacts 123 --properties=firstname --properties=lastname --properties=state 48 | ``` 49 | 50 | Create new object 51 | 52 | ```bash 53 | ./bin/cli.js create [objectType] 54 | ``` 55 | 56 | Please also notice that some objects require mandatory properties, that you can provide in the following way: 57 | 58 | ```bash 59 | ./bin/cli.js create [objectType] --email='test@test.com' --firstname='Brian' --lastname='Halligan' 60 | ``` 61 | 62 | Update existing object 63 | 64 | ```bash 65 | ./bin/cli.js update [objectType] [objectId] --firstname='Ryan' 66 | ``` 67 | 68 | Archive existing object 69 | 70 | ```bash 71 | ./bin/cli.js delete [objectType] [objectId] 72 | ``` 73 | 74 | Get list of available properties for an object 75 | 76 | ```bash 77 | ./bin/cli.js properties [objectType] 78 | ``` 79 | -------------------------------------------------------------------------------- /node/bin/cli.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const yargs = require('yargs'); 4 | 5 | const authCommand = require('../src/commands/auth'); 6 | const getCommand = require('../src/commands/get'); 7 | const createCommand = require('../src/commands/create'); 8 | const updateCommand = require('../src/commands/update'); 9 | const deleteCommand = require('../src/commands/delete'); 10 | const propertiesCommand = require('../src/commands/properties'); 11 | const { logger } = require('../src/helpers/logger'); 12 | 13 | yargs 14 | .usage('Sample app that interacts with Hubspot CRM objects') 15 | .exitProcess(false) 16 | .fail((msg, err, yargs) => { 17 | if (msg === null) { 18 | yargs.showHelp(); 19 | process.exit(0); 20 | } else { 21 | logger.error(msg); 22 | process.exit(1); 23 | } 24 | }) 25 | .command(authCommand) 26 | .command(getCommand) 27 | .command(createCommand) 28 | .command(updateCommand) 29 | .command(deleteCommand) 30 | .command(propertiesCommand) 31 | .help() 32 | .recommendCommands() 33 | .demandCommand(1, '') 34 | .strictCommands().argv; 35 | -------------------------------------------------------------------------------- /node/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hubspot-crm-objects", 3 | "version": "1.0.0", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "hubspot-crm-objects", 9 | "version": "1.0.0", 10 | "license": "Apache-2.0", 11 | "dependencies": { 12 | "@hubspot/api-client": "^9.0.*", 13 | "bluebird": "^3.7.2", 14 | "chalk": "^4.1.0", 15 | "dotenv": "^8.1.0", 16 | "inquirer": "^7.3.3", 17 | "lodash": "^4.17.15", 18 | "pluralize": "^8.0.0", 19 | "yargs": "^16.2.0" 20 | }, 21 | "devDependencies": { 22 | "nodemon": "^2.0.16", 23 | "prettier": "^2.2.1" 24 | }, 25 | "engines": { 26 | "node": ">= 10.13.0" 27 | } 28 | }, 29 | "node_modules/@hubspot/api-client": { 30 | "version": "9.0.0", 31 | "resolved": "https://registry.npmjs.org/@hubspot/api-client/-/api-client-9.0.0.tgz", 32 | "integrity": "sha512-dwM07fy0NXlSud6BGgUqnUVwBSVWCa3TkAM4nAExn6xsvG6adtA0rD6ljNEGYVdIs0n8wvqAv13vh25fekMbXQ==", 33 | "dependencies": { 34 | "@types/node-fetch": "^2.5.7", 35 | "bottleneck": "^2.19.5", 36 | "es6-promise": "^4.2.4", 37 | "form-data": "^2.5.0", 38 | "lodash.get": "^4.4.2", 39 | "lodash.merge": "^4.6.2", 40 | "node-fetch": "^2.6.0", 41 | "url-parse": "^1.4.3" 42 | } 43 | }, 44 | "node_modules/@types/node": { 45 | "version": "20.3.2", 46 | "resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.2.tgz", 47 | "integrity": "sha512-vOBLVQeCQfIcF/2Y7eKFTqrMnizK5lRNQ7ykML/5RuwVXVWxYkgwS7xbt4B6fKCUPgbSL5FSsjHQpaGQP/dQmw==" 48 | }, 49 | "node_modules/@types/node-fetch": { 50 | "version": "2.6.4", 51 | "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.4.tgz", 52 | "integrity": "sha512-1ZX9fcN4Rvkvgv4E6PAY5WXUFWFcRWxZa3EW83UjycOB9ljJCedb2CupIP4RZMEwF/M3eTcCihbBRgwtGbg5Rg==", 53 | "dependencies": { 54 | "@types/node": "*", 55 | "form-data": "^3.0.0" 56 | } 57 | }, 58 | "node_modules/@types/node-fetch/node_modules/form-data": { 59 | "version": "3.0.1", 60 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", 61 | "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", 62 | "dependencies": { 63 | "asynckit": "^0.4.0", 64 | "combined-stream": "^1.0.8", 65 | "mime-types": "^2.1.12" 66 | }, 67 | "engines": { 68 | "node": ">= 6" 69 | } 70 | }, 71 | "node_modules/abbrev": { 72 | "version": "1.1.1", 73 | "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", 74 | "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", 75 | "dev": true 76 | }, 77 | "node_modules/ansi-escapes": { 78 | "version": "4.3.2", 79 | "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", 80 | "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", 81 | "dependencies": { 82 | "type-fest": "^0.21.3" 83 | }, 84 | "engines": { 85 | "node": ">=8" 86 | }, 87 | "funding": { 88 | "url": "https://github.com/sponsors/sindresorhus" 89 | } 90 | }, 91 | "node_modules/ansi-regex": { 92 | "version": "5.0.1", 93 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 94 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 95 | "engines": { 96 | "node": ">=8" 97 | } 98 | }, 99 | "node_modules/ansi-styles": { 100 | "version": "4.3.0", 101 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 102 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 103 | "dependencies": { 104 | "color-convert": "^2.0.1" 105 | }, 106 | "engines": { 107 | "node": ">=8" 108 | }, 109 | "funding": { 110 | "url": "https://github.com/chalk/ansi-styles?sponsor=1" 111 | } 112 | }, 113 | "node_modules/anymatch": { 114 | "version": "3.1.3", 115 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", 116 | "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", 117 | "dev": true, 118 | "dependencies": { 119 | "normalize-path": "^3.0.0", 120 | "picomatch": "^2.0.4" 121 | }, 122 | "engines": { 123 | "node": ">= 8" 124 | } 125 | }, 126 | "node_modules/asynckit": { 127 | "version": "0.4.0", 128 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 129 | "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" 130 | }, 131 | "node_modules/balanced-match": { 132 | "version": "1.0.2", 133 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 134 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 135 | "dev": true 136 | }, 137 | "node_modules/binary-extensions": { 138 | "version": "2.2.0", 139 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", 140 | "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", 141 | "dev": true, 142 | "engines": { 143 | "node": ">=8" 144 | } 145 | }, 146 | "node_modules/bluebird": { 147 | "version": "3.7.2", 148 | "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", 149 | "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" 150 | }, 151 | "node_modules/bottleneck": { 152 | "version": "2.19.5", 153 | "resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz", 154 | "integrity": "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==" 155 | }, 156 | "node_modules/brace-expansion": { 157 | "version": "1.1.11", 158 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 159 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 160 | "dev": true, 161 | "dependencies": { 162 | "balanced-match": "^1.0.0", 163 | "concat-map": "0.0.1" 164 | } 165 | }, 166 | "node_modules/braces": { 167 | "version": "3.0.2", 168 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 169 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 170 | "dev": true, 171 | "dependencies": { 172 | "fill-range": "^7.0.1" 173 | }, 174 | "engines": { 175 | "node": ">=8" 176 | } 177 | }, 178 | "node_modules/chalk": { 179 | "version": "4.1.2", 180 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", 181 | "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", 182 | "dependencies": { 183 | "ansi-styles": "^4.1.0", 184 | "supports-color": "^7.1.0" 185 | }, 186 | "engines": { 187 | "node": ">=10" 188 | }, 189 | "funding": { 190 | "url": "https://github.com/chalk/chalk?sponsor=1" 191 | } 192 | }, 193 | "node_modules/chardet": { 194 | "version": "0.7.0", 195 | "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", 196 | "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" 197 | }, 198 | "node_modules/chokidar": { 199 | "version": "3.5.3", 200 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", 201 | "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", 202 | "dev": true, 203 | "funding": [ 204 | { 205 | "type": "individual", 206 | "url": "https://paulmillr.com/funding/" 207 | } 208 | ], 209 | "dependencies": { 210 | "anymatch": "~3.1.2", 211 | "braces": "~3.0.2", 212 | "glob-parent": "~5.1.2", 213 | "is-binary-path": "~2.1.0", 214 | "is-glob": "~4.0.1", 215 | "normalize-path": "~3.0.0", 216 | "readdirp": "~3.6.0" 217 | }, 218 | "engines": { 219 | "node": ">= 8.10.0" 220 | }, 221 | "optionalDependencies": { 222 | "fsevents": "~2.3.2" 223 | } 224 | }, 225 | "node_modules/cli-cursor": { 226 | "version": "3.1.0", 227 | "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", 228 | "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", 229 | "dependencies": { 230 | "restore-cursor": "^3.1.0" 231 | }, 232 | "engines": { 233 | "node": ">=8" 234 | } 235 | }, 236 | "node_modules/cli-width": { 237 | "version": "3.0.0", 238 | "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", 239 | "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", 240 | "engines": { 241 | "node": ">= 10" 242 | } 243 | }, 244 | "node_modules/cliui": { 245 | "version": "7.0.4", 246 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", 247 | "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", 248 | "dependencies": { 249 | "string-width": "^4.2.0", 250 | "strip-ansi": "^6.0.0", 251 | "wrap-ansi": "^7.0.0" 252 | } 253 | }, 254 | "node_modules/color-convert": { 255 | "version": "2.0.1", 256 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 257 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 258 | "dependencies": { 259 | "color-name": "~1.1.4" 260 | }, 261 | "engines": { 262 | "node": ">=7.0.0" 263 | } 264 | }, 265 | "node_modules/color-name": { 266 | "version": "1.1.4", 267 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 268 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" 269 | }, 270 | "node_modules/combined-stream": { 271 | "version": "1.0.8", 272 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", 273 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", 274 | "dependencies": { 275 | "delayed-stream": "~1.0.0" 276 | }, 277 | "engines": { 278 | "node": ">= 0.8" 279 | } 280 | }, 281 | "node_modules/concat-map": { 282 | "version": "0.0.1", 283 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 284 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", 285 | "dev": true 286 | }, 287 | "node_modules/debug": { 288 | "version": "3.2.7", 289 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", 290 | "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", 291 | "dev": true, 292 | "dependencies": { 293 | "ms": "^2.1.1" 294 | } 295 | }, 296 | "node_modules/delayed-stream": { 297 | "version": "1.0.0", 298 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 299 | "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", 300 | "engines": { 301 | "node": ">=0.4.0" 302 | } 303 | }, 304 | "node_modules/dotenv": { 305 | "version": "8.6.0", 306 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz", 307 | "integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==", 308 | "engines": { 309 | "node": ">=10" 310 | } 311 | }, 312 | "node_modules/emoji-regex": { 313 | "version": "8.0.0", 314 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 315 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" 316 | }, 317 | "node_modules/es6-promise": { 318 | "version": "4.2.8", 319 | "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", 320 | "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" 321 | }, 322 | "node_modules/escalade": { 323 | "version": "3.1.1", 324 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", 325 | "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", 326 | "engines": { 327 | "node": ">=6" 328 | } 329 | }, 330 | "node_modules/escape-string-regexp": { 331 | "version": "1.0.5", 332 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 333 | "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", 334 | "engines": { 335 | "node": ">=0.8.0" 336 | } 337 | }, 338 | "node_modules/external-editor": { 339 | "version": "3.1.0", 340 | "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", 341 | "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", 342 | "dependencies": { 343 | "chardet": "^0.7.0", 344 | "iconv-lite": "^0.4.24", 345 | "tmp": "^0.0.33" 346 | }, 347 | "engines": { 348 | "node": ">=4" 349 | } 350 | }, 351 | "node_modules/figures": { 352 | "version": "3.2.0", 353 | "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", 354 | "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", 355 | "dependencies": { 356 | "escape-string-regexp": "^1.0.5" 357 | }, 358 | "engines": { 359 | "node": ">=8" 360 | }, 361 | "funding": { 362 | "url": "https://github.com/sponsors/sindresorhus" 363 | } 364 | }, 365 | "node_modules/fill-range": { 366 | "version": "7.0.1", 367 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 368 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 369 | "dev": true, 370 | "dependencies": { 371 | "to-regex-range": "^5.0.1" 372 | }, 373 | "engines": { 374 | "node": ">=8" 375 | } 376 | }, 377 | "node_modules/form-data": { 378 | "version": "2.5.1", 379 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", 380 | "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", 381 | "dependencies": { 382 | "asynckit": "^0.4.0", 383 | "combined-stream": "^1.0.6", 384 | "mime-types": "^2.1.12" 385 | }, 386 | "engines": { 387 | "node": ">= 0.12" 388 | } 389 | }, 390 | "node_modules/fsevents": { 391 | "version": "2.3.2", 392 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 393 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 394 | "dev": true, 395 | "hasInstallScript": true, 396 | "optional": true, 397 | "os": [ 398 | "darwin" 399 | ], 400 | "engines": { 401 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 402 | } 403 | }, 404 | "node_modules/get-caller-file": { 405 | "version": "2.0.5", 406 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", 407 | "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", 408 | "engines": { 409 | "node": "6.* || 8.* || >= 10.*" 410 | } 411 | }, 412 | "node_modules/glob-parent": { 413 | "version": "5.1.2", 414 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 415 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 416 | "dev": true, 417 | "dependencies": { 418 | "is-glob": "^4.0.1" 419 | }, 420 | "engines": { 421 | "node": ">= 6" 422 | } 423 | }, 424 | "node_modules/has-flag": { 425 | "version": "4.0.0", 426 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 427 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 428 | "engines": { 429 | "node": ">=8" 430 | } 431 | }, 432 | "node_modules/iconv-lite": { 433 | "version": "0.4.24", 434 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 435 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 436 | "dependencies": { 437 | "safer-buffer": ">= 2.1.2 < 3" 438 | }, 439 | "engines": { 440 | "node": ">=0.10.0" 441 | } 442 | }, 443 | "node_modules/ignore-by-default": { 444 | "version": "1.0.1", 445 | "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", 446 | "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", 447 | "dev": true 448 | }, 449 | "node_modules/inquirer": { 450 | "version": "7.3.3", 451 | "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", 452 | "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==", 453 | "dependencies": { 454 | "ansi-escapes": "^4.2.1", 455 | "chalk": "^4.1.0", 456 | "cli-cursor": "^3.1.0", 457 | "cli-width": "^3.0.0", 458 | "external-editor": "^3.0.3", 459 | "figures": "^3.0.0", 460 | "lodash": "^4.17.19", 461 | "mute-stream": "0.0.8", 462 | "run-async": "^2.4.0", 463 | "rxjs": "^6.6.0", 464 | "string-width": "^4.1.0", 465 | "strip-ansi": "^6.0.0", 466 | "through": "^2.3.6" 467 | }, 468 | "engines": { 469 | "node": ">=8.0.0" 470 | } 471 | }, 472 | "node_modules/is-binary-path": { 473 | "version": "2.1.0", 474 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 475 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 476 | "dev": true, 477 | "dependencies": { 478 | "binary-extensions": "^2.0.0" 479 | }, 480 | "engines": { 481 | "node": ">=8" 482 | } 483 | }, 484 | "node_modules/is-extglob": { 485 | "version": "2.1.1", 486 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 487 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 488 | "dev": true, 489 | "engines": { 490 | "node": ">=0.10.0" 491 | } 492 | }, 493 | "node_modules/is-fullwidth-code-point": { 494 | "version": "3.0.0", 495 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 496 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 497 | "engines": { 498 | "node": ">=8" 499 | } 500 | }, 501 | "node_modules/is-glob": { 502 | "version": "4.0.3", 503 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 504 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 505 | "dev": true, 506 | "dependencies": { 507 | "is-extglob": "^2.1.1" 508 | }, 509 | "engines": { 510 | "node": ">=0.10.0" 511 | } 512 | }, 513 | "node_modules/is-number": { 514 | "version": "7.0.0", 515 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 516 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 517 | "dev": true, 518 | "engines": { 519 | "node": ">=0.12.0" 520 | } 521 | }, 522 | "node_modules/lodash": { 523 | "version": "4.17.21", 524 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", 525 | "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" 526 | }, 527 | "node_modules/lodash.get": { 528 | "version": "4.4.2", 529 | "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", 530 | "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==" 531 | }, 532 | "node_modules/lodash.merge": { 533 | "version": "4.6.2", 534 | "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", 535 | "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" 536 | }, 537 | "node_modules/mime-db": { 538 | "version": "1.52.0", 539 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", 540 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", 541 | "engines": { 542 | "node": ">= 0.6" 543 | } 544 | }, 545 | "node_modules/mime-types": { 546 | "version": "2.1.35", 547 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", 548 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", 549 | "dependencies": { 550 | "mime-db": "1.52.0" 551 | }, 552 | "engines": { 553 | "node": ">= 0.6" 554 | } 555 | }, 556 | "node_modules/mimic-fn": { 557 | "version": "2.1.0", 558 | "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", 559 | "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", 560 | "engines": { 561 | "node": ">=6" 562 | } 563 | }, 564 | "node_modules/minimatch": { 565 | "version": "3.1.2", 566 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 567 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 568 | "dev": true, 569 | "dependencies": { 570 | "brace-expansion": "^1.1.7" 571 | }, 572 | "engines": { 573 | "node": "*" 574 | } 575 | }, 576 | "node_modules/ms": { 577 | "version": "2.1.3", 578 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 579 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", 580 | "dev": true 581 | }, 582 | "node_modules/mute-stream": { 583 | "version": "0.0.8", 584 | "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", 585 | "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" 586 | }, 587 | "node_modules/node-fetch": { 588 | "version": "2.6.12", 589 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz", 590 | "integrity": "sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==", 591 | "dependencies": { 592 | "whatwg-url": "^5.0.0" 593 | }, 594 | "engines": { 595 | "node": "4.x || >=6.0.0" 596 | }, 597 | "peerDependencies": { 598 | "encoding": "^0.1.0" 599 | }, 600 | "peerDependenciesMeta": { 601 | "encoding": { 602 | "optional": true 603 | } 604 | } 605 | }, 606 | "node_modules/nodemon": { 607 | "version": "2.0.22", 608 | "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.22.tgz", 609 | "integrity": "sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==", 610 | "dev": true, 611 | "dependencies": { 612 | "chokidar": "^3.5.2", 613 | "debug": "^3.2.7", 614 | "ignore-by-default": "^1.0.1", 615 | "minimatch": "^3.1.2", 616 | "pstree.remy": "^1.1.8", 617 | "semver": "^5.7.1", 618 | "simple-update-notifier": "^1.0.7", 619 | "supports-color": "^5.5.0", 620 | "touch": "^3.1.0", 621 | "undefsafe": "^2.0.5" 622 | }, 623 | "bin": { 624 | "nodemon": "bin/nodemon.js" 625 | }, 626 | "engines": { 627 | "node": ">=8.10.0" 628 | }, 629 | "funding": { 630 | "type": "opencollective", 631 | "url": "https://opencollective.com/nodemon" 632 | } 633 | }, 634 | "node_modules/nodemon/node_modules/has-flag": { 635 | "version": "3.0.0", 636 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 637 | "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", 638 | "dev": true, 639 | "engines": { 640 | "node": ">=4" 641 | } 642 | }, 643 | "node_modules/nodemon/node_modules/supports-color": { 644 | "version": "5.5.0", 645 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 646 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 647 | "dev": true, 648 | "dependencies": { 649 | "has-flag": "^3.0.0" 650 | }, 651 | "engines": { 652 | "node": ">=4" 653 | } 654 | }, 655 | "node_modules/nopt": { 656 | "version": "1.0.10", 657 | "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", 658 | "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", 659 | "dev": true, 660 | "dependencies": { 661 | "abbrev": "1" 662 | }, 663 | "bin": { 664 | "nopt": "bin/nopt.js" 665 | }, 666 | "engines": { 667 | "node": "*" 668 | } 669 | }, 670 | "node_modules/normalize-path": { 671 | "version": "3.0.0", 672 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 673 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 674 | "dev": true, 675 | "engines": { 676 | "node": ">=0.10.0" 677 | } 678 | }, 679 | "node_modules/onetime": { 680 | "version": "5.1.2", 681 | "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", 682 | "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", 683 | "dependencies": { 684 | "mimic-fn": "^2.1.0" 685 | }, 686 | "engines": { 687 | "node": ">=6" 688 | }, 689 | "funding": { 690 | "url": "https://github.com/sponsors/sindresorhus" 691 | } 692 | }, 693 | "node_modules/os-tmpdir": { 694 | "version": "1.0.2", 695 | "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", 696 | "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", 697 | "engines": { 698 | "node": ">=0.10.0" 699 | } 700 | }, 701 | "node_modules/picomatch": { 702 | "version": "2.3.1", 703 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 704 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 705 | "dev": true, 706 | "engines": { 707 | "node": ">=8.6" 708 | }, 709 | "funding": { 710 | "url": "https://github.com/sponsors/jonschlinkert" 711 | } 712 | }, 713 | "node_modules/pluralize": { 714 | "version": "8.0.0", 715 | "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", 716 | "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", 717 | "engines": { 718 | "node": ">=4" 719 | } 720 | }, 721 | "node_modules/prettier": { 722 | "version": "2.8.8", 723 | "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", 724 | "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", 725 | "dev": true, 726 | "bin": { 727 | "prettier": "bin-prettier.js" 728 | }, 729 | "engines": { 730 | "node": ">=10.13.0" 731 | }, 732 | "funding": { 733 | "url": "https://github.com/prettier/prettier?sponsor=1" 734 | } 735 | }, 736 | "node_modules/pstree.remy": { 737 | "version": "1.1.8", 738 | "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", 739 | "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", 740 | "dev": true 741 | }, 742 | "node_modules/querystringify": { 743 | "version": "2.2.0", 744 | "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", 745 | "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" 746 | }, 747 | "node_modules/readdirp": { 748 | "version": "3.6.0", 749 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", 750 | "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", 751 | "dev": true, 752 | "dependencies": { 753 | "picomatch": "^2.2.1" 754 | }, 755 | "engines": { 756 | "node": ">=8.10.0" 757 | } 758 | }, 759 | "node_modules/require-directory": { 760 | "version": "2.1.1", 761 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", 762 | "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", 763 | "engines": { 764 | "node": ">=0.10.0" 765 | } 766 | }, 767 | "node_modules/requires-port": { 768 | "version": "1.0.0", 769 | "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", 770 | "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" 771 | }, 772 | "node_modules/restore-cursor": { 773 | "version": "3.1.0", 774 | "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", 775 | "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", 776 | "dependencies": { 777 | "onetime": "^5.1.0", 778 | "signal-exit": "^3.0.2" 779 | }, 780 | "engines": { 781 | "node": ">=8" 782 | } 783 | }, 784 | "node_modules/run-async": { 785 | "version": "2.4.1", 786 | "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", 787 | "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", 788 | "engines": { 789 | "node": ">=0.12.0" 790 | } 791 | }, 792 | "node_modules/rxjs": { 793 | "version": "6.6.7", 794 | "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", 795 | "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", 796 | "dependencies": { 797 | "tslib": "^1.9.0" 798 | }, 799 | "engines": { 800 | "npm": ">=2.0.0" 801 | } 802 | }, 803 | "node_modules/safer-buffer": { 804 | "version": "2.1.2", 805 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 806 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 807 | }, 808 | "node_modules/semver": { 809 | "version": "5.7.1", 810 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", 811 | "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", 812 | "dev": true, 813 | "bin": { 814 | "semver": "bin/semver" 815 | } 816 | }, 817 | "node_modules/signal-exit": { 818 | "version": "3.0.7", 819 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", 820 | "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" 821 | }, 822 | "node_modules/simple-update-notifier": { 823 | "version": "1.1.0", 824 | "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz", 825 | "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==", 826 | "dev": true, 827 | "dependencies": { 828 | "semver": "~7.0.0" 829 | }, 830 | "engines": { 831 | "node": ">=8.10.0" 832 | } 833 | }, 834 | "node_modules/simple-update-notifier/node_modules/semver": { 835 | "version": "7.0.0", 836 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", 837 | "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", 838 | "dev": true, 839 | "bin": { 840 | "semver": "bin/semver.js" 841 | } 842 | }, 843 | "node_modules/string-width": { 844 | "version": "4.2.3", 845 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", 846 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", 847 | "dependencies": { 848 | "emoji-regex": "^8.0.0", 849 | "is-fullwidth-code-point": "^3.0.0", 850 | "strip-ansi": "^6.0.1" 851 | }, 852 | "engines": { 853 | "node": ">=8" 854 | } 855 | }, 856 | "node_modules/strip-ansi": { 857 | "version": "6.0.1", 858 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 859 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 860 | "dependencies": { 861 | "ansi-regex": "^5.0.1" 862 | }, 863 | "engines": { 864 | "node": ">=8" 865 | } 866 | }, 867 | "node_modules/supports-color": { 868 | "version": "7.2.0", 869 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 870 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 871 | "dependencies": { 872 | "has-flag": "^4.0.0" 873 | }, 874 | "engines": { 875 | "node": ">=8" 876 | } 877 | }, 878 | "node_modules/through": { 879 | "version": "2.3.8", 880 | "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", 881 | "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" 882 | }, 883 | "node_modules/tmp": { 884 | "version": "0.0.33", 885 | "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", 886 | "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", 887 | "dependencies": { 888 | "os-tmpdir": "~1.0.2" 889 | }, 890 | "engines": { 891 | "node": ">=0.6.0" 892 | } 893 | }, 894 | "node_modules/to-regex-range": { 895 | "version": "5.0.1", 896 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 897 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 898 | "dev": true, 899 | "dependencies": { 900 | "is-number": "^7.0.0" 901 | }, 902 | "engines": { 903 | "node": ">=8.0" 904 | } 905 | }, 906 | "node_modules/touch": { 907 | "version": "3.1.0", 908 | "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", 909 | "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", 910 | "dev": true, 911 | "dependencies": { 912 | "nopt": "~1.0.10" 913 | }, 914 | "bin": { 915 | "nodetouch": "bin/nodetouch.js" 916 | } 917 | }, 918 | "node_modules/tr46": { 919 | "version": "0.0.3", 920 | "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", 921 | "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" 922 | }, 923 | "node_modules/tslib": { 924 | "version": "1.14.1", 925 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", 926 | "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" 927 | }, 928 | "node_modules/type-fest": { 929 | "version": "0.21.3", 930 | "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", 931 | "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", 932 | "engines": { 933 | "node": ">=10" 934 | }, 935 | "funding": { 936 | "url": "https://github.com/sponsors/sindresorhus" 937 | } 938 | }, 939 | "node_modules/undefsafe": { 940 | "version": "2.0.5", 941 | "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", 942 | "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", 943 | "dev": true 944 | }, 945 | "node_modules/url-parse": { 946 | "version": "1.5.10", 947 | "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", 948 | "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", 949 | "dependencies": { 950 | "querystringify": "^2.1.1", 951 | "requires-port": "^1.0.0" 952 | } 953 | }, 954 | "node_modules/webidl-conversions": { 955 | "version": "3.0.1", 956 | "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", 957 | "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" 958 | }, 959 | "node_modules/whatwg-url": { 960 | "version": "5.0.0", 961 | "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", 962 | "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", 963 | "dependencies": { 964 | "tr46": "~0.0.3", 965 | "webidl-conversions": "^3.0.0" 966 | } 967 | }, 968 | "node_modules/wrap-ansi": { 969 | "version": "7.0.0", 970 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", 971 | "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", 972 | "dependencies": { 973 | "ansi-styles": "^4.0.0", 974 | "string-width": "^4.1.0", 975 | "strip-ansi": "^6.0.0" 976 | }, 977 | "engines": { 978 | "node": ">=10" 979 | }, 980 | "funding": { 981 | "url": "https://github.com/chalk/wrap-ansi?sponsor=1" 982 | } 983 | }, 984 | "node_modules/y18n": { 985 | "version": "5.0.8", 986 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", 987 | "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", 988 | "engines": { 989 | "node": ">=10" 990 | } 991 | }, 992 | "node_modules/yargs": { 993 | "version": "16.2.0", 994 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", 995 | "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", 996 | "dependencies": { 997 | "cliui": "^7.0.2", 998 | "escalade": "^3.1.1", 999 | "get-caller-file": "^2.0.5", 1000 | "require-directory": "^2.1.1", 1001 | "string-width": "^4.2.0", 1002 | "y18n": "^5.0.5", 1003 | "yargs-parser": "^20.2.2" 1004 | }, 1005 | "engines": { 1006 | "node": ">=10" 1007 | } 1008 | }, 1009 | "node_modules/yargs-parser": { 1010 | "version": "20.2.9", 1011 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", 1012 | "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", 1013 | "engines": { 1014 | "node": ">=10" 1015 | } 1016 | } 1017 | }, 1018 | "dependencies": { 1019 | "@hubspot/api-client": { 1020 | "version": "9.0.0", 1021 | "resolved": "https://registry.npmjs.org/@hubspot/api-client/-/api-client-9.0.0.tgz", 1022 | "integrity": "sha512-dwM07fy0NXlSud6BGgUqnUVwBSVWCa3TkAM4nAExn6xsvG6adtA0rD6ljNEGYVdIs0n8wvqAv13vh25fekMbXQ==", 1023 | "requires": { 1024 | "@types/node-fetch": "^2.5.7", 1025 | "bottleneck": "^2.19.5", 1026 | "es6-promise": "^4.2.4", 1027 | "form-data": "^2.5.0", 1028 | "lodash.get": "^4.4.2", 1029 | "lodash.merge": "^4.6.2", 1030 | "node-fetch": "^2.6.0", 1031 | "url-parse": "^1.4.3" 1032 | } 1033 | }, 1034 | "@types/node": { 1035 | "version": "20.3.2", 1036 | "resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.2.tgz", 1037 | "integrity": "sha512-vOBLVQeCQfIcF/2Y7eKFTqrMnizK5lRNQ7ykML/5RuwVXVWxYkgwS7xbt4B6fKCUPgbSL5FSsjHQpaGQP/dQmw==" 1038 | }, 1039 | "@types/node-fetch": { 1040 | "version": "2.6.4", 1041 | "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.4.tgz", 1042 | "integrity": "sha512-1ZX9fcN4Rvkvgv4E6PAY5WXUFWFcRWxZa3EW83UjycOB9ljJCedb2CupIP4RZMEwF/M3eTcCihbBRgwtGbg5Rg==", 1043 | "requires": { 1044 | "@types/node": "*", 1045 | "form-data": "^3.0.0" 1046 | }, 1047 | "dependencies": { 1048 | "form-data": { 1049 | "version": "3.0.1", 1050 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", 1051 | "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", 1052 | "requires": { 1053 | "asynckit": "^0.4.0", 1054 | "combined-stream": "^1.0.8", 1055 | "mime-types": "^2.1.12" 1056 | } 1057 | } 1058 | } 1059 | }, 1060 | "abbrev": { 1061 | "version": "1.1.1", 1062 | "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", 1063 | "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", 1064 | "dev": true 1065 | }, 1066 | "ansi-escapes": { 1067 | "version": "4.3.2", 1068 | "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", 1069 | "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", 1070 | "requires": { 1071 | "type-fest": "^0.21.3" 1072 | } 1073 | }, 1074 | "ansi-regex": { 1075 | "version": "5.0.1", 1076 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 1077 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" 1078 | }, 1079 | "ansi-styles": { 1080 | "version": "4.3.0", 1081 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 1082 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 1083 | "requires": { 1084 | "color-convert": "^2.0.1" 1085 | } 1086 | }, 1087 | "anymatch": { 1088 | "version": "3.1.3", 1089 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", 1090 | "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", 1091 | "dev": true, 1092 | "requires": { 1093 | "normalize-path": "^3.0.0", 1094 | "picomatch": "^2.0.4" 1095 | } 1096 | }, 1097 | "asynckit": { 1098 | "version": "0.4.0", 1099 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 1100 | "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" 1101 | }, 1102 | "balanced-match": { 1103 | "version": "1.0.2", 1104 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 1105 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 1106 | "dev": true 1107 | }, 1108 | "binary-extensions": { 1109 | "version": "2.2.0", 1110 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", 1111 | "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", 1112 | "dev": true 1113 | }, 1114 | "bluebird": { 1115 | "version": "3.7.2", 1116 | "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", 1117 | "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" 1118 | }, 1119 | "bottleneck": { 1120 | "version": "2.19.5", 1121 | "resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz", 1122 | "integrity": "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==" 1123 | }, 1124 | "brace-expansion": { 1125 | "version": "1.1.11", 1126 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 1127 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 1128 | "dev": true, 1129 | "requires": { 1130 | "balanced-match": "^1.0.0", 1131 | "concat-map": "0.0.1" 1132 | } 1133 | }, 1134 | "braces": { 1135 | "version": "3.0.2", 1136 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 1137 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 1138 | "dev": true, 1139 | "requires": { 1140 | "fill-range": "^7.0.1" 1141 | } 1142 | }, 1143 | "chalk": { 1144 | "version": "4.1.2", 1145 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", 1146 | "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", 1147 | "requires": { 1148 | "ansi-styles": "^4.1.0", 1149 | "supports-color": "^7.1.0" 1150 | } 1151 | }, 1152 | "chardet": { 1153 | "version": "0.7.0", 1154 | "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", 1155 | "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" 1156 | }, 1157 | "chokidar": { 1158 | "version": "3.5.3", 1159 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", 1160 | "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", 1161 | "dev": true, 1162 | "requires": { 1163 | "anymatch": "~3.1.2", 1164 | "braces": "~3.0.2", 1165 | "fsevents": "~2.3.2", 1166 | "glob-parent": "~5.1.2", 1167 | "is-binary-path": "~2.1.0", 1168 | "is-glob": "~4.0.1", 1169 | "normalize-path": "~3.0.0", 1170 | "readdirp": "~3.6.0" 1171 | } 1172 | }, 1173 | "cli-cursor": { 1174 | "version": "3.1.0", 1175 | "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", 1176 | "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", 1177 | "requires": { 1178 | "restore-cursor": "^3.1.0" 1179 | } 1180 | }, 1181 | "cli-width": { 1182 | "version": "3.0.0", 1183 | "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", 1184 | "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==" 1185 | }, 1186 | "cliui": { 1187 | "version": "7.0.4", 1188 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", 1189 | "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", 1190 | "requires": { 1191 | "string-width": "^4.2.0", 1192 | "strip-ansi": "^6.0.0", 1193 | "wrap-ansi": "^7.0.0" 1194 | } 1195 | }, 1196 | "color-convert": { 1197 | "version": "2.0.1", 1198 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 1199 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 1200 | "requires": { 1201 | "color-name": "~1.1.4" 1202 | } 1203 | }, 1204 | "color-name": { 1205 | "version": "1.1.4", 1206 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 1207 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" 1208 | }, 1209 | "combined-stream": { 1210 | "version": "1.0.8", 1211 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", 1212 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", 1213 | "requires": { 1214 | "delayed-stream": "~1.0.0" 1215 | } 1216 | }, 1217 | "concat-map": { 1218 | "version": "0.0.1", 1219 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 1220 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", 1221 | "dev": true 1222 | }, 1223 | "debug": { 1224 | "version": "3.2.7", 1225 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", 1226 | "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", 1227 | "dev": true, 1228 | "requires": { 1229 | "ms": "^2.1.1" 1230 | } 1231 | }, 1232 | "delayed-stream": { 1233 | "version": "1.0.0", 1234 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 1235 | "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" 1236 | }, 1237 | "dotenv": { 1238 | "version": "8.6.0", 1239 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz", 1240 | "integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==" 1241 | }, 1242 | "emoji-regex": { 1243 | "version": "8.0.0", 1244 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 1245 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" 1246 | }, 1247 | "es6-promise": { 1248 | "version": "4.2.8", 1249 | "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", 1250 | "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" 1251 | }, 1252 | "escalade": { 1253 | "version": "3.1.1", 1254 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", 1255 | "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" 1256 | }, 1257 | "escape-string-regexp": { 1258 | "version": "1.0.5", 1259 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 1260 | "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" 1261 | }, 1262 | "external-editor": { 1263 | "version": "3.1.0", 1264 | "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", 1265 | "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", 1266 | "requires": { 1267 | "chardet": "^0.7.0", 1268 | "iconv-lite": "^0.4.24", 1269 | "tmp": "^0.0.33" 1270 | } 1271 | }, 1272 | "figures": { 1273 | "version": "3.2.0", 1274 | "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", 1275 | "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", 1276 | "requires": { 1277 | "escape-string-regexp": "^1.0.5" 1278 | } 1279 | }, 1280 | "fill-range": { 1281 | "version": "7.0.1", 1282 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 1283 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 1284 | "dev": true, 1285 | "requires": { 1286 | "to-regex-range": "^5.0.1" 1287 | } 1288 | }, 1289 | "form-data": { 1290 | "version": "2.5.1", 1291 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", 1292 | "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", 1293 | "requires": { 1294 | "asynckit": "^0.4.0", 1295 | "combined-stream": "^1.0.6", 1296 | "mime-types": "^2.1.12" 1297 | } 1298 | }, 1299 | "fsevents": { 1300 | "version": "2.3.2", 1301 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 1302 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 1303 | "dev": true, 1304 | "optional": true 1305 | }, 1306 | "get-caller-file": { 1307 | "version": "2.0.5", 1308 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", 1309 | "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" 1310 | }, 1311 | "glob-parent": { 1312 | "version": "5.1.2", 1313 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 1314 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 1315 | "dev": true, 1316 | "requires": { 1317 | "is-glob": "^4.0.1" 1318 | } 1319 | }, 1320 | "has-flag": { 1321 | "version": "4.0.0", 1322 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 1323 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" 1324 | }, 1325 | "iconv-lite": { 1326 | "version": "0.4.24", 1327 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 1328 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 1329 | "requires": { 1330 | "safer-buffer": ">= 2.1.2 < 3" 1331 | } 1332 | }, 1333 | "ignore-by-default": { 1334 | "version": "1.0.1", 1335 | "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", 1336 | "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", 1337 | "dev": true 1338 | }, 1339 | "inquirer": { 1340 | "version": "7.3.3", 1341 | "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", 1342 | "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==", 1343 | "requires": { 1344 | "ansi-escapes": "^4.2.1", 1345 | "chalk": "^4.1.0", 1346 | "cli-cursor": "^3.1.0", 1347 | "cli-width": "^3.0.0", 1348 | "external-editor": "^3.0.3", 1349 | "figures": "^3.0.0", 1350 | "lodash": "^4.17.19", 1351 | "mute-stream": "0.0.8", 1352 | "run-async": "^2.4.0", 1353 | "rxjs": "^6.6.0", 1354 | "string-width": "^4.1.0", 1355 | "strip-ansi": "^6.0.0", 1356 | "through": "^2.3.6" 1357 | } 1358 | }, 1359 | "is-binary-path": { 1360 | "version": "2.1.0", 1361 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 1362 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 1363 | "dev": true, 1364 | "requires": { 1365 | "binary-extensions": "^2.0.0" 1366 | } 1367 | }, 1368 | "is-extglob": { 1369 | "version": "2.1.1", 1370 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 1371 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 1372 | "dev": true 1373 | }, 1374 | "is-fullwidth-code-point": { 1375 | "version": "3.0.0", 1376 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 1377 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" 1378 | }, 1379 | "is-glob": { 1380 | "version": "4.0.3", 1381 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 1382 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 1383 | "dev": true, 1384 | "requires": { 1385 | "is-extglob": "^2.1.1" 1386 | } 1387 | }, 1388 | "is-number": { 1389 | "version": "7.0.0", 1390 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 1391 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 1392 | "dev": true 1393 | }, 1394 | "lodash": { 1395 | "version": "4.17.21", 1396 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", 1397 | "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" 1398 | }, 1399 | "lodash.get": { 1400 | "version": "4.4.2", 1401 | "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", 1402 | "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==" 1403 | }, 1404 | "lodash.merge": { 1405 | "version": "4.6.2", 1406 | "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", 1407 | "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" 1408 | }, 1409 | "mime-db": { 1410 | "version": "1.52.0", 1411 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", 1412 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" 1413 | }, 1414 | "mime-types": { 1415 | "version": "2.1.35", 1416 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", 1417 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", 1418 | "requires": { 1419 | "mime-db": "1.52.0" 1420 | } 1421 | }, 1422 | "mimic-fn": { 1423 | "version": "2.1.0", 1424 | "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", 1425 | "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" 1426 | }, 1427 | "minimatch": { 1428 | "version": "3.1.2", 1429 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 1430 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 1431 | "dev": true, 1432 | "requires": { 1433 | "brace-expansion": "^1.1.7" 1434 | } 1435 | }, 1436 | "ms": { 1437 | "version": "2.1.3", 1438 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 1439 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", 1440 | "dev": true 1441 | }, 1442 | "mute-stream": { 1443 | "version": "0.0.8", 1444 | "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", 1445 | "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" 1446 | }, 1447 | "node-fetch": { 1448 | "version": "2.6.12", 1449 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz", 1450 | "integrity": "sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==", 1451 | "requires": { 1452 | "whatwg-url": "^5.0.0" 1453 | } 1454 | }, 1455 | "nodemon": { 1456 | "version": "2.0.22", 1457 | "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.22.tgz", 1458 | "integrity": "sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==", 1459 | "dev": true, 1460 | "requires": { 1461 | "chokidar": "^3.5.2", 1462 | "debug": "^3.2.7", 1463 | "ignore-by-default": "^1.0.1", 1464 | "minimatch": "^3.1.2", 1465 | "pstree.remy": "^1.1.8", 1466 | "semver": "^5.7.1", 1467 | "simple-update-notifier": "^1.0.7", 1468 | "supports-color": "^5.5.0", 1469 | "touch": "^3.1.0", 1470 | "undefsafe": "^2.0.5" 1471 | }, 1472 | "dependencies": { 1473 | "has-flag": { 1474 | "version": "3.0.0", 1475 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 1476 | "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", 1477 | "dev": true 1478 | }, 1479 | "supports-color": { 1480 | "version": "5.5.0", 1481 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 1482 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 1483 | "dev": true, 1484 | "requires": { 1485 | "has-flag": "^3.0.0" 1486 | } 1487 | } 1488 | } 1489 | }, 1490 | "nopt": { 1491 | "version": "1.0.10", 1492 | "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", 1493 | "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", 1494 | "dev": true, 1495 | "requires": { 1496 | "abbrev": "1" 1497 | } 1498 | }, 1499 | "normalize-path": { 1500 | "version": "3.0.0", 1501 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 1502 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 1503 | "dev": true 1504 | }, 1505 | "onetime": { 1506 | "version": "5.1.2", 1507 | "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", 1508 | "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", 1509 | "requires": { 1510 | "mimic-fn": "^2.1.0" 1511 | } 1512 | }, 1513 | "os-tmpdir": { 1514 | "version": "1.0.2", 1515 | "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", 1516 | "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==" 1517 | }, 1518 | "picomatch": { 1519 | "version": "2.3.1", 1520 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 1521 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 1522 | "dev": true 1523 | }, 1524 | "pluralize": { 1525 | "version": "8.0.0", 1526 | "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", 1527 | "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==" 1528 | }, 1529 | "prettier": { 1530 | "version": "2.8.8", 1531 | "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", 1532 | "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", 1533 | "dev": true 1534 | }, 1535 | "pstree.remy": { 1536 | "version": "1.1.8", 1537 | "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", 1538 | "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", 1539 | "dev": true 1540 | }, 1541 | "querystringify": { 1542 | "version": "2.2.0", 1543 | "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", 1544 | "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" 1545 | }, 1546 | "readdirp": { 1547 | "version": "3.6.0", 1548 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", 1549 | "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", 1550 | "dev": true, 1551 | "requires": { 1552 | "picomatch": "^2.2.1" 1553 | } 1554 | }, 1555 | "require-directory": { 1556 | "version": "2.1.1", 1557 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", 1558 | "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==" 1559 | }, 1560 | "requires-port": { 1561 | "version": "1.0.0", 1562 | "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", 1563 | "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" 1564 | }, 1565 | "restore-cursor": { 1566 | "version": "3.1.0", 1567 | "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", 1568 | "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", 1569 | "requires": { 1570 | "onetime": "^5.1.0", 1571 | "signal-exit": "^3.0.2" 1572 | } 1573 | }, 1574 | "run-async": { 1575 | "version": "2.4.1", 1576 | "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", 1577 | "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==" 1578 | }, 1579 | "rxjs": { 1580 | "version": "6.6.7", 1581 | "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", 1582 | "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", 1583 | "requires": { 1584 | "tslib": "^1.9.0" 1585 | } 1586 | }, 1587 | "safer-buffer": { 1588 | "version": "2.1.2", 1589 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 1590 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 1591 | }, 1592 | "semver": { 1593 | "version": "5.7.1", 1594 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", 1595 | "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", 1596 | "dev": true 1597 | }, 1598 | "signal-exit": { 1599 | "version": "3.0.7", 1600 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", 1601 | "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" 1602 | }, 1603 | "simple-update-notifier": { 1604 | "version": "1.1.0", 1605 | "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz", 1606 | "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==", 1607 | "dev": true, 1608 | "requires": { 1609 | "semver": "~7.0.0" 1610 | }, 1611 | "dependencies": { 1612 | "semver": { 1613 | "version": "7.0.0", 1614 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", 1615 | "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", 1616 | "dev": true 1617 | } 1618 | } 1619 | }, 1620 | "string-width": { 1621 | "version": "4.2.3", 1622 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", 1623 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", 1624 | "requires": { 1625 | "emoji-regex": "^8.0.0", 1626 | "is-fullwidth-code-point": "^3.0.0", 1627 | "strip-ansi": "^6.0.1" 1628 | } 1629 | }, 1630 | "strip-ansi": { 1631 | "version": "6.0.1", 1632 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 1633 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 1634 | "requires": { 1635 | "ansi-regex": "^5.0.1" 1636 | } 1637 | }, 1638 | "supports-color": { 1639 | "version": "7.2.0", 1640 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 1641 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 1642 | "requires": { 1643 | "has-flag": "^4.0.0" 1644 | } 1645 | }, 1646 | "through": { 1647 | "version": "2.3.8", 1648 | "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", 1649 | "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" 1650 | }, 1651 | "tmp": { 1652 | "version": "0.0.33", 1653 | "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", 1654 | "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", 1655 | "requires": { 1656 | "os-tmpdir": "~1.0.2" 1657 | } 1658 | }, 1659 | "to-regex-range": { 1660 | "version": "5.0.1", 1661 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 1662 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 1663 | "dev": true, 1664 | "requires": { 1665 | "is-number": "^7.0.0" 1666 | } 1667 | }, 1668 | "touch": { 1669 | "version": "3.1.0", 1670 | "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", 1671 | "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", 1672 | "dev": true, 1673 | "requires": { 1674 | "nopt": "~1.0.10" 1675 | } 1676 | }, 1677 | "tr46": { 1678 | "version": "0.0.3", 1679 | "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", 1680 | "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" 1681 | }, 1682 | "tslib": { 1683 | "version": "1.14.1", 1684 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", 1685 | "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" 1686 | }, 1687 | "type-fest": { 1688 | "version": "0.21.3", 1689 | "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", 1690 | "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==" 1691 | }, 1692 | "undefsafe": { 1693 | "version": "2.0.5", 1694 | "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", 1695 | "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", 1696 | "dev": true 1697 | }, 1698 | "url-parse": { 1699 | "version": "1.5.10", 1700 | "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", 1701 | "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", 1702 | "requires": { 1703 | "querystringify": "^2.1.1", 1704 | "requires-port": "^1.0.0" 1705 | } 1706 | }, 1707 | "webidl-conversions": { 1708 | "version": "3.0.1", 1709 | "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", 1710 | "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" 1711 | }, 1712 | "whatwg-url": { 1713 | "version": "5.0.0", 1714 | "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", 1715 | "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", 1716 | "requires": { 1717 | "tr46": "~0.0.3", 1718 | "webidl-conversions": "^3.0.0" 1719 | } 1720 | }, 1721 | "wrap-ansi": { 1722 | "version": "7.0.0", 1723 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", 1724 | "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", 1725 | "requires": { 1726 | "ansi-styles": "^4.0.0", 1727 | "string-width": "^4.1.0", 1728 | "strip-ansi": "^6.0.0" 1729 | } 1730 | }, 1731 | "y18n": { 1732 | "version": "5.0.8", 1733 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", 1734 | "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" 1735 | }, 1736 | "yargs": { 1737 | "version": "16.2.0", 1738 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", 1739 | "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", 1740 | "requires": { 1741 | "cliui": "^7.0.2", 1742 | "escalade": "^3.1.1", 1743 | "get-caller-file": "^2.0.5", 1744 | "require-directory": "^2.1.1", 1745 | "string-width": "^4.2.0", 1746 | "y18n": "^5.0.5", 1747 | "yargs-parser": "^20.2.2" 1748 | } 1749 | }, 1750 | "yargs-parser": { 1751 | "version": "20.2.9", 1752 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", 1753 | "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==" 1754 | } 1755 | } 1756 | } 1757 | -------------------------------------------------------------------------------- /node/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hubspot-crm-objects", 3 | "version": "1.0.0", 4 | "engines": { 5 | "node": ">= 10.13.0" 6 | }, 7 | "description": "hubspot-node client sample applications", 8 | "main": "src/index.js", 9 | "scripts": { 10 | "prettier:write": "prettier --write './**/*.{js,json}'" 11 | }, 12 | "keywords": [ 13 | "hubspot", 14 | "sample", 15 | "example" 16 | ], 17 | "author": "hubspot", 18 | "license": "Apache-2.0", 19 | "dependencies": { 20 | "@hubspot/api-client": "^9.0.*", 21 | "bluebird": "^3.7.2", 22 | "chalk": "^4.1.0", 23 | "dotenv": "^8.1.0", 24 | "inquirer": "^7.3.3", 25 | "lodash": "^4.17.15", 26 | "pluralize": "^8.0.0", 27 | "yargs": "^16.2.0" 28 | }, 29 | "devDependencies": { 30 | "nodemon": "^2.0.16", 31 | "prettier": "^2.2.1" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /node/prettier.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | bracketSpacing: true, 3 | jsxBracketSameLine: false, 4 | printWidth: 80, 5 | proseWrap: 'never', 6 | semi: true, 7 | singleQuote: true, 8 | tabWidth: 2, 9 | // TODO: Change to `all` once supported 10 | trailingComma: 'es5', 11 | useTabs: false, 12 | overrides: [ 13 | { 14 | files: ['static_conf.json'], 15 | options: { 16 | parser: 'json-stringify', 17 | }, 18 | }, 19 | { 20 | files: ['*.lyaml'], 21 | options: { 22 | // Prevent unparsable wrapping behavior in lyaml files: 23 | // https://git.hubteam.com/HubSpot/prettier-config-hubspot/pull/36 24 | printWidth: 999, 25 | // Wrapping looks bad for certain strings that use newlines to separate 26 | // JSX elements 27 | proseWrap: 'preserve', 28 | }, 29 | }, 30 | ], 31 | }; 32 | -------------------------------------------------------------------------------- /node/src/commands/auth.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const { 3 | createEnvironmentFile, 4 | getEnvironmentConfigPath, 5 | } = require('../helpers/common'); 6 | 7 | const { promptUser, overwritePrompt } = require('../helpers/prompts'); 8 | 9 | const ACCESS_TOKEN_FLOW = { 10 | name: 'accessToken', 11 | message: 12 | 'Enter the access token for your account (found at https://app.hubspot.com/l/private-apps):', 13 | }; 14 | 15 | exports.command = 'init'; 16 | exports.describe = `initialize .env file for a HubSpot account`; 17 | 18 | exports.handler = async () => { 19 | const path = getEnvironmentConfigPath(); 20 | if (fs.existsSync(path)) { 21 | const { overwrite } = await overwritePrompt(path); 22 | if (overwrite) { 23 | fs.rmSync(path); 24 | } else { 25 | return; 26 | } 27 | } 28 | const { accessToken } = await promptUser([ACCESS_TOKEN_FLOW]); 29 | 30 | createEnvironmentFile({ 31 | ACCESS_TOKEN: accessToken || '', 32 | }); 33 | }; 34 | 35 | exports.builder = (yargs) => { 36 | return yargs; 37 | }; 38 | -------------------------------------------------------------------------------- /node/src/commands/create.js: -------------------------------------------------------------------------------- 1 | const _ = require('lodash'); 2 | const pluralize = require('pluralize'); 3 | const { AVAILABLE_OBJECT_TYPES } = require('../helpers/constants'); 4 | const { cleanupDefaultArgs } = require('../helpers/common'); 5 | const { checkConfig } = require('../config'); 6 | 7 | const { createObject } = require('../sdk'); 8 | 9 | exports.command = 'create '; 10 | exports.describe = 'Create CRM object'; 11 | 12 | exports.handler = async (options) => { 13 | const { objectType, ...properties } = options; 14 | 15 | if (!checkConfig()) { 16 | process.exit(1); 17 | } 18 | 19 | await createObject({ 20 | objectType: pluralize(objectType), 21 | properties: cleanupDefaultArgs(properties), 22 | }); 23 | }; 24 | 25 | exports.builder = (yargs) => { 26 | yargs.positional('objectType', { 27 | describe: 'CRM object type', 28 | type: 'string', 29 | choices: [ 30 | ...Object.values(AVAILABLE_OBJECT_TYPES), 31 | ...Object.keys(AVAILABLE_OBJECT_TYPES), 32 | ].sort(), 33 | coerce: (arg) => arg.toLowerCase(), 34 | }); 35 | return yargs; 36 | }; 37 | -------------------------------------------------------------------------------- /node/src/commands/delete.js: -------------------------------------------------------------------------------- 1 | const _ = require('lodash'); 2 | const pluralize = require('pluralize'); 3 | const { AVAILABLE_OBJECT_TYPES } = require('../helpers/constants'); 4 | const { checkConfig } = require('../config'); 5 | 6 | const { archiveObject } = require('../sdk'); 7 | 8 | exports.command = 'delete '; 9 | exports.describe = 'Archive CRM object'; 10 | 11 | exports.handler = async (options) => { 12 | const { objectType, objectId } = options; 13 | 14 | if (!checkConfig()) { 15 | process.exit(1); 16 | } 17 | 18 | await archiveObject({ 19 | objectType: pluralize(objectType), 20 | objectId, 21 | }); 22 | }; 23 | 24 | exports.builder = (yargs) => { 25 | yargs.positional('objectType', { 26 | describe: 'CRM object type', 27 | type: 'string', 28 | choices: [ 29 | ...Object.values(AVAILABLE_OBJECT_TYPES), 30 | ...Object.keys(AVAILABLE_OBJECT_TYPES), 31 | ].sort(), 32 | coerce: (arg) => arg.toLowerCase(), 33 | }); 34 | 35 | yargs.positional('objectId', { 36 | describe: 'CRM object id', 37 | type: 'string', 38 | }); 39 | return yargs; 40 | }; 41 | -------------------------------------------------------------------------------- /node/src/commands/get.js: -------------------------------------------------------------------------------- 1 | const _ = require('lodash'); 2 | const pluralize = require('pluralize'); 3 | const { AVAILABLE_OBJECT_TYPES } = require('../helpers/constants'); 4 | const { checkConfig } = require('../config'); 5 | const { logger } = require('../helpers/logger'); 6 | 7 | const { getObject, getAllObjects } = require('../sdk'); 8 | 9 | exports.command = 'get [objectId]'; 10 | exports.describe = 'Get CRM object'; 11 | 12 | exports.handler = async (options) => { 13 | const { objectType, objectId, properties, all, query } = options; 14 | 15 | if (!all && !objectId) { 16 | logger.error( 17 | 'Please, specify Object Id, or use --all flag for getting all objects' 18 | ); 19 | process.exit(1); 20 | } 21 | if (!checkConfig()) { 22 | process.exit(1); 23 | } 24 | 25 | if (all) { 26 | const res = await getAllObjects({ 27 | objectType: pluralize(objectType), 28 | query, 29 | properties, 30 | }); 31 | logger.log(res); 32 | } else { 33 | await getObject({ objectType: pluralize(objectType), objectId, properties }); 34 | } 35 | }; 36 | 37 | exports.builder = (yargs) => { 38 | yargs.positional('objectType', { 39 | describe: 'CRM object type', 40 | type: 'string', 41 | choices: [ 42 | ...Object.values(AVAILABLE_OBJECT_TYPES), 43 | ...Object.keys(AVAILABLE_OBJECT_TYPES), 44 | ].sort(), 45 | coerce: (arg) => arg.toLowerCase(), 46 | }); 47 | 48 | yargs.positional('objectId', { 49 | describe: 'CRM object id', 50 | type: 'string', 51 | }); 52 | 53 | yargs.positional('properties', { 54 | describe: 'CRM object properties', 55 | type: 'array', 56 | }); 57 | 58 | yargs.option('query', { 59 | alias: 'q', 60 | describe: 'searching filter for getting list of objects', 61 | type: 'string', 62 | }); 63 | 64 | yargs.option('all', { 65 | alias: 'a', 66 | describe: 'Get all objects', 67 | type: 'boolean', 68 | }); 69 | return yargs; 70 | }; 71 | -------------------------------------------------------------------------------- /node/src/commands/properties.js: -------------------------------------------------------------------------------- 1 | const _ = require('lodash'); 2 | const { AVAILABLE_OBJECT_TYPES } = require('../helpers/constants'); 3 | const { checkConfig } = require('../config'); 4 | 5 | const { getProperties } = require('../sdk'); 6 | 7 | exports.command = 'properties '; 8 | exports.describe = 'Get CRM object properties'; 9 | 10 | exports.handler = async (options) => { 11 | if (!checkConfig()) { 12 | process.exit(1); 13 | } 14 | const { objectType } = options; 15 | const res = await getProperties({ objectType }); 16 | console.table( 17 | res.map((item) => _.pick(item, ['name', 'label', 'type', 'groupName'])) 18 | ); 19 | }; 20 | 21 | exports.builder = (yargs) => { 22 | yargs.positional('objectType', { 23 | describe: 'CRM object type', 24 | type: 'string', 25 | choices: [ 26 | ...Object.values(AVAILABLE_OBJECT_TYPES), 27 | ...Object.keys(AVAILABLE_OBJECT_TYPES), 28 | ].sort(), 29 | coerce: (arg) => arg.toLowerCase(), 30 | }); 31 | return yargs; 32 | }; 33 | -------------------------------------------------------------------------------- /node/src/commands/update.js: -------------------------------------------------------------------------------- 1 | const _ = require('lodash'); 2 | const pluralize = require('pluralize'); 3 | const { AVAILABLE_OBJECT_TYPES } = require('../helpers/constants'); 4 | const { cleanupDefaultArgs } = require('../helpers/common'); 5 | const { checkConfig } = require('../config'); 6 | 7 | const { updateObject } = require('../sdk'); 8 | 9 | exports.command = 'update '; 10 | exports.describe = 'Update CRM object'; 11 | 12 | exports.handler = async (options) => { 13 | const { objectType, objectId, ...properties } = options; 14 | 15 | if (!checkConfig()) { 16 | process.exit(1); 17 | } 18 | 19 | const res = await updateObject({ 20 | objectType: pluralize(objectType), 21 | objectId, 22 | properties: cleanupDefaultArgs(properties), 23 | }); 24 | }; 25 | 26 | exports.builder = (yargs) => { 27 | yargs.positional('objectType', { 28 | describe: 'CRM object type', 29 | type: 'string', 30 | choices: [ 31 | ...Object.values(AVAILABLE_OBJECT_TYPES), 32 | ...Object.keys(AVAILABLE_OBJECT_TYPES), 33 | ].sort(), 34 | coerce: (arg) => arg.toLowerCase(), 35 | }); 36 | 37 | yargs.positional('objectId', { 38 | describe: 'CRM object id', 39 | type: 'string', 40 | }); 41 | return yargs; 42 | }; 43 | -------------------------------------------------------------------------------- /node/src/config.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line node/no-unpublished-require 2 | require('dotenv').config({ path: '.env' }); 3 | const { logger } = require('./helpers/logger'); 4 | 5 | const checkConfig = () => { 6 | if (!process.env.ACCESS_TOKEN) { 7 | logger.error( 8 | 'Please, set .env file with access token, or use init command to authorize' 9 | ); 10 | return false; 11 | } 12 | return true; 13 | }; 14 | 15 | module.exports = { 16 | checkConfig, 17 | }; 18 | -------------------------------------------------------------------------------- /node/src/helpers/common.js: -------------------------------------------------------------------------------- 1 | const _ = require('lodash'); 2 | const fs = require('fs'); 3 | const { logger } = require('./logger'); 4 | 5 | const logResponse = (data) => { 6 | logger.log('Response from API', JSON.stringify(data, null, 1)); 7 | }; 8 | 9 | const cleanupDefaultArgs = (args) => 10 | _.omit(args, ['_', 'object-type', '$0', 'object-id']); 11 | 12 | const handleError = (e) => { 13 | if (_.isEqual(e.message, 'HTTP request failed')) { 14 | const errorMessage = JSON.stringify(e, null, 2); 15 | logger.error(errorMessage); 16 | } else { 17 | logger.error(e); 18 | } 19 | }; 20 | 21 | const jsonToEnv = (json) => { 22 | const variables = []; 23 | Object.entries(json).forEach(([key, value]) => { 24 | variables.push(`${key}=${value}`); 25 | }); 26 | return variables.join('\n'); 27 | }; 28 | 29 | const getEnvironmentConfigPath = () => { 30 | return `${process.cwd()}/.env`; 31 | }; 32 | 33 | const createEnvironmentFile = (config) => { 34 | const path = getEnvironmentConfigPath(); 35 | 36 | if (fs.existsSync(path)) { 37 | logger.log(`The .env file at ${path} already exists`); 38 | return; 39 | } 40 | 41 | try { 42 | logger.debug(`Writing current config to ${path}`); 43 | fs.writeFileSync(path, jsonToEnv(config)); 44 | } catch (err) { 45 | logger.error(err); 46 | } 47 | }; 48 | 49 | module.exports = { 50 | logResponse, 51 | handleError, 52 | createEnvironmentFile, 53 | getEnvironmentConfigPath, 54 | cleanupDefaultArgs, 55 | }; 56 | -------------------------------------------------------------------------------- /node/src/helpers/constants.js: -------------------------------------------------------------------------------- 1 | const AVAILABLE_OBJECT_TYPES = { 2 | contact: 'contacts', 3 | company: 'companies', 4 | ticket: 'tickets', 5 | deal: 'deals', 6 | product: 'products', 7 | }; 8 | 9 | module.exports = { 10 | AVAILABLE_OBJECT_TYPES, 11 | }; 12 | -------------------------------------------------------------------------------- /node/src/helpers/logger.js: -------------------------------------------------------------------------------- 1 | const chalk = require('chalk'); 2 | 3 | const LOG_LEVEL = { 4 | NONE: 0, 5 | DEBUG: 1, 6 | LOG: 2, 7 | WARN: 4, 8 | ERROR: 8, 9 | }; 10 | 11 | /** 12 | * Chalk styles for logger strings. 13 | */ 14 | const Styles = { 15 | debug: chalk.reset.blue, 16 | log: chalk.reset, 17 | success: chalk.reset.green, 18 | info: chalk.reset.white, 19 | warn: chalk.reset.yellow, 20 | error: chalk.reset.red, 21 | }; 22 | 23 | const stylize = (label, style, args) => { 24 | const styledLabel = style(label); 25 | const [firstArg, ...rest] = args; 26 | if (typeof firstArg === 'string') { 27 | return [`${styledLabel} ${firstArg}`, ...rest]; 28 | } 29 | return [styledLabel, ...args]; 30 | }; 31 | 32 | class Logger { 33 | error(...args) { 34 | console.error(...stylize('[ERROR]', Styles.error, args)); 35 | } 36 | warn(...args) { 37 | console.warn(...stylize('[WARNING]', Styles.warn, args)); 38 | } 39 | log(...args) { 40 | console.log(...args); 41 | } 42 | success(...args) { 43 | console.log(...stylize('[SUCCESS]', Styles.success, args)); 44 | } 45 | info(...args) { 46 | console.info(...stylize('[INFO]', Styles.info, args)); 47 | } 48 | debug(...args) { 49 | console.debug(...stylize('[DEBUG]', Styles.log, args)); 50 | } 51 | group(...args) { 52 | console.group(...args); 53 | } 54 | groupEnd(...args) { 55 | console.groupEnd(...args); 56 | } 57 | } 58 | 59 | let currentLogger = new Logger(); 60 | let currentLogLevel = LOG_LEVEL.LOG | LOG_LEVEL.WARN | LOG_LEVEL.ERROR; 61 | 62 | const shouldLog = (level) => { 63 | return currentLogLevel & level; 64 | }; 65 | 66 | const logger = { 67 | error(...args) { 68 | if (shouldLog(LOG_LEVEL.ERROR)) { 69 | currentLogger.error(...args); 70 | } 71 | }, 72 | warn(...args) { 73 | if (shouldLog(LOG_LEVEL.WARN)) { 74 | currentLogger.warn(...args); 75 | } 76 | }, 77 | log(...args) { 78 | if (shouldLog(LOG_LEVEL.LOG)) { 79 | currentLogger.log(...args); 80 | } 81 | }, 82 | success(...args) { 83 | if (shouldLog(LOG_LEVEL.LOG)) { 84 | currentLogger.success(...args); 85 | } 86 | }, 87 | info(...args) { 88 | if (shouldLog(LOG_LEVEL.LOG)) { 89 | currentLogger.info(...args); 90 | } 91 | }, 92 | debug(...args) { 93 | if (shouldLog(LOG_LEVEL.DEBUG)) { 94 | currentLogger.debug(...args); 95 | } 96 | }, 97 | group(...args) { 98 | currentLogger.group(...args); 99 | }, 100 | groupEnd(...args) { 101 | currentLogger.groupEnd(...args); 102 | }, 103 | }; 104 | 105 | module.exports = { 106 | logger, 107 | }; 108 | -------------------------------------------------------------------------------- /node/src/helpers/prompts.js: -------------------------------------------------------------------------------- 1 | const inquirer = require('inquirer'); 2 | 3 | const promptUser = async (promptConfig) => { 4 | const prompt = inquirer.createPromptModule(); 5 | return prompt(promptConfig); 6 | }; 7 | 8 | const overwritePrompt = (path) => { 9 | return inquirer.prompt({ 10 | type: 'confirm', 11 | name: 'overwrite', 12 | message: `The file '${path}' already exists. Overwrite?`, 13 | default: false, 14 | }); 15 | }; 16 | 17 | module.exports = { 18 | promptUser, 19 | overwritePrompt, 20 | }; 21 | -------------------------------------------------------------------------------- /node/src/sdk.js: -------------------------------------------------------------------------------- 1 | require('dotenv').config({ path: '.env' }); 2 | const _ = require('lodash'); 3 | const hubspot = require('@hubspot/api-client'); 4 | 5 | const { logResponse, handleError } = require('./helpers/common'); 6 | const { logger } = require('./helpers/logger'); 7 | 8 | const OBJECTS_LIMIT = 100; 9 | 10 | const hubspotClient = new hubspot.Client({ 11 | accessToken: process.env.ACCESS_TOKEN, 12 | }); 13 | 14 | const getAllObjects = async ({ objectType, query, properties}) => { 15 | const objects = []; 16 | let objectsResponse; 17 | let after; 18 | do { 19 | if (_.isNil(query) || _.isEmpty(query)) { 20 | // Get CRM Object 21 | // GET /crm/v3/objects/{objectType} 22 | // https://developers.hubspot.com/docs/api/crm/{objectType} 23 | logger.log( 24 | `Calling crm.${objectType}.basicApi.getPage API method. Retrieve ${objectType}` 25 | ); 26 | objectsResponse = await hubspotClient.crm[objectType].basicApi.getPage( 27 | OBJECTS_LIMIT, 28 | after, 29 | properties 30 | ); 31 | } else { 32 | // Search for CRM object 33 | // POST /crm/v3/objects/{objectType}/search 34 | // https://developers.hubspot.com/docs/api/crm/{objectType} 35 | logger.log( 36 | `Calling crm.${objectType}.searchApi.doSearch API method. Retrieve ${objectType} with search query:`, 37 | query 38 | ); 39 | objectsResponse = await hubspotClient.crm[objectType].searchApi.doSearch({ 40 | query, 41 | limit: OBJECTS_LIMIT, 42 | properties, 43 | filterGroups: [], 44 | after, 45 | }); 46 | } 47 | logResponse(objectsResponse); 48 | after = _.get(objectsResponse, 'paging.next.after'); 49 | objects.push(...objectsResponse.results); 50 | } while (!_.isNil(after)); 51 | 52 | return objects; 53 | }; 54 | 55 | const createObject = async ({ objectType, properties }) => { 56 | try { 57 | // Create CRM object 58 | // POST /crm/v3/objects/{objectType}/ 59 | // https://developers.hubspot.com/docs/api/crm/{objectType} 60 | logger.log( 61 | `Calling crm.${objectType}.basicApi.create API method. Create new ${objectType}` 62 | ); 63 | const createResponse = await hubspotClient.crm[objectType].basicApi.create({ 64 | properties, 65 | }); 66 | logResponse(createResponse); 67 | 68 | const objectId = _.get(createResponse, 'id'); 69 | logger.log(`Created ${objectType} with id ${objectId}`); 70 | return objectId; 71 | } catch (e) { 72 | handleError(e); 73 | } 74 | }; 75 | 76 | const archiveObject = async ({ objectId, objectType }) => { 77 | try { 78 | // Archive an object 79 | // DELETE /crm/v3/objects/{objectType}/:objectId 80 | // https://developers.hubspot.com/docs/api/crm/{objectType} 81 | logger.log( 82 | `Calling crm.${objectType}.basicApi.archive API method. Update ${objectType} with id:`, 83 | objectId 84 | ); 85 | const archiveResponse = await hubspotClient.crm[ 86 | objectType 87 | ].basicApi.archive(objectId); 88 | logResponse(archiveResponse); 89 | logger.log(`Archived ${objectType} with id ${objectId}`); 90 | return objectId; 91 | } catch (e) { 92 | handleError(e); 93 | } 94 | }; 95 | 96 | const updateObject = async ({ objectId, objectType, properties }) => { 97 | try { 98 | // Update an object 99 | // POST /crm/v3/objects/{objectType}/:objectId 100 | // https://developers.hubspot.com/docs/api/crm/{objectType} 101 | logger.log( 102 | `Calling crm.${objectType}.basicApi.update API method. Update ${objectType} with id:`, 103 | objectId 104 | ); 105 | logger.log(`Properties: ${JSON.stringify(properties)}`); 106 | const updateResponse = await hubspotClient.crm[ 107 | objectType 108 | ].basicApi.update(objectId, { properties }); 109 | logResponse(updateResponse); 110 | logger.log(`Updated ${objectType} with id ${objectId}`); 111 | return objectId; 112 | } catch (e) { 113 | handleError(e); 114 | } 115 | }; 116 | 117 | const getObject = async ({ objectId, objectType, properties }) => { 118 | try { 119 | if (_.isNil(objectId)) { 120 | logger.error(`Missed ${objectType}`); 121 | return; 122 | } 123 | 124 | // Get {objectType} record by its id 125 | // GET /crm/v3/objects/{objectType}/:objectId 126 | // https://developers.hubspot.com/docs/api/crm/{objectType} 127 | logger.log( 128 | `Calling crm.${objectType}.basicApi.getById API method. Retrieve ${objectType} by id:`, 129 | objectId 130 | ); 131 | 132 | const objectResponse = await hubspotClient.crm[objectType].basicApi.getById( 133 | objectId, 134 | properties 135 | ); 136 | logResponse(objectResponse); 137 | 138 | return objectResponse; 139 | } catch (e) { 140 | handleError(e); 141 | } 142 | }; 143 | 144 | const getProperties = async ({ objectType }) => { 145 | try { 146 | // Get All {ObjectType} Properties 147 | // GET /crm/v3/properties/:objectType 148 | // https://developers.hubspot.com/docs/api/crm/properties 149 | logger.log( 150 | 'Calling crm.properties.coreApi.getAll API method. Retrieve all contacts properties' 151 | ); 152 | const propertiesResponse = await hubspotClient.crm.properties.coreApi.getAll( 153 | objectType 154 | ); 155 | logResponse(propertiesResponse); 156 | 157 | return propertiesResponse.results; 158 | } catch (e) { 159 | handleError(e); 160 | } 161 | }; 162 | 163 | module.exports = { 164 | getAllObjects, 165 | getObject, 166 | getProperties, 167 | createObject, 168 | updateObject, 169 | archiveObject, 170 | }; 171 | -------------------------------------------------------------------------------- /php/.env.template: -------------------------------------------------------------------------------- 1 | ACCESS_TOKEN= 2 | -------------------------------------------------------------------------------- /php/.gitignore: -------------------------------------------------------------------------------- 1 | .php-cs-fixer.cache 2 | -------------------------------------------------------------------------------- /php/.php-cs-fixer.php: -------------------------------------------------------------------------------- 1 | in([__DIR__]) 5 | ->exclude(['vendor', 'var', 'codegen']) 6 | ->notPath('/cache/') 7 | ; 8 | 9 | $config = new PhpCsFixer\Config(); 10 | 11 | return $config 12 | ->setFinder($finder) 13 | ->setRules([ 14 | '@PSR2' => true, 15 | '@PhpCsFixer' => true, 16 | ]) 17 | ; 18 | -------------------------------------------------------------------------------- /php/README.md: -------------------------------------------------------------------------------- 1 | # HubSpot-php CRM-objects sample app 2 | 3 | ### Requirements 4 | 5 | 1. php >=7.2.5 6 | 2. [Configured](https://github.com/HubSpot/sample-apps-manage-crm-objects/blob/main/README.md#how-to-run-locally) .env file 7 | 8 | ### Running 9 | 10 | 1. Install dependencies 11 | 12 | ```bash 13 | composer i 14 | ``` 15 | 16 | 2. Initialize 17 | 18 | If .env config file was not configured manually there is a way to initialize the CLI and create .env file via: 19 | 20 | ```bash 21 | ./bin/cli.php app:init 22 | ``` 23 | 24 | It will ask for your Hubspot Api Key and will save it to the new .env config file. 25 | 26 | 3. Commands 27 | 28 | Show all commands 29 | 30 | ```bash 31 | ./bin/cli.php 32 | ``` 33 | Get All objects 34 | 35 | ```bash 36 | ./bin/cli.php objects:get [objectType] --all 37 | ``` 38 | 39 | Get an object by Id 40 | 41 | ```bash 42 | ./bin/cli.php objects:get [objectType] --id=[objectId] 43 | ``` 44 | 45 | Search an object by query 46 | 47 | ```bash 48 | ./bin/cli.php objects:get [objectType] --query=test 49 | ``` 50 | 51 | Create new object 52 | 53 | ```bash 54 | ./bin/cli.php objects:create [objectType] [properties] 55 | ``` 56 | 57 | For example: 58 | ```bash 59 | ./bin/cli.php objects:create companies name=newCompany city=Cambridge state=Massachusetts 60 | ``` 61 | 62 | Please also notice that some objects require mandatory properties. 63 | 64 | Update an object by Id 65 | 66 | ```bash 67 | ./bin/cli.php objects:update [objectType] [objectId] [properties] 68 | ``` 69 | For example: 70 | ```bash 71 | ./bin/cli.php objects:update contacts 123456 firstname=Ryan 72 | ``` 73 | 74 | Delete an object by Id 75 | 76 | ```bash 77 | ./bin/cli.php objects:delete [objectType] [objectId] 78 | ``` 79 | -------------------------------------------------------------------------------- /php/bin/cli.php: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | load(); 16 | } 17 | 18 | $application = new Application(); 19 | 20 | $application->add(new GetCommand()); 21 | $application->add(new CreateCommand()); 22 | $application->add(new DeleteCommand()); 23 | $application->add(new UpdateCommand()); 24 | $application->add(new InitCommand()); 25 | 26 | $application->run(); 27 | -------------------------------------------------------------------------------- /php/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "minimum-stability": "stable", 3 | "require": { 4 | "php": ">=7.2.5", 5 | "symfony/console": "^5.2", 6 | "vlucas/phpdotenv": "^5.3", 7 | "hubspot/api-client": "*" 8 | }, 9 | "require-dev": { 10 | "friendsofphp/php-cs-fixer": "~3.4.0" 11 | }, 12 | "autoload": { 13 | "psr-4": { 14 | "": "src/" 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /php/src/Commands/InitCommand.php: -------------------------------------------------------------------------------- 1 | setDescription('Configure ".env" file.'); 19 | } 20 | 21 | protected function execute(InputInterface $input, OutputInterface $output): int 22 | { 23 | $io = new SymfonyStyle($input, $output); 24 | 25 | if (!file_exists($this->envFileName)) { 26 | copy($this->envFileName.'.template', $this->envFileName); 27 | } elseif (!$io->confirm('The file ".env" already exists. Overwrite?')) { 28 | return Command::SUCCESS; 29 | } 30 | 31 | $accessToken = $this->askForAccessToken($io); 32 | 33 | $content = preg_replace( 34 | '/^ACCESS_TOKEN=.*$/m', 35 | 'ACCESS_TOKEN='.$accessToken, 36 | file_get_contents($this->envFileName) 37 | ); 38 | 39 | file_put_contents($this->envFileName, $content); 40 | 41 | $io->writeln('Access token was put to ".env" successfully.'); 42 | 43 | return Command::SUCCESS; 44 | } 45 | 46 | protected function askForAccessToken(SymfonyStyle $io): string 47 | { 48 | return $io->ask( 49 | 'Enter an access token for your account (found at https://app.hubspot.com/l/private-apps)', 50 | null, 51 | function ($key) { 52 | if (empty($key)) { 53 | throw new \RuntimeException('Access token can\'t be empty.'); 54 | } 55 | 56 | return $key; 57 | } 58 | ); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /php/src/Commands/Objects/CreateCommand.php: -------------------------------------------------------------------------------- 1 | setDescription('Create an object.'); 19 | 20 | $this->addPropertiesToCommand(); 21 | } 22 | 23 | protected function execute( 24 | InputInterface $input, 25 | OutputInterface $output 26 | ): int { 27 | $io = new SymfonyStyle($input, $output); 28 | $hubspot = HubspotClientHelper::createFactory(); 29 | 30 | $objectType = $this->getObjectType($input); 31 | $properties = $this->getProperties($input->getArgument('properties')); 32 | 33 | $io->writeln('Creating an object...'); 34 | 35 | $objectName = '\HubSpot\Client\Crm\\'.ucfirst($objectType).'\Model\SimplePublicObjectInput'; 36 | $object = new $objectName(); 37 | 38 | $object->setProperties($properties); 39 | 40 | $response = $hubspot->crm()->{$objectType}()->basicApi()->create($object); 41 | 42 | $io->info($response); 43 | 44 | return ObjectsCommand::SUCCESS; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /php/src/Commands/Objects/DeleteCommand.php: -------------------------------------------------------------------------------- 1 | setDescription('Delete an object by Id.'); 19 | 20 | $this->addIdToCommand(); 21 | } 22 | 23 | protected function execute( 24 | InputInterface $input, 25 | OutputInterface $output 26 | ): int { 27 | $io = new SymfonyStyle($input, $output); 28 | $hubspot = HubspotClientHelper::createFactory(); 29 | $objectType = $this->getObjectType($input); 30 | $objectId = $input->getArgument('id'); 31 | 32 | $io->writeln("Deleting an object with id: {$objectId}"); 33 | 34 | $hubspot->crm()->{$objectType}()->basicApi()->archive($objectId); 35 | 36 | return ObjectsCommand::SUCCESS; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /php/src/Commands/Objects/GetCommand.php: -------------------------------------------------------------------------------- 1 | setDescription('Get all objects, an object by Id or search an objects.'); 21 | 22 | $this 23 | ->addOption( 24 | 'all', 25 | null, 26 | InputOption::VALUE_NONE, 27 | 'Get all objects.' 28 | ) 29 | ; 30 | 31 | $this 32 | ->addOption( 33 | 'id', 34 | null, 35 | InputOption::VALUE_REQUIRED, 36 | 'Get object by Id.' 37 | ) 38 | ; 39 | 40 | $this 41 | ->addOption( 42 | 'query', 43 | null, 44 | InputOption::VALUE_REQUIRED, 45 | 'Search objects by query.' 46 | ) 47 | ; 48 | } 49 | 50 | protected function execute( 51 | InputInterface $input, 52 | OutputInterface $output 53 | ): int { 54 | $io = new SymfonyStyle($input, $output); 55 | $hubspot = HubspotClientHelper::createFactory(); 56 | $objectType = $this->getObjectType($input); 57 | 58 | if ($input->getOption('all')) { 59 | $io->writeln('Getting all objects...'); 60 | $objects = $hubspot->crm()->{$objectType}()->getAll(); 61 | 62 | $io->listing($objects); 63 | } elseif (!empty($input->getOption('id'))) { 64 | $io->writeln('Getting object by id...'); 65 | $object = $hubspot->crm()->{$objectType}()->basicApi()->getById($input->getOption('id')); 66 | 67 | $io->info($object); 68 | } elseif ($input->getOption('query')) { 69 | $io->writeln('Searching objects by query...'); 70 | 71 | $this->search($input->getOption('query'), $objectType, $hubspot, $io); 72 | } 73 | 74 | return ObjectsCommand::SUCCESS; 75 | } 76 | 77 | protected function search( 78 | string $query, 79 | string $objectType, 80 | Discovery $hubspot, 81 | SymfonyStyle $io 82 | ): void { 83 | $after = null; 84 | $object = '\HubSpot\Client\Crm\\'.ucfirst($objectType).'\Model\PublicObjectSearchRequest'; 85 | $request = new $object(['query' => $query]); 86 | $request->setLimit(100); 87 | 88 | do { 89 | $request->setAfter($after); 90 | $objects = $hubspot->crm()->{$objectType}()->searchApi()->doSearch($request); 91 | 92 | $io->listing($objects->getResults()); 93 | if ($objects->getPaging()) { 94 | $after = $objects->getPaging()->getNext()->getAfter(); 95 | } else { 96 | $after = null; 97 | } 98 | } while ($after); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /php/src/Commands/Objects/ObjectsCommand.php: -------------------------------------------------------------------------------- 1 | addArgument( 26 | 'objectType', 27 | InputArgument::REQUIRED, 28 | 'Enter object type ('.implode('|', $this->allowedObjectsTypes).')' 29 | ); 30 | } 31 | 32 | protected function getObjectType(InputInterface $input): string 33 | { 34 | $objectType = $input->getArgument('objectType'); 35 | 36 | if (!in_array($objectType, $this->allowedObjectsTypes)) { 37 | throw new \RuntimeException('Invalid Object Type. ('.implode('|', $this->allowedObjectsTypes).')'); 38 | } 39 | 40 | return $objectType; 41 | } 42 | 43 | protected function addPropertiesToCommand(): void 44 | { 45 | $this 46 | ->addArgument( 47 | 'properties', 48 | InputArgument::IS_ARRAY | InputArgument::REQUIRED, 49 | 'Enter Properties (separate multiple names with a space), for example firstname=Josh lastname=Green.' 50 | ) 51 | ; 52 | } 53 | 54 | protected function getProperties(array $elements): array 55 | { 56 | $properties = []; 57 | foreach ($elements as $element) { 58 | $array = explode('=', $element); 59 | if (static::KEY_VALUE_COUNT != count($array)) { 60 | throw new \RuntimeException('Invalid Element "'.$element.'".'); 61 | } 62 | $properties[$array[0]] = $array[1]; 63 | } 64 | 65 | return $properties; 66 | } 67 | 68 | protected function addIdToCommand(): void 69 | { 70 | $this 71 | ->addArgument( 72 | 'id', 73 | InputArgument::REQUIRED, 74 | 'Object`s Id.' 75 | ) 76 | ; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /php/src/Commands/Objects/UpdateCommand.php: -------------------------------------------------------------------------------- 1 | setDescription('Update an object.'); 19 | 20 | $this->addIdToCommand(); 21 | 22 | $this->addPropertiesToCommand(); 23 | } 24 | 25 | protected function execute( 26 | InputInterface $input, 27 | OutputInterface $output 28 | ): int { 29 | $io = new SymfonyStyle($input, $output); 30 | $hubspot = HubspotClientHelper::createFactory(); 31 | $objectId = $input->getArgument('id'); 32 | 33 | $objectType = $this->getObjectType($input); 34 | $properties = $this->getProperties($input->getArgument('properties')); 35 | 36 | $io->writeln("Updating an object with id: {$objectId}"); 37 | 38 | $objectName = '\HubSpot\Client\Crm\\'.ucfirst($objectType).'\Model\SimplePublicObjectInput'; 39 | $object = new $objectName(); 40 | 41 | $object->setProperties($properties); 42 | 43 | $response = $hubspot->crm()->{$objectType}()->basicApi()->update($objectId, $object); 44 | 45 | $io->info($response); 46 | 47 | return ObjectsCommand::SUCCESS; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /php/src/Helpers/HubspotClientHelper.php: -------------------------------------------------------------------------------- 1 | = 11.2' 6 | gem 'dotenv' 7 | gem 'pry' 8 | -------------------------------------------------------------------------------- /ruby/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | coderay (1.1.3) 5 | dotenv (2.8.1) 6 | ethon (0.16.0) 7 | ffi (>= 1.15.0) 8 | ffi (1.15.5) 9 | hubspot-api-client (16.0.4) 10 | json (~> 2.1, >= 2.1.0) 11 | typhoeus (~> 1.4.0) 12 | json (2.6.3) 13 | method_source (1.0.0) 14 | pry (0.14.1) 15 | coderay (~> 1.1) 16 | method_source (~> 1.0) 17 | typhoeus (1.4.0) 18 | ethon (>= 0.9.0) 19 | 20 | PLATFORMS 21 | ruby 22 | 23 | DEPENDENCIES 24 | dotenv 25 | hubspot-api-client (>= 11.2) 26 | pry 27 | 28 | RUBY VERSION 29 | ruby 3.1.3p185 30 | 31 | BUNDLED WITH 32 | 1.17.3 33 | -------------------------------------------------------------------------------- /ruby/README.md: -------------------------------------------------------------------------------- 1 | # HubSpot-ruby CRM-objects sample app 2 | 3 | ### Requirements 4 | 5 | 1. ruby 2.6.3 6 | 2. [Configured](https://github.com/HubSpot/sample-apps-manage-crm-objects/blob/main/README.md#how-to-run-locally) .env file 7 | 8 | ### Running 9 | 10 | 1. Install dependencies 11 | 12 | ``` 13 | bundle install 14 | ``` 15 | 16 | 2. Commands 17 | 18 | Show all commands (get help) 19 | 20 | ``` 21 | ruby cli.rb -h 22 | ``` 23 | 24 | Get objects 25 | 26 | ``` 27 | ruby cli.rb -m get_page -t [object_type] 28 | ``` 29 | 30 | Get an object by id 31 | 32 | ``` 33 | ruby cli.rb -m get_by_id -t [object_type] -i [object_id] 34 | ``` 35 | 36 | Create new object 37 | 38 | ``` 39 | ruby cli.rb -m create -t [object_type] -p [params] 40 | ``` 41 | 42 | Params is a json, example: 43 | 44 | ``` 45 | '{"email":"some@email.com","firstname":"Brian","lastname":"Halligan"}' 46 | ``` 47 | 48 | Delete an object by id 49 | 50 | ``` 51 | ruby cli.rb -m archive -t [object_type] -i [object_id] 52 | ``` 53 | 54 | Update an object by id 55 | 56 | ``` 57 | ruby cli.rb -m update -t [object_type] -i [object_id] -p [params] 58 | ``` 59 | 60 | Params is a json, example: 61 | 62 | ``` 63 | '{"firstname":"John}' 64 | ``` 65 | -------------------------------------------------------------------------------- /ruby/cli.rb: -------------------------------------------------------------------------------- 1 | require_relative 'config' 2 | require 'optparse' 3 | require 'ostruct' 4 | require 'json' 5 | 6 | class Cli 7 | REQUIRED_PARAMS = { 8 | archive: %i(object_type object_id), 9 | create: %i(object_type simple_public_object_input), 10 | get_by_id: %i(object_type object_id), 11 | get_page: %i(object_type), 12 | update: %i(object_type object_id simple_public_object_input) 13 | }.freeze 14 | 15 | def initialize(options) 16 | @options = options 17 | @method = options[:method]&.to_sym 18 | end 19 | 20 | def run 21 | validate 22 | call_api 23 | end 24 | 25 | private 26 | 27 | attr_reader :options, :method 28 | 29 | def validate 30 | raise ArgumentError 'Please, provide method to call with -m or --method' unless method 31 | missing_params = REQUIRED_PARAMS[method] - options.to_h.keys 32 | raise ArgumentError "Please, provide missing params #{missing_params} for the method. Use help (-h) if you need." if missing_params.any? 33 | end 34 | 35 | def call_api 36 | client = Hubspot::Client.new(access_token: access_token) 37 | api = client.crm.objects.basic_api 38 | api.public_send(method, params) 39 | end 40 | 41 | def params 42 | options.to_h.slice(*REQUIRED_PARAMS[method]) 43 | end 44 | end 45 | 46 | options = OpenStruct.new 47 | OptionParser.new do |opt| 48 | opt.on('-m', '--method METHOD', 'Method to run') { |o| options.method = o } 49 | opt.on('-t', '--type TYPE', 'The type of object') { |o| options.object_type = o } 50 | opt.on('-i', '--id ID', 'The id of object') { |o| options.object_id = o } 51 | opt.on('-p', '--properties PROPERTIES', 'Properties of object') { |o| options.simple_public_object_input = { properties: JSON.parse(o) } } 52 | opt.on('-o', '--options OPTIONS', 'Options to pass') { |o| options.opts = JSON.parse(o) } 53 | end.parse! 54 | 55 | p Cli.new(options).run 56 | -------------------------------------------------------------------------------- /ruby/config.rb: -------------------------------------------------------------------------------- 1 | # Load the gem 2 | require 'hubspot-api-client' 3 | require 'dotenv' 4 | 5 | Dotenv.load 6 | 7 | def access_token 8 | ENV['ACCESS_TOKEN'] 9 | end 10 | --------------------------------------------------------------------------------