Compare commits

..

42 Commits

Author SHA1 Message Date
github-actions[bot] 381f1f7505 chore: release 1.4.0 (#66)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2020-09-19 18:17:27 -04:00
Jef LeCompte ebbdfe3f63 perf: browser abstraction (#68) (#81)
Signed-off-by: Jef LeCompte <jeffreylec@gmail.com>
2020-09-19 18:13:20 -04:00
Jef LeCompte 14b1e4cee6 chore: add discord badge, update includes-labels
Signed-off-by: Jef LeCompte <jeffreylec@gmail.com>
2020-09-19 18:01:36 -04:00
vmnt 433fa8ca9f chore(logging): reformat output (#74)
Co-authored-by: Jef LeCompte <jeffreylec@gmail.com>
2020-09-19 17:47:55 -04:00
Jef LeCompte cf0e959fb4 refactor: store naming and map reference
Signed-off-by: Jef LeCompte <jeffreylec@gmail.com>
2020-09-19 17:43:53 -04:00
Jef LeCompte 8c5d7d0c49 refactor: env, cartUrl optional, other consistencies
Signed-off-by: Jef LeCompte <jeffreylec@gmail.com>
2020-09-19 17:36:33 -04:00
Mark Dietzer 393d5f6898 feat(notification): add telegram (#71) 2020-09-19 17:02:00 -04:00
anethema d4de1a4638 feat(store): add amazon.ca, fix timeout (#75) 2020-09-19 17:00:14 -04:00
Thomas Herrell c85658bf82 feat(notification): add pushover (#55)
Co-authored-by: Jef LeCompte <jeffreylec@gmail.com>
2020-09-19 15:55:21 -04:00
Cody Stammers 8aba7ecbdb feat(notification): add mint mobile carrier (#70) 2020-09-19 15:53:39 -04:00
Jef LeCompte ccc781b8dd docs: better format for carriers
Signed-off-by: Jef LeCompte <jeffreylec@gmail.com>
2020-09-19 13:10:09 -04:00
Jef LeCompte 6be74a19f3 feat(notification): add telus sms
Signed-off-by: Jef LeCompte <jeffreylec@gmail.com>
2020-09-19 13:07:53 -04:00
Jef LeCompte dcda82bd98 hotfix: lint
Signed-off-by: Jef LeCompte <jeffreylec@gmail.com>
2020-09-19 12:45:47 -04:00
Jef LeCompte ea5b7a0918 refactor: lookup, rm defaults (#69)
prep work for #38

Signed-off-by: Jef LeCompte <jeffreylec@gmail.com>
2020-09-19 12:45:03 -04:00
Gylfi 3b2ba29cf1 chore(store): add bandh links (#65)
Co-authored-by: Jef LeCompte <jeffreylec@gmail.com>
2020-09-19 11:23:49 -04:00
Evan Gentis a21740942b feat: webpage toggle, sound notification, fix evga links (#52)
Co-authored-by: Evan Gentis <evan.gentis@gmail.com>
Co-authored-by: Jef LeCompte <jeffreylec@gmail.com>
2020-09-19 10:42:40 -04:00
Jef LeCompte 25643c4870 refactor: map sms, fix amazon text
Signed-off-by: Jef LeCompte <jeffreylec@gmail.com>
2020-09-19 10:28:31 -04:00
Jef LeCompte ef319d4b20 chore: update issue templates
Signed-off-by: Jef LeCompte <jeffreylec@gmail.com>
2020-09-19 10:05:19 -04:00
github-actions[bot] fcb279d5de chore: release 1.3.0 (#62)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2020-09-19 09:17:46 -04:00
admon84 5c9e0b6d06 fix(store): amazon captcha false-positives (#54)
Co-authored-by: Jef LeCompte <jeffreylec@gmail.com>
2020-09-19 09:02:11 -04:00
Ruochong Wu 6c3cd01685 feat(logging): add timestamp (#48)
Co-authored-by: Jef LeCompte <jeffreylec@gmail.com>
2020-09-19 08:49:22 -04:00
Kevin Tong d907092b44 fix: evga xc3 ultra link (#56)
Co-authored-by: Jef LeCompte <jeffreylec@gmail.com>
2020-09-19 08:43:45 -04:00
admon84 7cfc7c7442 fix: screenshot size, add screenshot config setting (#53) 2020-09-19 08:37:20 -04:00
admon84 971fec20e4 fix: sms carrier config, add google carrier (#44) 2020-09-18 21:39:30 -04:00
github-actions[bot] d73449dd7f chore: release 1.2.0 (#31)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2020-09-18 20:12:30 -04:00
malbert69 edf17e926f feat(store): microcenter (#39)
Co-authored-by: Ion Caza <contact@johncaza.com>
Co-authored-by: Jef LeCompte <jeffreylec@gmail.com>
2020-09-18 20:09:47 -04:00
Jef LeCompte faad3e68ef feat(ci): add npm run build
Signed-off-by: Jef LeCompte <jeffreylec@gmail.com>
2020-09-18 19:58:07 -04:00
Jef LeCompte 131dda4d5a hotfix: config variable reference
Signed-off-by: Jef LeCompte <jeffreylec@gmail.com>
2020-09-18 19:56:11 -04:00
Jef LeCompte 2246ecedf2 hotfix: config variable reference
Signed-off-by: Jef LeCompte <jeffreylec@gmail.com>
2020-09-18 19:55:47 -04:00
Alexandru Gutu 5a3636bcb6 feat: sms notification for usa carriers (#40)
Co-authored-by: Jef LeCompte <jeffreylec@gmail.com>
2020-09-18 19:54:59 -04:00
Jef LeCompte ec2108f4b9 hotfix: config variable reference
Signed-off-by: Jef LeCompte <jeffreylec@gmail.com>
2020-09-18 19:39:18 -04:00
Jef LeCompte fad9ea04c7 refactor: doc and notification (#42)
Signed-off-by: Jef LeCompte <jeffreylec@gmail.com>
2020-09-18 19:34:09 -04:00
Ion Caza 643045c7e0 feat: page timeout (#22)
Co-authored-by: Jef LeCompte <jeffreylec@gmail.com>
2020-09-18 19:04:29 -04:00
Vincent 7d7bd18b4d feat: more Best Buy AIBs (#41)
Co-authored-by: Jef LeCompte <jeffreylec@gmail.com>
2020-09-18 18:45:12 -04:00
Jef LeCompte ec98602d5b chore: remove cart link for nvidia
no longer working

Signed-off-by: Jef LeCompte <jeffreylec@gmail.com>
2020-09-18 18:43:34 -04:00
DakkJaniels a2fb97333c feat: add email test, fix memory leak (#24)
Co-authored-by: Jef LeCompte <jeffreylec@gmail.com>
2020-09-18 18:06:40 -04:00
Esg450 c0a881a16e feat: slack integration (#34)
Co-authored-by: Evan Gentis <evan.gentis@gmail.com>
2020-09-18 17:55:26 -04:00
Vincent c2a210cc81 fix: small error in isOutOfStock logic (#33) 2020-09-18 17:28:29 -04:00
George aa856c7121 docs: add amazon 2020-09-18 15:08:04 -04:00
George f0560ce72b feat: add Amazon links (#26)
Co-authored-by: Jef LeCompte <jeffreylec@gmail.com>
2020-09-18 14:35:11 -04:00
fuckingrobot 00ede13501 feat: update to check if FE in-stock via Digital River (#29)
Co-authored-by: Jef LeCompte <jeffreylec@gmail.com>
2020-09-18 14:31:55 -04:00
geman220 feed4ed6e4 docs: add EVGA to table checklist (#23) 2020-09-18 11:13:18 -04:00
41 changed files with 1204 additions and 242 deletions
+5
View File
@@ -0,0 +1,5 @@
root = true
[*]
end_of_line = lf
insert_final_newline = true
indent_style = tab
+18
View File
@@ -0,0 +1,18 @@
EMAIL_USERNAME="youremail@gmail.com"
EMAIL_PASSWORD="secretpassword"
NOTIFICATION_TEST="false"
PAGE_TIMEOUT="30000"
RATE_LIMIT_TIMEOUT="5000"
SLACK_CHANNEL="SlackChannelName"
SLACK_TOKEN="slack-token"
STORES="bestbuy,bandh,nvidia"
PHONE_NUMBER="1234567890"
PHONE_CARRIER="tmobile"
PUSHOVER_TOKEN="123pushover-token456"
PUSHOVER_USER="123pushover-user-key"
OPEN_BROWSER="true"
PLAY_SOUND="false"
SCREENSHOT="true"
TELEGRAM_ACCESS_TOKEN=""
TELEGRAM_CHAT_ID="1234"
SHOW_ONLY_BRANDS="evga"
-3
View File
@@ -1,3 +0,0 @@
EMAIL_USERNAME="youremail@gmail.com"
EMAIL_PASSWORD="secretpassword"
STORES="bestbuy,bandh,nvidia"
+4 -2
View File
@@ -1,7 +1,7 @@
---
name: 🐛 Bug report
about: Report a bug for this project
title: 'bug: '
title: ''
labels: 'bug'
assignees: jef
@@ -9,7 +9,9 @@ assignees: jef
### Description
<!-- Describe the feature here. -->
<!-- Describe the bug here. -->
<!-- Please be as detailed as possible. -->
<!-- Include OS, screenshots and console outputs. -->
### Possible solution
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: 🚀 Feature request
about: Suggest a feature for this project
title: 'enhancement: '
title: ''
labels: 'enhancement'
assignees: jef
+2 -1
View File
@@ -4,7 +4,7 @@ on:
branches:
- main
jobs:
lint:
build-lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
@@ -21,4 +21,5 @@ jobs:
- name: Pull dependencies
run: |
npm ci
npm run build
npm run lint
+7
View File
@@ -1,5 +1,12 @@
.idea/
.vs/
.vscode/
build/
node_modules/
.env
success-*.png
*.wav
*.mp3
*.flac
+52
View File
@@ -1,5 +1,57 @@
# Changelog
## [1.4.0](https://www.github.com/jef/nvidia-snatcher/compare/v1.3.0...v1.4.0) (2020-09-19)
### Features
* **notification:** add mint mobile carrier ([#70](https://www.github.com/jef/nvidia-snatcher/issues/70)) ([8aba7ec](https://www.github.com/jef/nvidia-snatcher/commit/8aba7ecbdb0bfce06257b7b9066e8fccbd82e47e))
* **notification:** add pushover ([#55](https://www.github.com/jef/nvidia-snatcher/issues/55)) ([c85658b](https://www.github.com/jef/nvidia-snatcher/commit/c85658bf82fdf360e5e9d8345eaa846f0572e67c))
* **notification:** add telegram ([#71](https://www.github.com/jef/nvidia-snatcher/issues/71)) ([393d5f6](https://www.github.com/jef/nvidia-snatcher/commit/393d5f689887bf1d6f30a37eea163b2e6bbd4efa))
* **notification:** add telus sms ([6be74a1](https://www.github.com/jef/nvidia-snatcher/commit/6be74a19f3d3f999145d17ac8e91c59db2502071))
* **store:** add amazon.ca, fix timeout ([#75](https://www.github.com/jef/nvidia-snatcher/issues/75)) ([d4de1a4](https://www.github.com/jef/nvidia-snatcher/commit/d4de1a4638e903eb9518354ab6fb2f8c4befc347))
* webpage toggle, sound notification, fix evga links ([#52](https://www.github.com/jef/nvidia-snatcher/issues/52)) ([a217409](https://www.github.com/jef/nvidia-snatcher/commit/a21740942bbbbe967948062fa06cfc82c31eb755))
### Performance Improvements
* browser abstraction ([#68](https://www.github.com/jef/nvidia-snatcher/issues/68)) ([#81](https://www.github.com/jef/nvidia-snatcher/issues/81)) ([ebbdfe3](https://www.github.com/jef/nvidia-snatcher/commit/ebbdfe3f6378516112f4b6e004bbd6ccf13af685))
## [1.3.0](https://www.github.com/jef/nvidia-snatcher/compare/v1.2.0...v1.3.0) (2020-09-19)
### Features
* **logging:** add timestamp ([#48](https://www.github.com/jef/nvidia-snatcher/issues/48)) ([6c3cd01](https://www.github.com/jef/nvidia-snatcher/commit/6c3cd016850d03a6c6a894cab24ba2d3781a9af1))
### Bug Fixes
* **store:** amazon captcha false-positives ([#54](https://www.github.com/jef/nvidia-snatcher/issues/54)) ([5c9e0b6](https://www.github.com/jef/nvidia-snatcher/commit/5c9e0b6d06bd7e1223a7587fec067c8e79c9cfd6))
* evga xc3 ultra link ([#56](https://www.github.com/jef/nvidia-snatcher/issues/56)) ([d907092](https://www.github.com/jef/nvidia-snatcher/commit/d907092b443b056605e09cb2ca3e94e6ca811d9e))
* screenshot size, add screenshot config setting ([#53](https://www.github.com/jef/nvidia-snatcher/issues/53)) ([7cfc7c7](https://www.github.com/jef/nvidia-snatcher/commit/7cfc7c74429c808fa14468cdd497eb9f9aeb922c))
* sms carrier config, add google carrier ([#44](https://www.github.com/jef/nvidia-snatcher/issues/44)) ([971fec2](https://www.github.com/jef/nvidia-snatcher/commit/971fec20e441e2b12a38d5c8d17d2d4cb5e64d6b))
## [1.2.0](https://www.github.com/jef/nvidia-snatcher/compare/v1.1.0...v1.2.0) (2020-09-19)
### Features
* **ci:** add `npm run build` ([faad3e6](https://www.github.com/jef/nvidia-snatcher/commit/faad3e68efafaab135b77080b02af83429b6eca6))
* **store:** microcenter ([#39](https://www.github.com/jef/nvidia-snatcher/issues/39)) ([edf17e9](https://www.github.com/jef/nvidia-snatcher/commit/edf17e926f3d186e7630da2834d78de3e540a956))
* add Amazon links ([#26](https://www.github.com/jef/nvidia-snatcher/issues/26)) ([f0560ce](https://www.github.com/jef/nvidia-snatcher/commit/f0560ce72bfbfdd6360b85e23edaa875d58f228f))
* add email test, fix memory leak ([#24](https://www.github.com/jef/nvidia-snatcher/issues/24)) ([a2fb973](https://www.github.com/jef/nvidia-snatcher/commit/a2fb97333c6eb81250b24ccb6859e9356acded21))
* more Best Buy AIBs ([#41](https://www.github.com/jef/nvidia-snatcher/issues/41)) ([7d7bd18](https://www.github.com/jef/nvidia-snatcher/commit/7d7bd18b4dd656ec01ef2fb2d8519e2a7f34ef70))
* page timeout ([#22](https://www.github.com/jef/nvidia-snatcher/issues/22)) ([643045c](https://www.github.com/jef/nvidia-snatcher/commit/643045c7e0158fb6526bd09427b96cce7958bcea))
* slack integration ([#34](https://www.github.com/jef/nvidia-snatcher/issues/34)) ([c0a881a](https://www.github.com/jef/nvidia-snatcher/commit/c0a881a16ebb573bf35b7f29cb27e5b3c2e1fe78))
* sms notification for usa carriers ([#40](https://www.github.com/jef/nvidia-snatcher/issues/40)) ([5a3636b](https://www.github.com/jef/nvidia-snatcher/commit/5a3636bcb639bb33bc586af96264f5df2f3a8307))
* update to check if FE in-stock via Digital River ([#29](https://www.github.com/jef/nvidia-snatcher/issues/29)) ([00ede13](https://www.github.com/jef/nvidia-snatcher/commit/00ede13501082f530ea672a349816be1d31621a8))
### Bug Fixes
* small error in `isOutOfStock` logic ([#33](https://www.github.com/jef/nvidia-snatcher/issues/33)) ([c2a210c](https://www.github.com/jef/nvidia-snatcher/commit/c2a210cc815c3aa06f6f14d33954f65577d95954))
## [1.1.0](https://www.github.com/jef/nvidia-snatcher/compare/v1.0.0...v1.1.0) (2020-09-18)
+43 -17
View File
@@ -1,6 +1,6 @@
# nvidia-snatcher [![ci](https://github.com/jef/nvidia-snatcher/workflows/ci/badge.svg)](https://github.com/jef/nvidia-snatcher/actions?query=workflow%3Aci)
# nvidia-snatcher [![ci](https://github.com/jef/nvidia-snatcher/workflows/ci/badge.svg)](https://github.com/jef/nvidia-snatcher/actions?query=workflow%3Aci) [![discord](https://img.shields.io/discord/756303724095471617.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/Cyc7nrz)
[FAQ](#FAQ) | [Discord](https://discord.gg/3duFzwk) | [Issues](https://github.com/jef/nvidia-snatcher/issues) | [Wiki](https://github.com/jef/nvidia-snatcher/wiki)
[FAQ](#FAQ) | [Issues](https://github.com/jef/nvidia-snatcher/issues) | [Wiki](https://github.com/jef/nvidia-snatcher/wiki)
The purpose of this bot is to get an Nvidia card. It tries multiple things to do that.
@@ -28,13 +28,11 @@ The purpose of this bot is to get an Nvidia card. It tries multiple things to do
> :point_right: You may get false positives from time to time, so I apologize for that. The library currently waits for all calls to be completed before parsing, but sometimes this can have unknown behavior. Patience is a virtue :)
| | **Best Buy** | **B&H** | **Newegg** | **Nvidia** |
|:---:|:---:|:---:|:---:|:---:|
| **3070**| | | | |
| **3080** | `✔` | `✔` | `` | `✔` |
| **3090** | | | | |
> :point_right: (``) Work in progress. Catchpa problems are intermittent. Use if you'd like, but expect problems.
| | **Amazon** | **EVGA** | **Best Buy** | **B&H** | **Micro Center** | **Newegg** | **Nvidia** |
|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
| **3070**| | | | | | | |
| **3080** | `✔` | `✔` | `✔` | `✔` | `✔` | `✔` | `✔` |
| **3090** | | | | | | | |
## Installation and prerequisites
@@ -58,29 +56,57 @@ At any point you want the program to stop, use <kbd>Ctrl</kbd> + <kbd>C</kbd>.
### Customization
There is not much to configure (as of now), but there are some options that you can choose to utilize.
To customize `nvidia-snatcher`, make a copy of `.env-example` as `.env` and make any changes to your liking.
First, you're going to need to copy the `.env.example` to `.env`. The current options are:
Here is a list of variables that you can use to customize your newly copied `.env` file:
| **Environment variable** | **Description** |
|:---:|:---:|
| `EMAIL_USERNAME` | Gmail address; e.g. `jensen.robbed.us@gmail.com` |
| `EMAIL_PASSWORD` | Gmail password; see below if you have MFA |
| `STORES` | List of [stores](#Supported-stores) you want to be scraped; optional, default: `nvidia` |
|:---:|---|
| `EMAIL_USERNAME` | Gmail address (e.g., `jensen.robbed.us@gmail.com`); optional |
| `EMAIL_PASSWORD` | Gmail password; see below if you have MFA; optional |
| `NOTIFICATION_TEST` | Test all the notifications configured; optional, default: `false` |
| `PAGE_TIMEOUT` | Navigation Timeout in milliseconds (`0` for infinite); optional, default: `30000` |
| `PHONE_NUMBER` | 10 digit phone number (e.g., `1234567890`); optional, email configuration required |
| `PHONE_CARRIER` | [Supported carriers](#supported-carriers) for SMS; optional, email configuration required |
| `RATE_LIMIT_TIMEOUT` | Rate limit timeout for each full store cycle; optional, default: `5000` |
| `SHOW_ONLY_BRANDS` | If set, will only show specified brands, seperated by `,` |
| `SLACK_CHANNEL` | Slack channel for posting (e.g., `update`); optional |
| `SLACK_TOKEN` | Slack API token; optional |
| `STORES` | [Supported stores](#supported-stores) you want to be scraped; optional, default: `nvidia` |
| `OPEN_BROWSER` | Toggle for whether or not the browser should open when item is found, default: `true` |
| `PLAY_SOUND` | Play this sound notification if a card is found.; optional |
| `SCREENSHOT` | Capture screenshot of page on successful hit; optional, default `true` |
| `TELEGRAM_ACCESS_TOKEN` | Telegram access token; optional |
| `TELEGRAM_CHAT_ID` | Telegram chat ID; optional |
> :point_right: If you have multi-factor authentication (MFA), you will need to create an [app password](https://myaccount.google.com/apppasswords) and use this instead of your Gmail password.
> :point_right: Free sounds available [here](https://freesound.org/home/). Place sounds into `resources/sounds/`
#### Supported stores
| **Store name** | **Store name environment variable** |
| **Stores** | **Environment variable** |
|:---:|:---:|
| Best Buy | `bestbuy`|
| Amazon.ca | `amazon-ca`|
| Amazon | `amazon`|
| B&H | `bandh`|
| EVGA | `evga`|
| Micro Center | `microcenter`|
| Newegg | `newegg`|
| Nvidia | `nvidia`|
> :point_right: Look at [`.env.example`](.env.example) for an example for `.env`.
#### Supported carriers
| **Carrier** | **Environment variable** | **Notes** |
|:---:|:---:|:---:|
| AT&T | `att`| |
| Google | `google`| |
| Mint | `mint`| |
| Sprint | `sprint`| |
| Telus | `telus`| |
| T-Mobile | `tmobile`| |
| Verizon | `verizon`| Works with Visible |
## FAQ
+345 -9
View File
@@ -1,6 +1,6 @@
{
"name": "nvidia-snatcher",
"version": "1.1.0",
"version": "1.4.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -173,6 +173,48 @@
"integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==",
"dev": true
},
"@slack/logger": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@slack/logger/-/logger-2.0.0.tgz",
"integrity": "sha512-OkIJpiU2fz6HOJujhlhfIGrc8hB4ibqtf7nnbJQDerG0BqwZCfmgtK5sWzZ0TkXVRBKD5MpLrTmCYyMxoMCgPw==",
"dev": true,
"requires": {
"@types/node": ">=8.9.0"
}
},
"@slack/types": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/@slack/types/-/types-1.9.0.tgz",
"integrity": "sha512-RmwgMWqOtzd2JPXdiaD/tyrDD0vtjjRDFdxN1I3tAxwBbg4aryzDUVqFc8na16A+3Xik/UN8X1hvVTw8J4EB9w==",
"dev": true
},
"@slack/web-api": {
"version": "5.12.0",
"resolved": "https://registry.npmjs.org/@slack/web-api/-/web-api-5.12.0.tgz",
"integrity": "sha512-ygSnNHVid7PltGo7W36f2SNVHyliemkzxn9uSwgnWNF7CHmWBKWAylU/eoDml9l5K7akMOxbousiurOw4XqOFg==",
"dev": true,
"requires": {
"@slack/logger": ">=1.0.0 <3.0.0",
"@slack/types": "^1.7.0",
"@types/is-stream": "^1.1.0",
"@types/node": ">=8.9.0",
"@types/p-queue": "^2.3.2",
"axios": "^0.19.0",
"eventemitter3": "^3.1.0",
"form-data": "^2.5.0",
"is-stream": "^1.1.0",
"p-queue": "^2.4.2",
"p-retry": "^4.0.0"
},
"dependencies": {
"is-stream": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
"integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=",
"dev": true
}
}
},
"@szmarczak/http-timer": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz",
@@ -188,6 +230,11 @@
"integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==",
"dev": true
},
"@types/debug": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.5.tgz",
"integrity": "sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ=="
},
"@types/eslint-visitor-keys": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz",
@@ -204,6 +251,15 @@
"@types/node": "*"
}
},
"@types/is-stream": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@types/is-stream/-/is-stream-1.1.0.tgz",
"integrity": "sha512-jkZatu4QVbR60mpIzjINmtS1ZF4a/FqdTUTBeQDVOQ2PYyidtwFKr0B5G6ERukKwliq+7mIXvxyppwzG5EgRYg==",
"dev": true,
"requires": {
"@types/node": "*"
}
},
"@types/json-schema": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz",
@@ -216,6 +272,11 @@
"integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=",
"dev": true
},
"@types/lodash": {
"version": "4.14.161",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.161.tgz",
"integrity": "sha512-EP6O3Jkr7bXvZZSZYlsgt5DIjiGr0dXP1/jVEwVLTFgg0d+3lWVQkRavYVQszV7dYUwvg0B8R0MBDpcmXg7XIA=="
},
"@types/minimatch": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
@@ -248,6 +309,12 @@
"integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==",
"dev": true
},
"@types/p-queue": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/@types/p-queue/-/p-queue-2.3.2.tgz",
"integrity": "sha512-eKAv5Ql6k78dh3ULCsSBxX6bFNuGjTmof5Q/T6PiECDq0Yf8IIn46jCyp3RJvCi8owaEmm3DZH1PEImjBMd/vQ==",
"dev": true
},
"@types/parse-json": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
@@ -263,6 +330,22 @@
"@types/node": "*"
}
},
"@types/retry": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz",
"integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==",
"dev": true
},
"@types/url-join": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@types/url-join/-/url-join-4.0.0.tgz",
"integrity": "sha512-awrJu8yML4E/xTwr2EMatC+HBnHGoDxc2+ImA9QyeUELI1S7dOCIZcyjki1rkwoA8P2D2NVgLAJLjnclkdLtAw=="
},
"@types/warning": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.0.tgz",
"integrity": "sha1-DSUBJorY+ZYrdA04fEZU9fjiPlI="
},
"@types/yauzl": {
"version": "2.9.1",
"resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.1.tgz",
@@ -564,6 +647,12 @@
"resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz",
"integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw=="
},
"asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
"dev": true
},
"at-least-node": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
@@ -576,6 +665,30 @@
"integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
"dev": true
},
"axios": {
"version": "0.19.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz",
"integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==",
"requires": {
"follow-redirects": "1.5.10"
}
},
"axios-error": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/axios-error/-/axios-error-1.0.0.tgz",
"integrity": "sha512-1JlcEEdTDeadLJ9+ImZd9eQudqqpAStpHzh9/Rb2q2UsWC+dJyQrFMTAHOzSJoFknWZ9IbVvW5gga9lG7CKLqQ==",
"requires": {
"axios": "^0.19.2",
"type-fest": "^0.15.1"
},
"dependencies": {
"type-fest": {
"version": "0.15.1",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.15.1.tgz",
"integrity": "sha512-n+UXrN8i5ioo7kqT/nF8xsEzLaqFra7k32SEsSPwvXVGyAcRgV/FUQN/sgfptJTR1oRmmq7z4IXMFSM7im7C9A=="
}
}
},
"babel-eslint": {
"version": "10.1.0",
"resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz",
@@ -965,6 +1078,15 @@
"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
"dev": true
},
"camel-case": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.1.tgz",
"integrity": "sha512-7fa2WcG4fYFkclIvEmxBbTvmibwF2/agfEBc6q3lOpVu0A13ltLsA+Hr/8Hp6kp5f+G7hKi6t8lys6XxP+1K6Q==",
"requires": {
"pascal-case": "^3.1.1",
"tslib": "^1.10.0"
}
},
"camelcase": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
@@ -1116,6 +1238,15 @@
"text-hex": "1.0.x"
}
},
"combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"dev": true,
"requires": {
"delayed-stream": "~1.0.0"
}
},
"commondir": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
@@ -1410,6 +1541,12 @@
}
}
},
"delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
"dev": true
},
"des.js": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz",
@@ -1485,6 +1622,15 @@
"integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==",
"dev": true
},
"dot-case": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.3.tgz",
"integrity": "sha512-7hwEmg6RiSQfm/GwPL4AAWXKy3YNNZA3oFv2Pdiey0mwkRCPZ9x6SZbkLcn8Ma5PYeVokzoD4Twv2n7LKp5WeA==",
"requires": {
"no-case": "^3.0.3",
"tslib": "^1.10.0"
}
},
"dot-prop": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz",
@@ -2316,6 +2462,12 @@
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
"dev": true
},
"eventemitter3": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz",
"integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==",
"dev": true
},
"events": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/events/-/events-3.2.0.tgz",
@@ -2622,6 +2774,12 @@
"pkg-dir": "^4.1.0"
}
},
"find-exec": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/find-exec/-/find-exec-1.0.1.tgz",
"integrity": "sha512-4o6QkGkpg3xK5s/47rdK9LDZRsE4JR1mrXnaAOXBngG6UKeIDJXfwtNCAkljgyy6VRh75D3FFaB0tii9vDEtIA==",
"dev": true
},
"find-root": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
@@ -2670,12 +2828,46 @@
"resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz",
"integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw=="
},
"follow-redirects": {
"version": "1.5.10",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz",
"integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==",
"requires": {
"debug": "=3.1.0"
},
"dependencies": {
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"requires": {
"ms": "2.0.0"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
}
}
},
"for-in": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
"integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=",
"dev": true
},
"form-data": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz",
"integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==",
"dev": true,
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.6",
"mime-types": "^2.1.12"
}
},
"fragment-cache": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
@@ -3413,8 +3605,7 @@
"js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
"dev": true
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
},
"js-types": {
"version": "1.0.0",
@@ -3577,8 +3768,7 @@
"lodash": {
"version": "4.17.20",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==",
"dev": true
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA=="
},
"lodash.get": {
"version": "4.4.2",
@@ -3659,6 +3849,22 @@
"triple-beam": "^1.3.0"
}
},
"loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
"requires": {
"js-tokens": "^3.0.0 || ^4.0.0"
}
},
"lower-case": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.1.tgz",
"integrity": "sha512-LiWgfDLLb1dwbFQZsSglpRj+1ctGnayXz3Uv0/WO8n558JycT5fg6zkNcnW0G68Nn0aEldTFeEfmjCfmqry/rQ==",
"requires": {
"tslib": "^1.10.0"
}
},
"lowercase-keys": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz",
@@ -3691,8 +3897,7 @@
"map-obj": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.1.0.tgz",
"integrity": "sha512-glc9y00wgtwcDmp7GaE/0b0OnxpNJsVf3ael/An6Fe2Q51LLwN1er6sdomLRzz5h0+yMpiYLhWYF5R7HeqVd4g==",
"dev": true
"integrity": "sha512-glc9y00wgtwcDmp7GaE/0b0OnxpNJsVf3ael/An6Fe2Q51LLwN1er6sdomLRzz5h0+yMpiYLhWYF5R7HeqVd4g=="
},
"map-visit": {
"version": "1.0.0",
@@ -3792,6 +3997,39 @@
"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
"dev": true
},
"messaging-api-common": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/messaging-api-common/-/messaging-api-common-1.0.0.tgz",
"integrity": "sha512-4bHqgnzrR2F97V+WnxVKS6EmjElkURa9jhy0/Tv7B+Xmcl3BDEW2krFpr5LfJDwFFiaDqj8Poel81hTOoWO/Lw==",
"requires": {
"@types/debug": "^4.1.5",
"@types/lodash": "^4.14.156",
"@types/url-join": "^4.0.0",
"axios": "^0.19.2",
"camel-case": "^4.1.1",
"debug": "^4.1.1",
"lodash": "^4.17.15",
"map-obj": "^4.1.0",
"pascal-case": "^3.1.1",
"snake-case": "^3.0.3",
"url-join": "^4.0.1"
}
},
"messaging-api-telegram": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/messaging-api-telegram/-/messaging-api-telegram-1.0.0.tgz",
"integrity": "sha512-hA2LFclQV5sVGGIYosdYvhap0GrPD73GuNjYi/T9rKZhn9qA5wTihrHNXdJHmUI7QOTT3JnA3QRdkwc9wkFZuA==",
"requires": {
"@types/lodash": "^4.14.156",
"@types/warning": "^3.0.0",
"axios": "^0.19.2",
"axios-error": "^1.0.0",
"lodash": "^4.17.15",
"messaging-api-common": "^1.0.0",
"ts-invariant": "^0.4.4",
"warning": "^4.0.3"
}
},
"micro-spelling-correcter": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/micro-spelling-correcter/-/micro-spelling-correcter-1.1.1.tgz",
@@ -3866,6 +4104,21 @@
"resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz",
"integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA=="
},
"mime-db": {
"version": "1.44.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz",
"integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==",
"dev": true
},
"mime-types": {
"version": "2.1.27",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz",
"integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==",
"dev": true,
"requires": {
"mime-db": "1.44.0"
}
},
"mimic-response": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz",
@@ -3994,6 +4247,15 @@
"integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
"dev": true
},
"no-case": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.3.tgz",
"integrity": "sha512-ehY/mVQCf9BL0gKfsJBvFJen+1V//U+0HQMPrWct40ixE4jnv0bfvxDbWtAHL9EcaPEOJHVVYKoQn1TlZUB8Tw==",
"requires": {
"lower-case": "^2.0.1",
"tslib": "^1.10.0"
}
},
"node-libs-browser": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz",
@@ -4321,12 +4583,28 @@
"p-limit": "^2.2.0"
}
},
"p-queue": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/p-queue/-/p-queue-2.4.2.tgz",
"integrity": "sha512-n8/y+yDJwBjoLQe1GSJbbaYQLTI7QHNZI2+rpmCDbe++WLf9HC3gf6iqj5yfPAV71W4UF3ql5W1+UBPXoXTxng==",
"dev": true
},
"p-reduce": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-2.1.0.tgz",
"integrity": "sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw==",
"dev": true
},
"p-retry": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.2.0.tgz",
"integrity": "sha512-jPH38/MRh263KKcq0wBNOGFJbm+U6784RilTmHjB/HM9kH9V8WlCpVUcdOmip9cjXOh6MxZ5yk1z2SjDUJfWmA==",
"dev": true,
"requires": {
"@types/retry": "^0.12.0",
"retry": "^0.12.0"
}
},
"p-try": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
@@ -4392,6 +4670,15 @@
"lines-and-columns": "^1.1.6"
}
},
"pascal-case": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.1.tgz",
"integrity": "sha512-XIeHKqIrsquVTQL2crjq3NfJUxmdLasn3TYOU0VBM+UX2a6ztAWBlJQBePLGY7VHW8+2dRadeIPK5+KImwTxQA==",
"requires": {
"no-case": "^3.0.3",
"tslib": "^1.10.0"
}
},
"pascalcase": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
@@ -4476,6 +4763,15 @@
"find-up": "^4.0.0"
}
},
"play-sound": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/play-sound/-/play-sound-1.1.3.tgz",
"integrity": "sha512-lqEzgtNAdfg2VUXItOtu5bTyWcqeFmnJmgvc8iHEeEOBEJdurqiGYfmCOzIpSBcwrs7XeSpvHv+Rw9dzRPc4aw==",
"dev": true,
"requires": {
"find-exec": "1.0.1"
}
},
"plur": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/plur/-/plur-4.0.0.tgz",
@@ -4616,6 +4912,11 @@
"ws": "^7.2.3"
}
},
"pushover-notifications": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/pushover-notifications/-/pushover-notifications-1.2.2.tgz",
"integrity": "sha512-+3Xcj+kiMiouZK1Ws8yGBTyl8WMPZZdELgl/iVxYqNwDdlaObBHMhEGPRC6Zb9t0BE27ikOoOqSIO1cKZOtsDA=="
},
"querystring": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
@@ -4890,6 +5191,12 @@
"integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==",
"dev": true
},
"retry": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz",
"integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=",
"dev": true
},
"rimraf": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
@@ -5043,6 +5350,15 @@
"is-fullwidth-code-point": "^2.0.0"
}
},
"snake-case": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.3.tgz",
"integrity": "sha512-WM1sIXEO+rsAHBKjGf/6R1HBBcgbncKS08d2Aqec/mrDSpU80SiOU41hO7ny6DToHSyrlwTYzQBIK1FPSx4Y3Q==",
"requires": {
"dot-case": "^3.0.3",
"tslib": "^1.10.0"
}
},
"snapdragon": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
@@ -5638,6 +5954,14 @@
"resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz",
"integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw=="
},
"ts-invariant": {
"version": "0.4.4",
"resolved": "https://registry.npmjs.org/ts-invariant/-/ts-invariant-0.4.4.tgz",
"integrity": "sha512-uEtWkFM/sdZvRNNDL3Ehu4WVpwaulhwQszV8mrtcdeE8nN00BV9mAmQ88RkrBhFgl9gMgvjJLAQcZbnPXI9mlA==",
"requires": {
"tslib": "^1.9.3"
}
},
"tsconfig-paths": {
"version": "3.9.0",
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz",
@@ -5664,8 +5988,7 @@
"tslib": {
"version": "1.13.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz",
"integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==",
"dev": true
"integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q=="
},
"tsutils": {
"version": "3.17.1",
@@ -5894,6 +6217,11 @@
}
}
},
"url-join": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz",
"integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA=="
},
"url-parse-lax": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz",
@@ -5953,6 +6281,14 @@
"integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==",
"dev": true
},
"warning": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
"integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==",
"requires": {
"loose-envify": "^1.0.0"
}
},
"which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+5 -1
View File
@@ -1,6 +1,6 @@
{
"name": "nvidia-snatcher",
"version": "1.1.0",
"version": "1.4.0",
"description": "🔮 For all your Nvidia needs",
"main": "src/index.ts",
"scripts": {
@@ -22,15 +22,19 @@
"homepage": "https://github.com/jef/nvidia-snatcher#readme",
"dependencies": {
"dotenv": "^8.2.0",
"messaging-api-telegram": "^1.0.0",
"nodemailer": "^6.4.11",
"open": "^7.2.1",
"puppeteer": "^5.3.0",
"pushover-notifications": "^1.2.2",
"winston": "^3.3.3"
},
"devDependencies": {
"@slack/web-api": "^5.12.0",
"@types/node": "^14.11.1",
"@types/nodemailer": "^6.4.0",
"@types/puppeteer": "^3.0.2",
"play-sound": "^1.1.3",
"rimraf": "^3.0.2",
"typescript": "^4.0.2",
"xo": "^0.33.1"
+44 -13
View File
@@ -3,27 +3,58 @@ import {config} from 'dotenv';
config({path: resolve(__dirname, '../.env')});
const email = {
username: process.env.EMAIL_USERNAME,
password: process.env.EMAIL_PASSWORD
};
const notifications = {
email: email.username && email.password
email: {
username: process.env.EMAIL_USERNAME ?? '',
password: process.env.EMAIL_PASSWORD ?? ''
},
phone: {
availableCarriers: new Map([
['att', 'txt.att.net'],
['google', 'msg.fi.google.com'],
['mint', 'mailmymobile.net'],
['sprint', 'messaging.sprintpcs.com'],
['telus', 'msg.telus.com'],
['tmobile', 'tmomail.net'],
['verizon', 'vtext.com']
]),
carrier: process.env.PHONE_CARRIER ?? '',
number: process.env.PHONE_NUMBER ?? ''
},
playSound: process.env.PLAY_SOUND ?? 'false',
pushover: {
token: process.env.PUSHOVER_TOKEN,
user: process.env.PUSHOVER_USER
},
slack: {
channel: process.env.SLACK_CHANNEL ?? '',
token: process.env.SLACK_TOKEN ?? ''
},
telegram: {
accessToken: process.env.TELEGRAM_ACCESS_TOKEN ?? '',
chatId: process.env.TELEGRAM_CHAT_ID ?? ''
},
test: process.env.NOTIFICATION_TEST ?? 'false'
};
const page = {
height: 1920,
userAgent: 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36',
width: 1080
capture: process.env.SCREENSHOT ?? 'true',
width: 1920,
height: 1080,
navigationTimeout: Number(process.env.PAGE_TIMEOUT) ?? 30000,
userAgent: 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'
};
const stores = process.env.STORES ?? 'nvidia';
const openBrowser = process.env.OPEN_BROWSER ?? 'true';
const rateLimitTimeout = Number(process.env.RATE_LIMIT_TIMEOUT) ?? 5000;
const stores = process.env.STORES ? process.env.STORES.split(',') : ['nvidia'];
const showOnlyBrands = process.env.SHOW_ONLY_BRANDS ? process.env.SHOW_ONLY_BRANDS.split(',') : [];
export const Config = {
email,
notifications,
rateLimitTimeout,
page,
rateLimitTimeout: 5000,
stores
stores,
openBrowser,
showOnlyBrands
};
+11 -68
View File
@@ -1,91 +1,34 @@
import {Config} from './config';
import {Store, Stores} from './store';
import puppeteer from 'puppeteer';
import open from 'open';
import sendNotification from './notification';
import {Stores} from './store/model';
import {Logger} from './logger';
import {sendNotification} from './notification';
import {lookup} from './store';
import puppeteer from 'puppeteer';
/**
* Starts the bot.
*/
async function main() {
const results = [];
const browser = await puppeteer.launch();
for (const store of Stores) {
Logger.debug(store.links);
results.push(lookup(store));
results.push(lookup(browser, store));
}
await Promise.all(results);
await browser.close();
Logger.info('↗ trying stores again');
setTimeout(main, Config.rateLimitTimeout);
}
/**
* Responsible for looking up information about a each product within
* a `Store`. It's important that we ignore `no-await-in-loop` here
* because we don't want to get rate limited within the same store.
*
* @param store Vendor of graphics cards.
* Send test email.
*/
async function lookup(store: Store) {
/* eslint-disable no-await-in-loop */
for (const link of store.links) {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setUserAgent(Config.page.userAgent);
await page.setViewport({
height: Config.page.height,
width: Config.page.width
});
const graphicsCard = `${link.brand} ${link.model}`;
try {
await page.goto(link.url, {waitUntil: 'networkidle0'});
} catch {
Logger.error(`✖ [${store.name}] ${graphicsCard} skipping; timed out`);
return;
}
const bodyHandle = await page.$('body');
const textContent = await page.evaluate(body => body.textContent, bodyHandle);
Logger.debug(textContent);
if (isOutOfStock(textContent, link.oosLabels)) {
Logger.info(`✖ [${store.name}] ${graphicsCard} is still out of stock`);
} else {
Logger.info(`🚀🚀🚀 [${store.name}] ${graphicsCard} IN STOCK 🚀🚀🚀`);
Logger.info(link.url);
Logger.debug(' saving screenshot');
await page.screenshot({path: `success-${Date.now()}.png`});
const givenUrl = store.cartUrl ? store.cartUrl : link.url;
await open(givenUrl);
sendNotification(givenUrl);
}
await browser.close();
}
/* eslint-enable no-await-in-loop */
}
/**
* Checks if DOM has any out-of-stock related text.
*
* @param domText Complete DOM of website.
* @param oosLabels Out-of-stock labels.
*/
function isOutOfStock(domText: string, oosLabels: string[]) {
const domTextLowerCase = domText.toLowerCase();
let result = false;
for (const oosLabel of oosLabels) {
result = domTextLowerCase.includes(oosLabel.toLowerCase());
}
return result;
if (Config.notifications.test === 'true') {
sendNotification('test');
}
/**
+3 -1
View File
@@ -1,11 +1,13 @@
import winston, {format} from 'winston';
const prettyJson = format.printf(info => {
const timestamp = new Date().toLocaleTimeString();
if (typeof info.message === 'object') {
info.message = JSON.stringify(info.message, null, 4);
}
return `${info.level} :: ${info.message}`;
return `[${timestamp}] ${info.level} :: ${info.message}`;
});
export const Logger = winston.createLogger({
+6 -5
View File
@@ -3,23 +3,24 @@ import Mail from 'nodemailer/lib/mailer';
import {Config} from '../config';
import {Logger} from '../logger';
const email = Config.notifications.email;
const subject = 'NVIDIA - BUY NOW';
const transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: Config.email.username,
pass: Config.email.password
user: email.username,
pass: email.password
}
});
const mailOptions: Mail.Options = {
from: Config.email.username,
to: Config.email.username,
from: email.username,
to: email.username,
subject
};
export default function sendEmail(text: string) {
export function sendEmail(text: string) {
mailOptions.text = text;
transporter.sendMail(mailOptions, (error, info) => {
+1 -8
View File
@@ -1,8 +1 @@
import {Config} from '../config';
import sendEmail from './email';
export default function sendNotification(cartUrl: string) {
if (Config.notifications.email) {
sendEmail(cartUrl);
}
}
export * from './notification';
+38
View File
@@ -0,0 +1,38 @@
import {Config} from '../config';
import {sendEmail} from './email';
import {sendSMS} from './sms';
import {playSound} from './sound';
import {sendSlackMessage} from './slack';
import {sendPushoverNotification} from './pushover';
import {sendTelegramMessage} from './telegram';
const notifications = Config.notifications;
export function sendNotification(cartUrl: string) {
if (notifications.email.username && notifications.email.password) {
sendEmail(cartUrl);
}
if (notifications.slack.channel && notifications.slack.token) {
sendSlackMessage(cartUrl);
}
if (notifications.telegram.accessToken && notifications.telegram.chatId) {
sendTelegramMessage(cartUrl);
}
if (notifications.phone.number) {
const carrier = notifications.phone.carrier.toLowerCase();
if (carrier && notifications.phone.availableCarriers.has(carrier)) {
sendSMS(cartUrl);
}
}
if (notifications.pushover.token && notifications.pushover.user) {
sendPushoverNotification(cartUrl);
}
if (notifications.playSound === 'true') {
playSound();
}
}
+23
View File
@@ -0,0 +1,23 @@
import Push from 'pushover-notifications';
import {Config} from '../config';
import {Logger} from '../logger';
const pushover = Config.notifications.pushover;
const push = new Push({
user: pushover.user,
token: pushover.token
});
export function sendPushoverNotification(text: string) {
const message = {
message: text
};
push.send(message, (err: Error, result: string) => {
if (err) {
Logger.error(err);
} else {
Logger.info(`✔ Pushover notification sent: ${result}`);
}
});
}
+23
View File
@@ -0,0 +1,23 @@
import {WebClient} from '@slack/web-api';
import {Config} from '../config';
import {Logger} from '../logger';
const channel = Config.notifications.slack.channel;
const token = Config.notifications.slack.token;
const web = new WebClient(token);
export function sendSlackMessage(text: string) {
(async () => {
try {
const result = await web.chat.postMessage({text, channel});
if (!result.ok) {
Logger.error(result.error);
return;
}
Logger.info(`✔ slack message sent to '${channel}': ${text}`);
} catch (error) {
Logger.error(error);
}
})();
}
+41
View File
@@ -0,0 +1,41 @@
import nodemailer from 'nodemailer';
import Mail from 'nodemailer/lib/mailer';
import {Config} from '../config';
import {Logger} from '../logger';
const subject = 'NVIDIA - BUY NOW';
const [email, phone] = [Config.notifications.email, Config.notifications.phone];
const transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: email.username,
pass: email.password
}
});
const mailOptions: Mail.Options = {
from: Config.notifications.email.username,
to: generateAddress(),
subject
};
export function sendSMS(text: string) {
mailOptions.text = text;
transporter.sendMail(mailOptions, (error, info) => {
if (error) {
Logger.error(error);
} else {
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
Logger.info(`✔ sms sent: ${info.response}`);
}
});
}
function generateAddress() {
const carrier = phone.carrier.toLowerCase();
if (carrier && phone.availableCarriers.has(carrier)) {
return [phone.number, phone.availableCarriers.get(carrier)].join('@');
}
}
+25
View File
@@ -0,0 +1,25 @@
import playerLib = require('play-sound');
import {Config} from '../config';
import {Logger} from '../logger';
import * as fs from 'fs';
const notificationSound = './resources/sounds/' + Config.notifications.playSound;
const player = playerLib();
export function playSound() {
// Check if file exists
fs.access(notificationSound, fs.constants.F_OK, err => {
if (err) {
Logger.error(`error opening sound file: ${err.message}`);
return;
}
player.play(notificationSound, (err: string) => {
Logger.info('✔ playing sound');
if (err) {
Logger.error(`error playing sound: ${err}`);
}
});
});
}
+20
View File
@@ -0,0 +1,20 @@
import {Config} from '../config';
import {Logger} from '../logger';
import {TelegramClient} from 'messaging-api-telegram';
const telegram = Config.notifications.telegram;
const client = new TelegramClient({
accessToken: telegram.accessToken
});
export function sendTelegramMessage(text: string) {
(async () => {
try {
await client.sendMessage(telegram.chatId, text);
Logger.info(`✔ telegram message sent to '${telegram.chatId}': ${text}`);
} catch (error) {
Logger.error(error);
}
})();
}
-14
View File
@@ -1,14 +0,0 @@
import {Store} from './store';
export const BAndH: Store = {
cartUrl: '',
links: [
{
brand: 'gigabyte',
model: 'black',
url: 'https://www.bhphotovideo.com/c/product/1593333-REG/gigabyte_gv_n3080gaming_oc_10gd_geforce_rtx_3080_gaming.html?SID=s1600391647213ytuua52439',
oosLabels: ['notify when available']
}
],
name: 'bandh'
};
-20
View File
@@ -1,20 +0,0 @@
import {Store} from './store';
export const BestBuy: Store = {
cartUrl: '',
links: [
{
brand: 'nvidia',
model: 'founder edition',
url: 'https://www.bestbuy.com/site/nvidia-geforce-rtx-3080-10gb-gddr6x-pci-express-4-0-graphics-card-titanium-and-black/6429440.p?skuId=6429440',
oosLabels: ['sold out']
},
{
brand: 'gigabyte',
model: 'black',
url: 'https://www.bestbuy.com/site/gigabyte-geforce-rtx-3080-10g-gddr6x-pci-express-4-0-graphics-card-black/6430620.p?acampID=0&cmp=RMX&loc=Hatch&ref=198&skuId=6430620',
oosLabels: ['sold out']
}
],
name: 'bestbuy'
};
-14
View File
@@ -1,14 +0,0 @@
import {Store} from './store';
export const Evga: Store = {
cartUrl: '',
links: [
{
brand: 'evga',
model: 'ftw3, xc3 black, xc3 gaming, xc3 ultra gaming',
url: 'https://www.evga.com/products/productlist.aspx?type=0&family=GeForce+30+Series+Family&chipset=RTX+3080',
oosLabels: ['out of stock']
}
],
name: 'evga'
};
+10
View File
@@ -0,0 +1,10 @@
/**
* Checks if DOM has any out-of-stock related text.
*
* @param domText Complete DOM of website.
* @param oosLabels Out-of-stock labels.
*/
export function includesLabels(domText: string, oosLabels: string[]): boolean {
const domTextLowerCase = domText.toLowerCase();
return oosLabels.some(label => domTextLowerCase.includes(label));
}
+2 -38
View File
@@ -1,38 +1,2 @@
import {BestBuy} from './bestbuy';
import {BAndH} from './bandh';
import {Evga} from './evga';
import {NewEgg} from './newegg';
import {Nvidia} from './nvidia';
import {Config} from '../config';
const list = new Map([
['bestbuy', BestBuy],
['bandh', BAndH],
['evga', Evga],
['newegg', NewEgg],
['nvidia', Nvidia]
]);
if (!Config.stores.toLowerCase().includes('bestbuy')) {
list.delete('bestbuy');
}
if (!Config.stores.toLowerCase().includes('bandh')) {
list.delete('bandh');
}
if (!Config.stores.toLowerCase().includes('evga')) {
list.delete('evga');
}
if (!Config.stores.toLowerCase().includes('newegg')) {
list.delete('newegg');
}
if (!Config.stores.toLowerCase().includes('nvidia')) {
list.delete('nvidia');
}
export const Stores = Array.from(list.values());
export * from './store';
export * from './lookup';
export * from './includes-labels';
+85
View File
@@ -0,0 +1,85 @@
import puppeteer from 'puppeteer';
import {Config} from '../config';
import {Logger} from '../logger';
import open from 'open';
import {Store} from './model';
import {sendNotification} from '../notification';
import {includesLabels} from './includes-labels';
/**
* Returns true if the brand should be checked for stock
*
* @param brand The brand of the GPU
*/
function filterBrand(brand: string) {
if (Config.showOnlyBrands.length === 0) {
return true;
}
return Config.showOnlyBrands.includes(brand);
}
/**
* Responsible for looking up information about a each product within
* a `Store`. It's important that we ignore `no-await-in-loop` here
* because we don't want to get rate limited within the same store.
*
* @param browser Current browser in use.
* @param store Vendor of graphics cards.
*/
export async function lookup(browser: puppeteer.Browser, store: Store) {
/* eslint-disable no-await-in-loop */
for (const link of store.links) {
if (!filterBrand(link.brand)) {
continue;
}
const page = await browser.newPage();
page.setDefaultNavigationTimeout(Config.page.navigationTimeout);
await page.setUserAgent(Config.page.userAgent);
await page.setViewport({
height: Config.page.height,
width: Config.page.width
});
const graphicsCard = `${link.brand} ${link.model}`;
try {
await page.goto(link.url, {waitUntil: 'networkidle0'});
} catch {
Logger.error(`✖ [${store.name}] ${graphicsCard} skipping; timed out`);
await page.close();
continue;
}
const bodyHandle = await page.$('body');
const textContent = await page.evaluate(body => body.textContent, bodyHandle);
Logger.debug(textContent);
if (includesLabels(textContent, link.oosLabels)) {
Logger.info(`✖ [${store.name}] still out of stock: ${graphicsCard}`);
} else if (link.captchaLabels && includesLabels(textContent, link.captchaLabels)) {
Logger.warn(`✖ [${store.name}] CAPTCHA from: ${graphicsCard}`);
} else {
Logger.info(`🚀🚀🚀 [${store.name}] ${graphicsCard} IN STOCK 🚀🚀🚀`);
Logger.info(link.url);
if (Config.page.capture === 'true') {
Logger.debug(' saving screenshot');
await page.screenshot({path: `success-${Date.now()}.png`});
}
const givenUrl = store.cartUrl ? store.cartUrl : link.url;
if (Config.openBrowser === 'true') {
await open(givenUrl);
}
sendNotification(givenUrl);
}
await page.close();
}
/* eslint-enable no-await-in-loop */
}
+84
View File
@@ -0,0 +1,84 @@
import {Store} from './store';
export const AmazonCa: Store = {
links: [
{
brand: 'msi',
model: 'gaming trio',
url: 'https://www.amazon.ca/MSI-GeForce-RTX-3080-10G/dp/B08HR7SV3M?ref_=ast_sto_dp',
oosLabels: ['currently unavailable'],
captchaLabels: ['enter the characters you see below']
},
{
brand: 'evga',
model: 'ftw3gaming',
url: 'https://www.amazon.ca/EVGA-GeForce-Technology-Backplate-10G-P5-3895-KR/dp/B08HR3DPGW?ref_=ast_sto_dp',
oosLabels: ['currently unavailable'],
captchaLabels: ['enter the characters you see below']
},
{
brand: 'evga',
model: 'ftw3ultra',
url: 'https://www.amazon.ca/EVGA-GeForce-Technology-Backplate-10G-P5-3897-KR/dp/B08HR3Y5GQ?ref_=ast_sto_dp',
oosLabels: ['currently unavailable'],
captchaLabels: ['enter the characters you see below']
},
{
brand: 'evga',
model: 'xc3ultra',
url: 'https://www.amazon.ca/EVGA-GeForce-Cooling-Backplate-10G-P5-3885-KR/dp/B08HR55YB5?ref_=ast_sto_dp',
oosLabels: ['currently unavailable'],
captchaLabels: ['enter the characters you see below']
},
{
brand: 'evga',
model: 'xc3gaming',
url: 'https://www.amazon.ca/EVGA-GeForce-Cooling-Backplate-10G-P5-3883-KR/dp/B08HR4RJ3Q?ref_=ast_sto_dp',
oosLabels: ['currently unavailable'],
captchaLabels: ['enter the characters you see below']
},
{
brand: 'evga',
model: 'xc3black',
url: 'https://www.amazon.ca/EVGA-GeForce-Gaming-Cooling-10G-P5-3881-KR/dp/B08HR6FMF3?ref_=ast_sto_dp',
oosLabels: ['currently unavailable'],
captchaLabels: ['enter the characters you see below']
},
{
brand: 'gigabyte',
model: 'windforce',
url: 'https://www.amazon.ca/GIGABYTE-GeForce-Graphics-WINDFORCE-GV-N3080GAMING/dp/B08HJTH61J?ref_=ast_sto_dp',
oosLabels: ['currently unavailable'],
captchaLabels: ['enter the characters you see below']
},
{
brand: 'gigabyte',
model: 'windforce eagle',
url: 'https://www.amazon.ca/GIGABYTE-GeForce-Graphics-WINDFORCE-GV-N3080EAGLE/dp/B08HJS2JLJ?ref_=ast_sto_dp',
oosLabels: ['currently unavailable'],
captchaLabels: ['enter the characters you see below']
},
{
brand: 'asus',
model: 'tuf',
url: 'https://www.amazon.ca/Asus-90YV0FB0-M0AM00-TUF-RTX3080-10G-GAMING/dp/B08HHDP9DW?ref_=ast_sto_dp',
oosLabels: ['currently unavailable'],
captchaLabels: ['enter the characters you see below']
},
{
brand: 'asus',
model: 'tufoc',
url: 'https://www.amazon.ca/Asus-90YV0FB1-M0AM00-TUF-RTX3080-O10G-GAMING/dp/B08HH5WF97?ref_=ast_sto_dp',
oosLabels: ['currently unavailable'],
captchaLabels: ['enter the characters you see below']
},
{
brand: 'msi',
model: 'ventus',
url: 'https://www.amazon.ca/MSI-GeForce-RTX-3080-10G/dp/B08HR5SXPS?ref_=ast_sto_dp',
oosLabels: ['currently unavailable'],
captchaLabels: ['enter the characters you see below']
}
],
name: 'amazon-ca'
};
+63
View File
@@ -0,0 +1,63 @@
import {Store} from './store';
export const Amazon: Store = {
links: [
{
brand: 'pny',
model: 'xlr8',
url: 'https://www.amazon.com/PNY-GeForce-Gaming-Epic-X-Graphics/dp/B08HBR7QBM?ref_=ast_sto_dp',
oosLabels: ['currently unavailable'],
captchaLabels: ['enter the characters you see below']
},
{
brand: 'msi',
model: 'gaming trio',
url: 'https://www.amazon.com/MSI-GeForce-RTX-3080-10G/dp/B08HR7SV3M?ref_=ast_sto_dp',
oosLabels: ['currently unavailable'],
captchaLabels: ['enter the characters you see below']
},
{
brand: 'evga',
model: 'ftw3',
url: 'https://www.amazon.com/EVGA-10G-P5-3897-KR-GeForce-Technology-Backplate/dp/B08HR3Y5GQ?ref_=ast_sto_dp',
oosLabels: ['currently unavailable'],
captchaLabels: ['enter the characters you see below']
},
{
brand: 'evga',
model: 'xc3',
url: 'https://www.amazon.com/EVGA-10G-P5-3885-KR-GeForce-Cooling-Backplate/dp/B08HR55YB5?ref_=ast_sto_dp',
oosLabels: ['currently unavailable'],
captchaLabels: ['enter the characters you see below']
},
{
brand: 'gigabyte',
model: 'windforce',
url: 'https://www.amazon.com/GIGABYTE-GeForce-Graphics-WINDFORCE-GV-N3080GAMING/dp/B08HJTH61J?ref_=ast_sto_dp',
oosLabels: ['currently unavailable'],
captchaLabels: ['enter the characters you see below']
},
{
brand: 'gigabyte',
model: 'windforce eagle',
url: 'https://www.amazon.com/GIGABYTE-GeForce-Graphics-WINDFORCE-GV-N3080EAGLE/dp/B08HJS2JLJ?ref_=ast_sto_dp',
oosLabels: ['currently unavailable'],
captchaLabels: ['enter the characters you see below']
},
{
brand: 'asus',
model: 'tuf',
url: 'https://www.amazon.com/ASUS-Graphics-DisplayPort-Military-Grade-Certification/dp/B08HH5WF97?ref_=ast_sto_dp',
oosLabels: ['currently unavailable'],
captchaLabels: ['enter the characters you see below']
},
{
brand: 'msi',
model: 'ventus',
url: 'https://www.amazon.com/MSI-GeForce-RTX-3080-10G/dp/B08HR5SXPS?ref_=ast_sto_dp',
oosLabels: ['currently unavailable'],
captchaLabels: ['enter the characters you see below']
}
],
name: 'amazon'
};
+62
View File
@@ -0,0 +1,62 @@
import {Store} from './store';
export const BAndH: Store = {
links: [
{
brand: 'gigabyte',
model: 'black',
url: 'https://www.bhphotovideo.com/c/product/1593333-REG/gigabyte_gv_n3080gaming_oc_10gd_geforce_rtx_3080_gaming.html?SID=s1600391647213ytuua52439',
oosLabels: ['notify when available']
},
{
brand: 'asus',
model: 'tuf',
url: 'https://www.bhphotovideo.com/c/product/1593649-REG/asus_tuf_rtx3080_10g_gaming_tuf_gaming_geforce_rtx.html',
oosLabels: ['notify when available']
},
{
brand: 'gigabyte',
model: 'gaming-oc',
url: 'https://www.bhphotovideo.com/c/product/1593333-REG/gigabyte_gv_n3080gaming_oc_10gd_geforce_rtx_3080_gaming.html',
oosLabels: ['notify when available']
},
{
brand: 'zotac',
model: 'trinity',
url: 'https://www.bhphotovideo.com/c/product/1592969-REG/zotac_zt_a30800d_10p_gaming_geforce_rtx_3080.html',
oosLabels: ['notify when available']
},
{
brand: 'asus',
model: 'tuf-oc',
url: 'https://www.bhphotovideo.com/c/product/1593650-REG/asus_tuf_rtx3080_o10g_gaming_tuf_gaming_geforce_rtx.html',
oosLabels: ['notify when available']
},
{
brand: 'msi',
model: 'xtrio',
url: 'https://www.bhphotovideo.com/c/product/1593996-REG/msi_g3080gxt10_geforce_rtx_3080_gaming.html',
oosLabels: ['notify when available']
},
{
brand: 'msi',
model: 'ventus',
url: 'https://www.bhphotovideo.com/c/product/1593997-REG/msi_g3080v3x10c_geforce_rtx_3080_ventus.html',
oosLabels: ['notify when available']
},
{
brand: 'msi',
model: 'TRIO2',
url: 'https://www.bhphotovideo.com/c/product/1593645-REG/msi_geforce_rtx_3080_gaming.html',
oosLabels: ['notify when available']
},
{
brand: 'msi',
model: 'ventus-oc',
url: 'https://www.bhphotovideo.com/c/product/1593646-REG/msi_geforce_rtx_3080_ventus.html',
oosLabels: ['notify when available']
}
],
name: 'bandh'
};
+49
View File
@@ -0,0 +1,49 @@
import {Store} from './store';
export const BestBuy: Store = {
links: [
{
brand: 'asus',
model: 'rog strix',
url: 'https://www.bestbuy.com/site/asus-geforce-rtx-3080-10gb-gddr6x-pci-express-4-0-strix-graphics-card-black/6432445.p?skuId=6432445',
oosLabels: ['sold out', 'coming soon']
},
{
brand: 'evga',
model: 'xc3 black',
url: 'https://www.bestbuy.com/site/evga-geforce-rtx-3080-10gb-gddr6x-pci-express-4-0-graphics-card/6432399.p?skuId=6432399',
oosLabels: ['sold out', 'coming soon']
},
{
brand: 'evga',
model: 'xc3 ultra',
url: 'https://www.bestbuy.com/site/evga-geforce-rtx-3080-10gb-gddr6x-pci-express-4-0-graphics-card/6432400.p?skuId=6432400',
oosLabels: ['sold out', 'coming soon']
},
{
brand: 'gigabyte',
model: 'black',
url: 'https://www.bestbuy.com/site/gigabyte-geforce-rtx-3080-10g-gddr6x-pci-express-4-0-graphics-card-black/6430620.p?acampID=0&cmp=RMX&loc=Hatch&ref=198&skuId=6430620',
oosLabels: ['sold out', 'coming soon']
},
{
brand: 'gigabyte',
model: 'eagle',
url: 'https://www.bestbuy.com/site/gigabyte-geforce-rtx-3080-10g-gddr6x-pci-express-4-0-graphics-card-black/6430621.p?skuId=6430621',
oosLabels: ['sold out', 'coming soon']
},
{
brand: 'msi',
model: 'ventus 3x',
url: 'https://www.bestbuy.com/site/msi-geforce-rtx-3080-ventus-3x-10g-oc-bv-gddr6x-pci-express-4-0-graphic-card-black-silver/6430175.p?skuId=6430175',
oosLabels: ['sold out', 'coming soon']
},
{
brand: 'nvidia',
model: 'founder edition',
url: 'https://www.bestbuy.com/site/nvidia-geforce-rtx-3080-10gb-gddr6x-pci-express-4-0-graphics-card-titanium-and-black/6429440.p?skuId=6429440',
oosLabels: ['sold out', 'coming soon']
}
],
name: 'bestbuy'
};
+32
View File
@@ -0,0 +1,32 @@
import {Store} from './store';
export const Evga: Store = {
links: [
{
brand: 'evga',
model: 'xc3 black',
url: 'https://www.evga.com/products/product.aspx?pn=10G-P5-3881-KR',
oosLabels: ['out of stock']
},
{
brand: 'evga',
model: 'ftw3',
url: 'https://www.evga.com/products/product.aspx?pn=10G-P5-3897-KR',
oosLabels: ['out of stock']
},
{
brand: 'evga',
model: 'xc3 gaming',
url: 'https://www.evga.com/products/product.aspx?pn=10G-P5-3883-KR',
oosLabels: ['out of stock']
},
{
brand: 'evga',
model: 'xc3 ultra gaming',
url: 'https://www.evga.com/products/product.aspx?pn=10G-P5-3885-KR',
oosLabels: ['out of stock']
}
],
name: 'evga'
};
+30
View File
@@ -0,0 +1,30 @@
import {BestBuy} from './bestbuy';
import {BAndH} from './bandh';
import {Evga} from './evga';
import {NewEgg} from './newegg';
import {Amazon} from './amazon';
import {MicroCenter} from './microcenter';
import {Config} from '../../config';
import {Nvidia} from './nvidia';
import {AmazonCa} from './amazon-ca';
const masterList = new Map([
[Amazon.name, Amazon],
[AmazonCa.name, AmazonCa],
[BestBuy.name, BestBuy],
[BAndH.name, BAndH],
[Evga.name, Evga],
[MicroCenter.name, MicroCenter],
[NewEgg.name, NewEgg],
[Nvidia.name, Nvidia]
]);
const list = new Map();
for (const name of Config.stores) {
list.set(name, masterList.get(name));
}
export const Stores = Array.from(list.values());
export * from './store';
+43
View File
@@ -0,0 +1,43 @@
import {Store} from './store';
export const MicroCenter: Store = {
links: [
{
brand: 'evga',
model: 'xc3 ultra gaming',
url: 'https://www.microcenter.com/product/628344/evga-geforce-rtx-3080-xc3-ultra-gaming-triple-fan-10gb-gddr6x-pcie-40-graphics-card',
oosLabels: ['sold out']
},
{
brand: 'msi',
model: 'ventus 3x overclocked',
url: 'https://www.microcenter.com/product/628331/msi-geforce-rtx-3080-ventus-3x-overclocked-triple-fan-10gb-gddr6x-pcie-40-graphics-card',
oosLabels: ['sold out']
},
{
brand: 'asus',
model: 'tuf gaming',
url: 'https://www.microcenter.com/product/628303/asus-geforce-rtx-3080-tuf-gaming-triple-fan-10gb-gddr6x-pcie-40-graphics-card',
oosLabels: ['sold out']
},
{
brand: 'msi',
model: 'gaming x trio',
url: 'https://www.microcenter.com/product/628330/msi-geforce-rtx-3080-gaming-x-trio-triple-fan-10gb-gddr6x-pcie-40-graphics-card',
oosLabels: ['sold out']
},
{
brand: 'evga',
model: 'xc3 black',
url: 'https://www.microcenter.com/product/628340/evga-geforce-rtx-3080-xc3-black-triple-fan-10gb-gddr6x-pcie-40-graphics-card',
oosLabels: ['sold out']
},
{
brand: 'zotac',
model: 'trinity overclocked',
url: 'https://www.microcenter.com/product/628607/zotac-geforce-rtx-3080-trinity-overclocked-triple-fan-10gb-gddr6x-pcie-40-graphics-card',
oosLabels: ['sold out']
}
],
name: 'microcenter'
};
@@ -1,37 +1,41 @@
import {Store} from './store';
export const NewEgg: Store = {
cartUrl: '',
links: [
{
brand: 'asus',
model: 'tuf',
url: 'https://www.newegg.com/asus-geforce-rtx-3080-tuf-rtx3080-10g-gaming/p/N82E16814126453',
oosLabels: ['auto notify', 'out of stock']
oosLabels: ['auto notify', 'out of stock'],
captchaLabels: ['are you a human?']
},
{
brand: 'evga',
model: 'black gaming',
url: 'https://www.newegg.com/evga-geforce-rtx-3080-10g-p5-3881-kr/p/N82E16814487522',
oosLabels: ['auto notify', 'out of stock']
oosLabels: ['auto notify', 'out of stock'],
captchaLabels: ['are you a human?']
},
{
brand: 'evga',
model: 'argb led icx3',
url: 'https://www.newegg.com/evga-geforce-rtx-3080-10g-p5-3883-kr/p/N82E16814487521',
oosLabels: ['auto notify', 'out of stock']
oosLabels: ['auto notify', 'out of stock'],
captchaLabels: ['are you a human?']
},
{
brand: 'evga',
model: 'xc3 ultra gaming',
url: 'https://www.newegg.com/evga-geforce-rtx-3080-10g-p5-3885-kr/p/N82E16814487520',
oosLabels: ['auto notify', 'out of stock']
oosLabels: ['auto notify', 'out of stock'],
captchaLabels: ['are you a human?']
},
{
brand: 'msi',
model: 'ventus',
url: 'https://www.newegg.com/msi-geforce-rtx-3080-rtx-3080-ventus-3x-10g/p/N82E16814137600',
oosLabels: ['auto notify', 'out of stock']
oosLabels: ['auto notify', 'out of stock'],
captchaLabels: ['are you a human?']
}
],
name: 'newegg'
+13
View File
@@ -0,0 +1,13 @@
import {Store} from './store';
export const Nvidia: Store = {
links: [
{
brand: 'nvidia',
model: 'founders edition',
url: 'https://api.digitalriver.com/v1/shoppers/me/products/5438481700/inventory-status?apiKey=9485fa7b159e42edb08a83bde0d83dia',
oosLabels: ['product_inventory_out_of_stock']
}
],
name: 'nvidia'
};
@@ -3,10 +3,11 @@ interface Link {
model: string;
url: string;
oosLabels: string[];
captchaLabels?: string[];
}
export interface Store {
cartUrl: string;
cartUrl?: string;
links: Link[];
name: string;
}
-20
View File
@@ -1,20 +0,0 @@
import {Store} from './store';
export const Nvidia: Store = {
cartUrl: 'https://store.nvidia.com/store/nvidia/en_US/buy/productID.5438481700/clearCart.yes/nextPage.QuickBuyCartPage',
links: [
{
brand: 'nvidia',
model: 'founders edition',
url: 'https://www.nvidia.com/en-us/geforce/buy/',
oosLabels: ['out of stock']
},
{
brand: 'nvidia',
model: 'founders edition',
url: 'https://www.nvidia.com/en-us/shop/geforce/?page=1&limit=9&locale=en-us&search=3080',
oosLabels: ['out of stock']
}
],
name: 'nvidia'
};
+1
View File
@@ -0,0 +1 @@
declare module 'play-sound';
+1
View File
@@ -0,0 +1 @@
declare module 'pushover-notifications';