├── .github └── workflows │ └── npm.yml ├── .gitignore ├── .npmignore ├── .prettierrc ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── jest.config.js ├── logo.png ├── package-lock.json ├── package.json ├── src ├── index.ts ├── scraping-actions │ ├── AddCookies.ts │ ├── Click.ts │ ├── Press.ts │ ├── Remove.ts │ ├── Scroll.ts │ ├── Select.ts │ ├── Type.ts │ ├── Wait.ts │ └── index.ts ├── scraping-strategies │ ├── ScreenshotToMap.ts │ ├── TextContentScraping.ts │ └── index.ts ├── types.ts └── utils │ ├── browser-config.ts │ └── utils.ts ├── tests ├── scraper.test.ts ├── screenshotToMap.spec.ts └── templates │ ├── actions.html │ ├── pricing.css │ └── pricing.html └── tsconfig.json /.github/workflows/npm.yml: -------------------------------------------------------------------------------- 1 | name: Publish to NPM 2 | on: 3 | push: 4 | branches: [ main, master ] 5 | 6 | jobs: 7 | test: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v3 11 | - uses: actions/setup-node@v3 12 | with: 13 | node-version: 16 14 | - run: npm ci 15 | - run: npm test 16 | build: 17 | needs: test 18 | runs-on: ubuntu-latest 19 | steps: 20 | - uses: actions/checkout@v3 21 | - uses: actions/setup-node@v3 22 | with: 23 | node-version: 16 24 | - run: npm ci 25 | - run: npm run build 26 | - uses: JS-DevTools/npm-publish@v1 27 | with: 28 | token: ${{ secrets.NPM_TOKEN }} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | .pnpm-debug.log* 9 | 10 | # Diagnostic reports (https://nodejs.org/api/report.html) 11 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 12 | 13 | # Runtime data 14 | pids 15 | *.pid 16 | *.seed 17 | *.pid.lock 18 | 19 | # Directory for instrumented libs generated by jscoverage/JSCover 20 | lib-cov 21 | 22 | # Coverage directory used by tools like istanbul 23 | coverage 24 | *.lcov 25 | 26 | # nyc test coverage 27 | .nyc_output 28 | 29 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 30 | .grunt 31 | 32 | # Bower dependency directory (https://bower.io/) 33 | bower_components 34 | 35 | # node-waf configuration 36 | .lock-wscript 37 | 38 | # Compiled binary addons (https://nodejs.org/api/addons.html) 39 | build/Release 40 | 41 | # Dependency directories 42 | node_modules/ 43 | jspm_packages/ 44 | 45 | # Snowpack dependency directory (https://snowpack.dev/) 46 | web_modules/ 47 | 48 | # TypeScript cache 49 | *.tsbuildinfo 50 | 51 | # Optional npm cache directory 52 | .npm 53 | 54 | # Optional eslint cache 55 | .eslintcache 56 | 57 | # Optional stylelint cache 58 | .stylelintcache 59 | 60 | # Microbundle cache 61 | .rpt2_cache/ 62 | .rts2_cache_cjs/ 63 | .rts2_cache_es/ 64 | .rts2_cache_umd/ 65 | 66 | # Optional REPL history 67 | .node_repl_history 68 | 69 | # Output of 'npm pack' 70 | *.tgz 71 | 72 | # Yarn Integrity file 73 | .yarn-integrity 74 | 75 | # dotenv environment variable files 76 | .env 77 | .env.development.local 78 | .env.test.local 79 | .env.production.local 80 | .env.local 81 | 82 | # parcel-bundler cache (https://parceljs.org/) 83 | .cache 84 | .parcel-cache 85 | 86 | # Next.js build output 87 | .next 88 | out 89 | 90 | # Nuxt.js build / generate output 91 | .nuxt 92 | dist 93 | 94 | # Gatsby files 95 | .cache/ 96 | # Comment in the public line in if your project uses Gatsby and not Next.js 97 | # https://nextjs.org/blog/next-9-1#public-directory-support 98 | # public 99 | 100 | # vuepress build output 101 | .vuepress/dist 102 | 103 | # vuepress v2.x temp and cache directory 104 | .temp 105 | .cache 106 | 107 | # Docusaurus cache and generated files 108 | .docusaurus 109 | 110 | # Serverless directories 111 | .serverless/ 112 | 113 | # FuseBox cache 114 | .fusebox/ 115 | 116 | # DynamoDB Local files 117 | .dynamodb/ 118 | 119 | # TernJS port file 120 | .tern-port 121 | 122 | # Stores VSCode versions used for testing VSCode extensions 123 | .vscode-test 124 | 125 | # yarn v2 126 | .yarn/cache 127 | .yarn/unplugged 128 | .yarn/build-state.yml 129 | .yarn/install-state.gz 130 | .pnp.* 131 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | .github 3 | tests -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 100, 3 | "useTabs": true 4 | } -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | ## [0.2.0] — 2022-06-13 6 | 7 | ### Added 8 | 9 | - Remove action: it removes an element from the DOM. It can be useful when dealing with consent pop-ups. 10 | 11 | ## [0.1.0] — 2022-06-11 12 | 13 | ### Added 14 | 15 | - ScreenshotToMap strategy (retrieve screenshot and maps with selectors for the specified elements). 16 | 17 | ### Changed 18 | 19 | - You can now run the scraper without a strategy. It will only run the actions and return the playwright instances of Browser, BrowserContext, and Page. 20 | 21 | ## [0.0.1] — 2022-06-10 22 | 23 | ### Added 24 | 25 | - First release 26 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Alex Ferrari 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![ScrapeBlocks Logo](logo.png) 2 | 3 |
4 | 5 | [![MIT License](https://img.shields.io/apm/l/atomic-design-ui.svg?)](https://github.com/tterb/atomic-design-ui/blob/master/LICENSEs) 6 | [![NPM Version](https://img.shields.io/npm/v/scrapeblocks?style=flat-square)](https://www.npmjs.com/package/scrapeblocks) 7 | [![lgtm Code Quality](https://img.shields.io/lgtm/grade/javascript/github/alexferrari88/scrapeblocks?style=flat-square)](https://lgtm.com/projects/g/alexferrari88/scrapeblocks/) 8 | [![GitHub Last Commit](https://img.shields.io/github/last-commit/alexferrari88/scrapeblocks?style=flat-square)](https://img.shields.io/github/last-commit/alexferrari88/scrapeblocks?style=flat-square) 9 | 10 |
11 | 12 | # ScrapeBlocks 13 | 14 | ScrapeBlocks is a layer on top of Playwright to make scraping automation easier. 15 | 16 | You can set actions to be performed before starting scraping and you can also decide which scraping strategy to use. 17 | 18 | Start with predefined actions and strategies in a matter of minutes. You can also write your own or use ones from the community. 19 | 20 | ## Who is this for? 🤔 21 | 22 | - I just want to start scraping right now with little effort as possible 23 | - I have a complicated scraping workflow that I want to simplify with still getting the same results 24 | - I like to tinker with scraping and build my custom workflows 25 | 26 | With ScrapeBlocks getting started with scraping is a matter of minutes. 27 | 28 | You can use it with its batteries included or as extension to Playwright. 29 | 30 | Whether you are a scraping-hero or just want to monitor the price for that product but you don't know much about scraping, ScrapeBlocks is here for you. 31 | 32 | ## Features 🚀 33 | 34 | - **Pre-scraping actions**: perform actions before running a scraping strategy 35 | - Example use-case: you need to click something before your target becomes visible 36 | - **Plug-n-play**: write your own scraping strategies or use those from the community 37 | - Example use-cases: scrape for text of certain elements, get all the images, etc. 38 | - **Fully customizible (or not)**: you can use it batteries included or use your own Playwright instances 39 | - **Easy to start with**: it's based on Playwright! 40 | 41 | ### Actions included ⚡ 42 | 43 | - [Click on any element](src/scraping-actions/Click.ts) 44 | - [Add cookie](src/scraping-actions/AddCookies.ts) 45 | - [Remove an element](src/scraping-actions/Remove.ts) 46 | - [Type anywhere you can type something](src/scraping-actions/Type.ts) 47 | - [Press keyboard buttons (e.g. Enter, CTRL+C, etc.)](src/scraping-actions/Press.ts) 48 | - [Scroll to bottom of the page](src/scraping-actions/Scroll.ts) 49 | - [Wait a certain amount of time](src/scraping-actions/Wait.ts) 50 | - [Select](src/scraping-actions/Select.ts) any option from a ` 16 | 17 |
18 |

You typed:

19 | 20 | 21 | 26 |
27 | 28 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /tests/templates/pricing.css: -------------------------------------------------------------------------------- 1 | body{ 2 | padding:0; 3 | margin: 0; 4 | background:#1E1E21; 5 | color:#fff; 6 | } 7 | h2{ 8 | font-size: 30px; 9 | color:#fff; 10 | } 11 | p{ 12 | color:rgb(238, 231, 231); 13 | } 14 | .has-tooltip:not(.tooltip-disabled) { 15 | cursor: help; 16 | position:relative; 17 | } 18 | 19 | .has-tooltip:not(.tooltip-disabled):hover 20 | .tooltip-container { 21 | display: block; 22 | } 23 | 24 | .has-tooltip .tooltip-container { 25 | display: none; 26 | position: absolute; 27 | background-color: #BE3760; 28 | color:#fff; 29 | z-index: 20; 30 | bottom: calc(100% + 13px); 31 | left: -10px; 32 | right: -10px; 33 | padding: 16px 20px; 34 | border-radius: 8px; 35 | 36 | } 37 | .has-tooltip .tooltip-container:after { 38 | width: 0; 39 | height: 0; 40 | border-left: 10px solid transparent; 41 | border-right: 10px solid transparent; 42 | border-top: 10px solid #BE3760; 43 | font-size: 0; 44 | line-height: 0; 45 | content: ""; 46 | position: absolute; 47 | bottom: -10px; 48 | } 49 | 50 | .has-tooltip .tooltip-container h6 { 51 | font-weight: 600; 52 | font-size: 16px; 53 | margin: 0px; 54 | } 55 | 56 | .has-tooltip .tooltip-container { 57 | color: #555; 58 | margin-top:4px; 59 | } 60 | /* - - - - - - - End Tooltips - - - */ 61 | 62 | 63 | 64 | 65 | 66 | #pricing-container * { 67 | box-sizing:border-box; 68 | } 69 | 70 | #pricing-container { 71 | font-family: "Open Sans", Helvetica, Arial, Lucida, sans-serif; 72 | -webkit-font-smoothing: antialiased; 73 | max-width: 1080px; 74 | margin: 0 auto 50px; 75 | justify-content: center; 76 | line-height: 1; 77 | color: #000; 78 | } 79 | 80 | 81 | 82 | /* Cards */ 83 | 84 | #pricing-cards { 85 | display: flex; 86 | font-size: 14px; 87 | } 88 | 89 | #pricing-container .price-card { 90 | background-color: #33333a; 91 | color:#fff; 92 | font-family: "Open Sans", Helvetica, Arial, Lucida, sans-serif; 93 | display: block; 94 | box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.12), 0 1px 5px 0 rgba(0, 0, 0, 0.2); 95 | transition: all 0.25s; 96 | position: relative; 97 | margin: 0 6px; 98 | flex-grow: 1; 99 | flex-shrink:1; 100 | } 101 | 102 | #pricing-container .price-card:hover { 103 | transform: translateY(-5px); 104 | box-shadow: 0 6px 20px 0 rgba(0, 0, 0, 0.14), 105 | 0 3px 1px -2px rgba(0, 0, 0, 0.12), 0 1px 5px 0 rgba(0, 0, 0, 0.2); 106 | } 107 | 108 | 109 | /* - - - - - - - - - Header Section - - - */ 110 | 111 | #pricing-container .price-card--header { 112 | 113 | margin: 0; 114 | padding: 20px 0; 115 | text-align: center; 116 | } 117 | 118 | #pricing-container .price-card--header h4 { 119 | margin: 0; 120 | padding: 0; 121 | font-size: 28px; 122 | color: #fff; 123 | font-family: "Raleway", Helvetica, Arial, Lucida, sans-serif; 124 | font-weight: 700; 125 | } 126 | 127 | 128 | /* - - - - - - - - - Price Section - - - */ 129 | 130 | #pricing-container .price-card--price { 131 | text-align: center; 132 | padding: 28px 0 6px 0; 133 | } 134 | 135 | #pricing-container .price-card--price-text { 136 | font-size: 48px; 137 | } 138 | 139 | #pricing-container .price-card--price-number { 140 | font-weight: 500; 141 | opacity: 0.89; 142 | } 143 | 144 | .odometer div { 145 | display: inline-block; 146 | } 147 | 148 | #pricing-container .price-card--price-number:before { 149 | content: "$"; 150 | font-size: 24px; 151 | top: -16px; 152 | display: inline-block; 153 | position: relative; 154 | } 155 | 156 | #pricing-container .price-card--price-number:after { 157 | content: "/month"; 158 | font-size: 12px; 159 | display: inline-block; 160 | color: grey; 161 | } 162 | 163 | #pricing-container .price-card--price-conditions { 164 | padding: 14px 0; 165 | color: #888; 166 | line-height: 1.5; 167 | } 168 | 169 | 170 | 171 | 172 | /* - - - - - - - - - CTA Button Section - - - */ 173 | 174 | #pricing-container .price-card--cta { 175 | padding: 0 20px 24px; 176 | text-align: center; 177 | } 178 | 179 | #pricing-container .price-card--cta--button.btn{ 180 | min-width:20px; 181 | display:block; 182 | max-width:183px; 183 | margin:0 auto; 184 | } 185 | 186 | 187 | 188 | 189 | 190 | /* - - - - - - - - - Features Section - - - */ 191 | 192 | #pricing-container .price-card--features { 193 | 194 | padding: 16px 0 20px; 195 | } 196 | 197 | #pricing-container ul.price-card--features--list { 198 | padding: 0 32px; 199 | list-style: none; 200 | margin: 0; 201 | } 202 | 203 | #pricing-container li.price-card--features--item { 204 | margin: 8px 0; 205 | padding-left: 8px; 206 | line-height: 1.5; 207 | position: relative; 208 | } 209 | 210 | #pricing-container 211 | li.price-card--features--item:not(.features-disabled):before { 212 | content: "✓"; 213 | color: #BE3760; 214 | display: block; 215 | position: absolute; 216 | left: -8px; 217 | } 218 | 219 | #pricing-container li.price-card--features--item.features-highlight { 220 | /* font-weight: 600; */ 221 | } 222 | 223 | #pricing-container li.price-card--features--item.features-disabled { 224 | opacity: 0.1; 225 | /* text-decoration: line-through; */ 226 | } 227 | 228 | 229 | 230 | 231 | /* - - - - - - - - - Mobile Features Toggle - - - */ 232 | 233 | #pricing-container .price-card--mobile-features-toggle { 234 | text-align: center; 235 | margin: 24px 0 0; 236 | padding: 16px 0; 237 | cursor: pointer; 238 | display: none; 239 | color: green; 240 | } 241 | 242 | #pricing-container .price-card--mobile-features-toggle:after { 243 | content: "Show All Features ▾"; 244 | } 245 | #pricing-container .price-card--mobile-features-toggle.hideall:after { 246 | content: "Hide Features ▴"; 247 | } 248 | 249 | /* - - - - - - - - - Hero Card Styles - - - */ 250 | 251 | #pricing-container .price-card--hero { 252 | margin: -38px 6px 0; 253 | /* width:31%; */ 254 | z-index: 10; 255 | } 256 | 257 | #pricing-container .price-card--hero-text { 258 | background-color: #BE3760; 259 | height: 38px; 260 | color: white; 261 | line-height: 38px; 262 | text-align: center; 263 | font-weight: 600; 264 | } 265 | 266 | /* - - - - - - - - - Only Yearly Basic Styles - - - */ 267 | 268 | #pricing-container .only-yearly { 269 | position: relative; 270 | } 271 | 272 | #pricing-container .only-yearly .price-card--price-number { 273 | transition: opacity 0.2s; 274 | } 275 | 276 | #pricing-container .only-yearly .only-yearly--text { 277 | position: absolute; 278 | top: -0.2em; 279 | left: 0; 280 | right: 0; 281 | display: none; 282 | } 283 | #pricing-container .only-yearly .only-yearly--text span { 284 | font-size: 14px; 285 | } 286 | 287 | #pricing-container .only-yearly.if-monthly .price-card--price-number { 288 | opacity: 0; 289 | } 290 | 291 | #pricing-container .only-yearly.if-monthly .only-yearly--text { 292 | display: block; 293 | } 294 | 295 | /* - - - - - - - - - Switch Section - - - */ 296 | 297 | #pricing-switch { 298 | margin: 80px auto 100px; 299 | text-align: center; 300 | line-height: 1.4; 301 | position: relative; 302 | max-width: 1080px; 303 | } 304 | 305 | #pricing-switch .switch-label { 306 | display: inline-block; 307 | width: 200px; 308 | text-align: center; 309 | opacity: 0.4; 310 | font-size: 16px; 311 | cursor: pointer; 312 | padding: 0 20px; 313 | } 314 | 315 | #pricing-switch .switch-label .save-money { 316 | color: #4caf50; 317 | font-style: italic; 318 | padding-left: 8px; 319 | } 320 | #pricing-switch .save-money--mobile { 321 | color: #4caf50; 322 | font-style: italic; 323 | padding-top: 22px; 324 | display: none; 325 | } 326 | 327 | #pricing-switch .switch-label.active { 328 | font-size: 18px; 329 | opacity: 1; 330 | } 331 | #pricing-switch .switch-label-monthly { 332 | text-align: right; 333 | } 334 | #pricing-switch .switch-label-yearly { 335 | text-align: left; 336 | } 337 | 338 | #pricing-switch .switch { 339 | position: relative; 340 | display: inline-block; 341 | width: 60px; 342 | height: 34px; 343 | vertical-align: -50%; 344 | margin: 0; 345 | } 346 | 347 | #pricing-switch .switch input { 348 | display: none; 349 | } 350 | 351 | #pricing-switch .slider { 352 | position: absolute; 353 | cursor: pointer; 354 | top: 0; 355 | left: 0; 356 | right: 0; 357 | bottom: 0; 358 | background-color: #BE3760; 359 | border-radius: 34px; 360 | -webkit-transition: 0.1s; 361 | transition: 0.1s; 362 | } 363 | 364 | #pricing-switch .slider:before { 365 | position: absolute; 366 | content: ""; 367 | height: 26px; 368 | width: 26px; 369 | left: 4px; 370 | bottom: 4px; 371 | background-color: white; 372 | border-radius: 50%; 373 | -webkit-transition: 0.1s; 374 | transition: 0.1s; 375 | } 376 | 377 | .btn{ 378 | width: 200px; 379 | height:45px; 380 | background: transparent; 381 | border:1px solid #BE3760; 382 | color:#fff; 383 | border-radius: 5px; 384 | cursor: pointer; 385 | margin:2em 5em; 386 | } 387 | .btn-pro{ 388 | width: 200px; 389 | height:45px; 390 | background: #BE3760; 391 | border:none; 392 | color:#fff; 393 | border-radius: 5px; 394 | cursor: pointer; 395 | margin:2em 5em; 396 | } 397 | .switch-label{ 398 | color:#fff; 399 | } 400 | .active{ 401 | color: #BE3760; 402 | } 403 | strong{ 404 | color:#fff; 405 | } -------------------------------------------------------------------------------- /tests/templates/pricing.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Test Page 10 | 11 | 12 | 13 |
14 | 15 |
16 |

Choose a plan

17 | Monthly 18 | 22 | Yearly 23 | 24 |
Save 10% on Yearly Plans
25 | 26 |
27 | 28 | 29 |
30 | 31 | 32 | 33 | 34 |
35 | 36 |
37 |

Premium

38 | 39 |
40 | 41 |
42 |
43 |
2,250
45 |
46 |
47 |
Billed Annually
49 | 50 |
51 |
52 | 53 | 54 | 55 |
56 | 57 |
    58 |
  • Sales & Marketing Platform 59 |
    Sales & Marketing Platform 60 |

    Vendasta's end-to-end sales solution for companies that serve local businesses, and 61 | want to grow digital revenue.

    62 |
    63 |
  • 64 |
  • Snapshot & Campaigns 65 |
    Snapshot & Campaigns 66 |

    Access to award-winning automated needs-assessment and email marketing automation. 67 | Unlimited emails sent to unlimited accounts.

    68 |
    69 |
  • 70 |
  • Marketplace 71 |
    Marketplace 72 |

    Access to world-class resellable products & services, aimed to fulfilling the digital 73 | marketing needs of your small & medium sized business clients.

    74 |
    75 |
  • 76 |
  • Business Center & Store 77 |
    Business Center & Store 78 |

    Portal for your local business clients, featuring your agency’s branding. They can 79 | access the products purchased from your Marketplace.

    80 |
    81 |
  • 82 | 83 |
  • Tech support 84 |
    Tech support 85 |

    Phone, Email and Web Chat support,
    9am-9pm EST Mon-Fri,
    2pm-7pm EST 86 | Sat-Sun

    87 |
    88 |
  • 89 |
  • Partner Success Manager 90 |
    Partner Success Manager 91 |

    One-on-one with a Vendasta Success Manager, who will provide sales training so you 92 | reach your goals quickly.

    93 |
    94 |
  • 95 | 96 | 97 |
98 | 99 |
100 | 101 |
102 | 103 |
104 | 105 | 106 | 107 | 108 | 109 |
110 | 111 |
112 |

Enterprise

113 | 114 |
115 |
116 | Most Popular Plan 117 |
118 | 119 |
120 |
121 |
900
123 |
124 |
125 |
Billed Annually
127 | 128 |
129 |
130 | 131 |
132 |
    133 | 134 |
  • Sales & Marketing Platform 135 |
    Sales & Marketing Platform 136 |

    Vendasta's end-to-end sales solution for companies that serve local businesses, and 137 | want to grow digital revenue.

    138 |
    139 |
  • 140 |
  • Snapshot & Campaigns 141 |
    Snapshot & Campaigns 142 |

    Access to award-winning automated needs-assessment and email marketing automation. 143 | Unlimited emails sent to unlimited accounts.

    144 |
    145 |
  • 146 |
  • Marketplace 147 |
    Marketplace 148 |

    Access to world-class resellable products & services, aimed to fulfilling the digital 149 | marketing needs of your small & medium sized business clients.

    150 |
    151 |
  • 152 |
  • Business Center & Store 153 |
    Business Center & Store 154 |

    Portal for your local business clients, featuring your agency’s branding. They can 155 | access the products purchased from your Marketplace.

    156 |
    157 |
  • 158 | 159 |
  • Tech support 160 |
    Tech support 161 |

    Phone, Email and Web Chat support,
    9am-9pm EST Mon-Fri,
    2pm-7pm EST 162 | Sat-Sun

    163 |
    164 |
  • 165 |
  • Partner Success Manager 166 |
    Partner Success Manager 167 |

    One-on-one with a Vendasta Success Manager, who will provide sales training so you 168 | reach your goals quickly.

    169 |
    170 |
  • 171 | 172 | 173 |
174 | 175 |
176 | 177 |
178 | 179 |
180 | 181 |
182 | 183 |
184 |

Basic

185 | 186 |
187 | 188 |
189 |
190 |
249
191 |
Only Available Yearly
192 |
193 |
194 |
Billed Annually
195 | 196 |
197 |
198 | 199 | 200 | 201 |
202 |
    203 | 204 |
  • Sales & Marketing Platform 205 |
    Sales & Marketing Platform 206 |

    Vendasta's end-to-end sales solution for companies that serve local businesses, and 207 | want to grow digital revenue.

    208 |
    209 |
  • 210 |
  • Snapshot & Campaigns 211 |
    Snapshot & Campaigns 212 |

    Access to award-winning automated needs-assessment and email marketing automation. 213 | Unlimited emails sent to unlimited accounts.

    214 |
    215 |
  • 216 |
  • Marketplace 217 |
    Marketplace 218 |

    Access to world-class resellable products & services, aimed to fulfilling the digital 219 | marketing needs of your small & medium sized business clients.

    220 |
    221 |
  • 222 |
  • Business Center & Store 223 |
    Business Center & Store 224 |

    Portal for your local business clients, featuring your agency’s branding. They can 225 | access the products purchased from your Marketplace.

    226 |
    227 |
  • 228 |
  • Tech support (limited) 229 |
    Tech support (limited) 230 |

    Email and Web Chat support,
    9am-9pm EST Mon-Fri,
    2pm-7pm EST Sat-Sun

    231 |
    232 |
  • 233 | 234 |
  • Partner 235 | Success Manager 236 |
    Partner Success Manager 237 |

    One-on-one with a Vendasta Success Manager, who will provide sales training so you 238 | reach your goals quickly.

    239 |
    240 |
  • 241 | 242 |
243 | 244 |
245 | 246 |
247 | 248 |
249 | 250 | 251 |
252 | 253 | 254 | 255 |
256 | 257 | 258 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig to read more about this file */ 4 | 5 | /* Projects */ 6 | // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ 7 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ 8 | // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ 9 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ 10 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ 11 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ 12 | 13 | /* Language and Environment */ 14 | "target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, 15 | // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ 16 | // "jsx": "preserve", /* Specify what JSX code is generated. */ 17 | // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ 18 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ 19 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ 20 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ 21 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ 22 | // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ 23 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ 24 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ 25 | // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ 26 | 27 | /* Modules */ 28 | "module": "commonjs" /* Specify what module code is generated. */, 29 | // "rootDir": "./", /* Specify the root folder within your source files. */ 30 | // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ 31 | // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ 32 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ 33 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ 34 | // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ 35 | // "types": [], /* Specify type package names to be included without being referenced in a source file. */ 36 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 37 | // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ 38 | // "resolveJsonModule": true, /* Enable importing .json files. */ 39 | // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ 40 | 41 | /* JavaScript Support */ 42 | // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ 43 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ 44 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ 45 | 46 | /* Emit */ 47 | "declaration": true /* Generate .d.ts files from TypeScript and JavaScript files in your project. */, 48 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */ 49 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ 50 | "sourceMap": true /* Create source map files for emitted JavaScript files. */, 51 | // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ 52 | "outDir": "./dist" /* Specify an output folder for all emitted files. */, 53 | // "removeComments": true, /* Disable emitting comments. */ 54 | // "noEmit": true, /* Disable emitting files from a compilation. */ 55 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ 56 | // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ 57 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ 58 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ 59 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 60 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ 61 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ 62 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ 63 | // "newLine": "crlf", /* Set the newline character for emitting files. */ 64 | // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ 65 | // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ 66 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ 67 | // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ 68 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ 69 | // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ 70 | 71 | /* Interop Constraints */ 72 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ 73 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ 74 | "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, 75 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ 76 | "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, 77 | 78 | /* Type Checking */ 79 | "strict": true /* Enable all strict type-checking options. */, 80 | // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ 81 | // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ 82 | // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ 83 | // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ 84 | // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ 85 | // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ 86 | // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ 87 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ 88 | // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ 89 | // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ 90 | // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ 91 | // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ 92 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ 93 | // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ 94 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ 95 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ 96 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ 97 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ 98 | 99 | /* Completeness */ 100 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ 101 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 102 | }, 103 | "include": ["src/**/*.ts"] 104 | } 105 | --------------------------------------------------------------------------------