diff --git a/.github/workflows/pre-release.yml b/.github/workflows/pre-release.yml
index 120963b..db29ace 100644
--- a/.github/workflows/pre-release.yml
+++ b/.github/workflows/pre-release.yml
@@ -12,10 +12,10 @@ jobs:
steps:
- uses: actions/checkout@v3
- - name: Use Node.js 16.x
+ - name: Use Node.js 20.x
uses: actions/setup-node@v3
with:
- node-version: 16.x
+ node-version: 20.x
- name: Building..
run: |
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 3a93013..11629e9 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -9,10 +9,10 @@ jobs:
steps:
- uses: actions/checkout@v3
- - name: Use Node.js 16.x
+ - name: Use Node.js 20.x
uses: actions/setup-node@v3
with:
- node-version: 16.x
+ node-version: 20.x
- name: Building..
run: |
diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml
index b5bf43b..fd5b055 100644
--- a/.github/workflows/testing.yml
+++ b/.github/workflows/testing.yml
@@ -9,7 +9,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
- node-version: [12.x, 14.x, 16.x]
+ node-version: [20.x]
steps:
- uses: actions/checkout@v3
@@ -23,9 +23,10 @@ jobs:
npm install
npm run test
- name: Upload coverage to Codecov
- uses: codecov/codecov-action@v3
+ uses: codecov/codecov-action@v5
with:
flags: unittests
name: codecov-umbrella
fail_ci_if_error: true
+ token: ${{ secrets.CODECOV_TOKEN }}
verbose: true
\ No newline at end of file
diff --git a/README.md b/README.md
index ce8fa10..e8f8c9d 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,12 @@
-
Steam Enchanter
+
Steam Enchanter
This is extension of Google Chrome browsers for [Steam](https://store.steampowered.com) users. Automate processes for getting badges.
---
+[](https://chrome.google.com/webstore/detail/steam-enchanter/ddjjembcdeddfaebkemgchgfbabbkppl)
+[](https://chrome.google.com/webstore/detail/steam-enchanter/ddjjembcdeddfaebkemgchgfbabbkppl)
+
+
[](https://codecov.io/gh/BigTows/Steam-Enchanter)
## Features
diff --git a/package-lock.json b/package-lock.json
index 6fd19a1..4806eed 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "steam-enchanter",
- "version": "1.1.0",
+ "version": "1.1.2",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "steam-enchanter",
- "version": "1.1.0",
+ "version": "1.1.2",
"license": "MIT",
"dependencies": {
"axios": "^0.27.2",
@@ -1732,6 +1732,7 @@
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz",
"integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
+ "license": "MIT",
"dependencies": {
"follow-redirects": "^1.14.9",
"form-data": "^4.0.0"
@@ -2005,6 +2006,19 @@
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
"dev": true
},
+ "node_modules/call-bind-apply-helpers": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
+ "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
"node_modules/callsites": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
@@ -2486,6 +2500,20 @@
"node": ">=8"
}
},
+ "node_modules/dunder-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
+ "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "gopd": "^1.2.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
"node_modules/electron-to-chromium": {
"version": "1.4.219",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.219.tgz",
@@ -2575,12 +2603,57 @@
"is-arrayish": "^0.2.1"
}
},
+ "node_modules/es-define-property": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
+ "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-errors": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
"node_modules/es-module-lexer": {
"version": "0.9.3",
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz",
"integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==",
"dev": true
},
+ "node_modules/es-object-atoms": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
+ "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-set-tostringtag": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
+ "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.6",
+ "has-tostringtag": "^1.0.2",
+ "hasown": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
"node_modules/escalade": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
@@ -2916,15 +2989,16 @@
}
},
"node_modules/follow-redirects": {
- "version": "1.15.1",
- "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz",
- "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==",
+ "version": "1.15.11",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz",
+ "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
+ "license": "MIT",
"engines": {
"node": ">=4.0"
},
@@ -2935,12 +3009,15 @@
}
},
"node_modules/form-data": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
- "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
+ "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
+ "license": "MIT",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
+ "es-set-tostringtag": "^2.1.0",
+ "hasown": "^2.0.2",
"mime-types": "^2.1.12"
},
"engines": {
@@ -2997,10 +3074,13 @@
}
},
"node_modules/function-bind": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
- "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
- "dev": true
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
},
"node_modules/gensync": {
"version": "1.0.0-beta.2",
@@ -3020,6 +3100,30 @@
"node": "6.* || 8.* || >= 10.*"
}
},
+ "node_modules/get-intrinsic": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
+ "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "es-define-property": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.1.1",
+ "function-bind": "^1.1.2",
+ "get-proto": "^1.0.1",
+ "gopd": "^1.2.0",
+ "has-symbols": "^1.1.0",
+ "hasown": "^2.0.2",
+ "math-intrinsics": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/get-package-type": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz",
@@ -3029,6 +3133,19 @@
"node": ">=8.0.0"
}
},
+ "node_modules/get-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
+ "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
+ "license": "MIT",
+ "dependencies": {
+ "dunder-proto": "^1.0.1",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
"node_modules/get-stream": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
@@ -3108,6 +3225,18 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/gopd": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
+ "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/graceful-fs": {
"version": "4.2.10",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
@@ -3135,6 +3264,45 @@
"node": ">=8"
}
},
+ "node_modules/has-symbols": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
+ "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-tostringtag": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
+ "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
+ "license": "MIT",
+ "dependencies": {
+ "has-symbols": "^1.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/hasown": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+ "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+ "license": "MIT",
+ "dependencies": {
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
"node_modules/html-encoding-sniffer": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz",
@@ -4471,6 +4639,15 @@
"tmpl": "1.0.5"
}
},
+ "node_modules/math-intrinsics": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
+ "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
"node_modules/memory-fs": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz",
@@ -7904,6 +8081,15 @@
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
"dev": true
},
+ "call-bind-apply-helpers": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
+ "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
+ "requires": {
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2"
+ }
+ },
"callsites": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
@@ -8276,6 +8462,16 @@
}
}
},
+ "dunder-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
+ "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
+ "requires": {
+ "call-bind-apply-helpers": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "gopd": "^1.2.0"
+ }
+ },
"electron-to-chromium": {
"version": "1.4.219",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.219.tgz",
@@ -8344,12 +8540,41 @@
"is-arrayish": "^0.2.1"
}
},
+ "es-define-property": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
+ "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="
+ },
+ "es-errors": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="
+ },
"es-module-lexer": {
"version": "0.9.3",
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz",
"integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==",
"dev": true
},
+ "es-object-atoms": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
+ "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
+ "requires": {
+ "es-errors": "^1.3.0"
+ }
+ },
+ "es-set-tostringtag": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
+ "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
+ "requires": {
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.6",
+ "has-tostringtag": "^1.0.2",
+ "hasown": "^2.0.2"
+ }
+ },
"escalade": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
@@ -8604,17 +8829,19 @@
}
},
"follow-redirects": {
- "version": "1.15.1",
- "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz",
- "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA=="
+ "version": "1.15.11",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz",
+ "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ=="
},
"form-data": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
- "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
+ "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
+ "es-set-tostringtag": "^2.1.0",
+ "hasown": "^2.0.2",
"mime-types": "^2.1.12"
}
},
@@ -8657,10 +8884,9 @@
"optional": true
},
"function-bind": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
- "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
- "dev": true
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="
},
"gensync": {
"version": "1.0.0-beta.2",
@@ -8674,12 +8900,38 @@
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
"dev": true
},
+ "get-intrinsic": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
+ "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
+ "requires": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "es-define-property": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.1.1",
+ "function-bind": "^1.1.2",
+ "get-proto": "^1.0.1",
+ "gopd": "^1.2.0",
+ "has-symbols": "^1.1.0",
+ "hasown": "^2.0.2",
+ "math-intrinsics": "^1.1.0"
+ }
+ },
"get-package-type": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz",
"integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==",
"dev": true
},
+ "get-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
+ "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
+ "requires": {
+ "dunder-proto": "^1.0.1",
+ "es-object-atoms": "^1.0.0"
+ }
+ },
"get-stream": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
@@ -8735,6 +8987,11 @@
"slash": "^3.0.0"
}
},
+ "gopd": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
+ "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="
+ },
"graceful-fs": {
"version": "4.2.10",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
@@ -8756,6 +9013,27 @@
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true
},
+ "has-symbols": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
+ "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="
+ },
+ "has-tostringtag": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
+ "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
+ "requires": {
+ "has-symbols": "^1.0.3"
+ }
+ },
+ "hasown": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+ "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+ "requires": {
+ "function-bind": "^1.1.2"
+ }
+ },
"html-encoding-sniffer": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz",
@@ -9782,6 +10060,11 @@
"tmpl": "1.0.5"
}
},
+ "math-intrinsics": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
+ "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="
+ },
"memory-fs": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz",
diff --git a/package.json b/package.json
index 55ff89a..ac73069 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "steam-enchanter",
- "version": "1.1.0",
+ "version": "1.1.2",
"description": "Google Chrome extension for Steam. Automating some actions for Level up your account.",
"main": "index.js",
"scripts": {
diff --git a/public/logo.png b/public/logo.png
deleted file mode 100644
index 6c713ba..0000000
Binary files a/public/logo.png and /dev/null differ
diff --git a/public/manifest.json b/public/manifest.json
index 4362d02..4a29b0d 100644
--- a/public/manifest.json
+++ b/public/manifest.json
@@ -2,11 +2,17 @@
"manifest_version": 3,
"name": "Steam Enchanter",
"description": "Automating some actions for Level up your Steam account.",
- "version": "1.1.0",
+ "version": "1.1.2",
"key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyPmdRVJ9XxGnV4qLbRm7pEM8kUzOa6MnJFJ43fstWn6wIktC6lWZ7Qz9oIyvGua9ytYSTaqsavQksPa8eBY8L9V+Hd6xOEap82SfT353N0P9M/ZLQsG1X/KtUijaoMxoPl5VNBz+h0tuVhNHFYjeFqtujTU1JrY+Dv4U0COQv4wiGUUfdh0QVIxLg/ELK/ltmM4xsIz6EehrowY6GGjQiT7PJPda6MwS0WaJeJa6HgvIAILISVDNMFD2CipiuHZjcxC3FQQGMabciNwiv5a3sY7wyum1zWUJb71DAJV3X0eqLuDXuCtoJm+O0HOFnhtVXeR9b4WtqYyOGk92yDuFmwIDAQAB",
"action": {
"default_icon": "icon.png"
},
+ "icons": {
+ "16": "icon.png",
+ "32": "icon.png",
+ "48": "icon.png",
+ "128": "icon.png"
+ },
"content_scripts": [
{
"matches": [
diff --git a/src/__tests__/SteamMarketApiTest.ts b/src/__tests__/SteamMarketApiTest.ts
index 320566c..ea7b81f 100644
--- a/src/__tests__/SteamMarketApiTest.ts
+++ b/src/__tests__/SteamMarketApiTest.ts
@@ -45,6 +45,35 @@ test("Create order", async () => {
});
+test("Can't create order, need confirmation", async () => {
+ const mockHttp = mock();
+ const steamMarketApi = new SteamMarketApiImpl("localhost", mockHttp);
+
+ mockHttp.post.mockReturnValue(new Promise((resolve) => {
+ resolve(
+ {
+ success: 22,
+ confirmation:{
+ confirmation_id: "124124124",
+ }
+ }
+ );
+ }));
+
+ await expect(() => {
+ return steamMarketApi.createOrder(
+ {
+ sessionId: "124",
+ currency: 5,
+ appId: 730,
+ marketHashName: "Any",
+ priceTotal: 23,
+ quantity: 151
+ }
+ );
+ }).rejects.toThrowError("You need to confirm your order (124124124).");
+});
+
test("Create order, unsuccessful", async () => {
const mockHttp = mock();
const steamMarketApi = new SteamMarketApiImpl("localhost", mockHttp);
diff --git a/src/__tests__/pages/SteamPageLoaderTest.ts b/src/__tests__/pages/SteamPageLoaderTest.ts
index 9470cd0..f6a04d2 100644
--- a/src/__tests__/pages/SteamPageLoaderTest.ts
+++ b/src/__tests__/pages/SteamPageLoaderTest.ts
@@ -1,22 +1,67 @@
import "reflect-metadata";
+import { anyObject, mock } from "jest-mock-extended";
+import HttpClient from "../../component/http/HttpClient";
+import GameCardsPage from "../../steam/pages/GameCardsPage";
+import SteamPageLoader from "../../steam/pages/SteamPageLoader";
+import CardMarketPage from "../../steam/pages/CardMarketPage";
+import UserCompletedBadgesPage from "../../steam/pages/UserCompletedBadgesPage";
+const host = "http://localhost";
-test("Load game card", () => {
- // TODO const httpClientMock = mock();
- // const host = "http://localhost";
- //
- // const steamPageLoader = new SteamPageLoader(host, httpClientMock);
- // const steamId = "12414124";
- // const appId = 1244;
- //
- // const mockedPage = mock();
- //
- // console.log(`${host}/profiles/${steamId}/gamecards/${appId}`)
- // httpClientMock.get
- // .mockReturnValue(new Promise(resolve => resolve(mockedPage)));
- //
- // const result = steamPageLoader.loadGameCard(steamId, appId);
- //
- // expect(result).toBe(mockedPage);
-
-});
\ No newline at end of file
+test("Load game card", async () => {
+ const httpClientMock = mock();
+
+ const steamPageLoader = new SteamPageLoader(host, httpClientMock);
+ const steamId = "12414124";
+ const appId = 1244;
+
+ const mockedPage = mock();
+
+ httpClientMock.get
+ .calledWith(`${host}/profiles/${steamId}/gamecards/${appId}`, anyObject())
+ .mockReturnValue(new Promise(resolve => {
+ resolve(mockedPage)
+ }));
+
+ const result = await steamPageLoader.loadGameCard(steamId, appId);
+ expect(result).toBe(mockedPage);
+});
+
+test("Load card market page", async ()=>{
+ const httpClientMock = mock();
+
+ const steamPageLoader = new SteamPageLoader(host, httpClientMock);
+
+ const link = 'ajkfklajkaakfjalf';
+
+ const mockedPage = mock();
+
+ httpClientMock.get
+ .calledWith(link, anyObject())
+ .mockReturnValue(new Promise(resolve => {
+ resolve(mockedPage)
+ }));
+
+ const result = await steamPageLoader.loadCardMarketPage(link);
+ expect(result).toBe(mockedPage);
+})
+
+
+test("Load user compled badges", async ()=>{
+ const httpClientMock = mock();
+
+ const steamPageLoader = new SteamPageLoader(host, httpClientMock);
+ const steamId = "12414124";
+ const page = 1244;
+
+ const mockedPage = mock();
+
+ httpClientMock.get
+ .calledWith(`${host}/profiles/${steamId}/badges/?sort=c&p=${page}`, anyObject())
+ .mockReturnValue(new Promise(resolve => {
+ resolve(mockedPage)
+ }));
+
+ const result = await steamPageLoader.loadUserCompletedBadges(steamId, page);
+ expect(result).toBe(mockedPage);
+})
\ No newline at end of file
diff --git a/src/__tests__/resources/html/steamCardMarketPage.html b/src/__tests__/resources/html/steamCardMarketPage.html
index 45c7dcc..dc81320 100644
--- a/src/__tests__/resources/html/steamCardMarketPage.html
+++ b/src/__tests__/resources/html/steamCardMarketPage.html
@@ -486,7 +486,7 @@
-
+
Buy multiple types of items
diff --git a/src/__tests__/service/SteamCardTraderServiceTest.ts b/src/__tests__/service/SteamCardTraderServiceTest.ts
new file mode 100644
index 0000000..6850ad1
--- /dev/null
+++ b/src/__tests__/service/SteamCardTraderServiceTest.ts
@@ -0,0 +1,54 @@
+import "reflect-metadata";
+import SteamMarketApi from "../../api/steam/SteamMarketApi";
+import { mock } from "jest-mock-extended";
+import SteamCardTraderService from "../../service/SteamCardTraderService";
+import Cookies from "js-cookie";
+import { Status } from "../../service/SteamCardTraderProcess";
+
+test("Create trader process.", async () => {
+
+ const steamApiMock = mock();
+ const sessionId = "12414";
+ Cookies.set("sessionid", sessionId);//TODO side effect :(
+
+ const service = new SteamCardTraderService(steamApiMock);
+
+
+ steamApiMock.createOrder.calledWith(
+ {
+ sessionId: sessionId,
+ currency: 5,
+ appId: 10,
+ marketHashName: "112",
+ priceTotal: (91 + 200) * 2,
+ quantity: 2
+ }).mockReturnValue(new Promise(resolve => resolve("order-1")));
+
+ const process = await service.createTrader([
+ {
+ appId: 10,
+ hashName: "112",
+ quantity: 2,
+ price: 91
+ }
+ ], 5);
+
+ expect(process.getCurrentStatus()).toBe(Status.pending);
+});
+
+test("When session id is not initialized", async () => {
+ const steamApiMock = mock();
+ Cookies.remove('sessionid')
+ const service = new SteamCardTraderService(steamApiMock);
+
+ await expect(async () => {
+ await service.createTrader([
+ {
+ appId: 10,
+ hashName: "112",
+ quantity: 2,
+ price: 91
+ }
+ ], 5);
+ }).rejects.toThrowError("Session id is not initialized");
+});
\ No newline at end of file
diff --git a/src/api/steam/SteamMarketApiImpl.ts b/src/api/steam/SteamMarketApiImpl.ts
index 4bdf943..2bc2f0f 100644
--- a/src/api/steam/SteamMarketApiImpl.ts
+++ b/src/api/steam/SteamMarketApiImpl.ts
@@ -1,99 +1,122 @@
import HttpClient from "../../component/http/HttpClient";
-import { inject, injectable } from "tsyringe";
-import { Tokens } from "../../configuration/Injector";
-import SteamMarketApi, { CreateMarkerOrderRequest, OrderStatusResponse } from "./SteamMarketApi";
+import {inject, injectable} from "tsyringe";
+import {Tokens} from "../../configuration/Injector";
+import SteamMarketApi, {CreateMarkerOrderRequest, OrderStatusResponse} from "./SteamMarketApi";
+import StreamApiException from "./exception/StreamApiException";
+import NeedConfirmationStreamApiException from "./exception/NeedConfirmationStreamApiException";
interface CreateMarketOrderResponse {
- success: number,
- buy_orderid: string
+ success: number,
+ buy_orderid: string
+ confirmation?: {
+ confirmation_id: string
+ }
}
interface OrderStatusResponseRaw {
- success: number,
- active: number,
- purchased: number,
- quantity: string,
- quantity_remaining: string
+ success: number,
+ active: number,
+ purchased: number,
+ quantity: string,
+ quantity_remaining: string
}
@injectable()
class SteamMarketApiImpl implements SteamMarketApi {
- private readonly steamHost: string;
- private readonly httpClient: HttpClient;
-
- private static readonly COUNT_RETRIES = 6;
-
- private static readonly STEAM_RETRIES_CODES = [
- 10,//The game's servers are currently too busy. Your pu…unds have been exchanged. Please try again later
- 40,//Tod many request
- 107//Извините! Серверы Steam не ответили на запрос о ва…полнен. Если это не так, повторите попытку позже.
- ];
-
- constructor(@inject(Tokens.STEAM_API) host: string, @inject(Tokens.HTTP_CLIENT) httpClient: HttpClient) {
- this.steamHost = host;
- this.httpClient = httpClient;
- }
-
- /**
- * Create order at steam market.
- */
- public async createOrder(request: CreateMarkerOrderRequest): Promise {
- const data = new URLSearchParams();
- data.append("sessionid", request.sessionId);
- data.append("currency", request.currency as unknown as string);
- data.append("appid", request.appId as unknown as string);
- data.append("market_hash_name", request.marketHashName);
- data.append("price_total", request.priceTotal as unknown as string);
- data.append("quantity", request.quantity as unknown as string);
- data.append("billing_state", "");
- data.append("save_my_address", "0");
-
- const result = await this.httpClient.post(`${this.steamHost}/market/createbuyorder/`, data, {
- retries: {
- count: SteamMarketApiImpl.COUNT_RETRIES,
- needRetry: (result) => {
- return SteamMarketApiImpl.STEAM_RETRIES_CODES.includes(result.success);
+ private readonly steamHost: string;
+ private readonly httpClient: HttpClient;
+
+ private static readonly COUNT_RETRIES = 6;
+
+ /**
+ * 22 - The order has been placed, but you need to confirm it.
+ * @private
+ */
+ private static readonly STEAM_NEED_CONFIRMATION = 22;
+
+ /**
+ * Slow down, You have tried too many purchases without confirmation. Please wait a few minutes before trying again.
+ * @private
+ */
+ private static readonly STEAM_TOO_MANY_PURCHASED = 84;
+
+ private static readonly STEAM_RETRIES_CODES = [
+ 10,//The game's servers are currently too busy. Your pu…unds have been exchanged. Please try again later
+ 40,//Tod many request
+ 107//Извините! Серверы Steam не ответили на запрос о ва…полнен. Если это не так, повторите попытку позже.
+ ];
+
+ constructor(@inject(Tokens.STEAM_API) host: string, @inject(Tokens.HTTP_CLIENT) httpClient: HttpClient) {
+ this.steamHost = host;
+ this.httpClient = httpClient;
+ }
+
+ /**
+ * Create order at steam market.
+ * @return The promise of order id
+ */
+ public async createOrder(request: CreateMarkerOrderRequest): Promise {
+ const data = new URLSearchParams();
+ data.append("sessionid", request.sessionId);
+ data.append("currency", request.currency as unknown as string);
+ data.append("appid", request.appId as unknown as string);
+ data.append("market_hash_name", request.marketHashName);
+ data.append("price_total", request.priceTotal as unknown as string);
+ data.append("quantity", request.quantity as unknown as string);
+ data.append("billing_state", "");
+ data.append("save_my_address", "0");
+
+ const result = await this.httpClient.post(`${this.steamHost}/market/createbuyorder/`, data, {
+ retries: {
+ count: SteamMarketApiImpl.COUNT_RETRIES,
+ needRetry: (result) => {
+ return SteamMarketApiImpl.STEAM_RETRIES_CODES.includes(result.success);
+ }
+ }
+ });
+
+ if (result.success === 1) {
+ return result.buy_orderid;
+ }
+
+ if (result.success === SteamMarketApiImpl.STEAM_NEED_CONFIRMATION) {
+ throw new NeedConfirmationStreamApiException(result.confirmation!.confirmation_id);
}
- }
- });
- if (result.success === 1) {
- return result.buy_orderid;
+ throw new StreamApiException("Can't place order at Steam :( Code: " + result.success);
}
- throw new Error("Can't place order at Steam :(");
- }
- public async getOrderStatus(sessionId: string, orderId: string): Promise {
- const resultRaw = await this.httpClient.get(`${this.steamHost}/market/getbuyorderstatus/?sessionid=${sessionId}&buy_orderid=${orderId}`);
+ public async getOrderStatus(sessionId: string, orderId: string): Promise {
+ const resultRaw = await this.httpClient.get(`${this.steamHost}/market/getbuyorderstatus/?sessionid=${sessionId}&buy_orderid=${orderId}`);
- if (resultRaw.success !== 1) {
- throw new Error("Can't get order status at Steam :(");
- }
+ if (resultRaw.success !== 1) {
+ throw new Error("Can't get order status at Steam :(");
+ }
- return {
- success: resultRaw.success === 1,
- active: resultRaw.active === 1,
- purchased: resultRaw.purchased,
- quantity: parseInt(resultRaw.quantity),
- quantityRemaining: parseInt(resultRaw.quantity_remaining)
- };
- }
+ return {
+ success: resultRaw.success === 1,
+ active: resultRaw.active === 1,
+ purchased: resultRaw.purchased,
+ quantity: parseInt(resultRaw.quantity),
+ quantityRemaining: parseInt(resultRaw.quantity_remaining)
+ };
+ }
- public async cancelOrder(sessionId: string, orderId: string): Promise {
+ public async cancelOrder(sessionId: string, orderId: string): Promise {
- const data = new URLSearchParams();
- data.append("sessionid", sessionId);
- data.append("buy_orderid", orderId);
+ const data = new URLSearchParams();
+ data.append("sessionid", sessionId);
+ data.append("buy_orderid", orderId);
- const result = await this.httpClient.post(`${this.steamHost}/market/cancelbuyorder/`, data);
+ const result = await this.httpClient.post(`${this.steamHost}/market/cancelbuyorder/`, data);
- if (result.success !== 1) {
- throw new Error("Can't cancel order at Steam :(");
+ if (result.success !== 1) {
+ throw new Error("Can't cancel order at Steam :(");
+ }
}
- }
}
diff --git a/src/api/steam/exception/NeedConfirmationStreamApiException.ts b/src/api/steam/exception/NeedConfirmationStreamApiException.ts
new file mode 100644
index 0000000..80f18ac
--- /dev/null
+++ b/src/api/steam/exception/NeedConfirmationStreamApiException.ts
@@ -0,0 +1,13 @@
+import StreamApiException from "./StreamApiException";
+
+class NeedConfirmationStreamApiException extends StreamApiException {
+
+ readonly confirmationId: string;
+
+ constructor(confirmationId: string) {
+ super(`You need to confirm your order (${confirmationId}).`);
+ this.confirmationId = confirmationId;
+ }
+}
+
+export default NeedConfirmationStreamApiException;
\ No newline at end of file
diff --git a/src/api/steam/exception/StreamApiException.ts b/src/api/steam/exception/StreamApiException.ts
new file mode 100644
index 0000000..283cec3
--- /dev/null
+++ b/src/api/steam/exception/StreamApiException.ts
@@ -0,0 +1,8 @@
+class StreamApiException extends Error {
+
+ constructor(message: string) {
+ super(message);
+ }
+}
+
+export default StreamApiException;
\ No newline at end of file
diff --git a/src/component/http/AxiosHttpClient.ts b/src/component/http/AxiosHttpClient.ts
index 3f3ab1b..f496141 100644
--- a/src/component/http/AxiosHttpClient.ts
+++ b/src/component/http/AxiosHttpClient.ts
@@ -1,77 +1,77 @@
-import HttpClient, { HttpClientOptions } from "./HttpClient";
-import { Axios, AxiosRequestConfig } from "axios";
+import HttpClient, {HttpClientOptions} from "./HttpClient";
+import {Axios, AxiosRequestConfig} from "axios";
class AxiosHttpClient implements HttpClient {
- private readonly axiosInstance;
-
- constructor() {
- this.axiosInstance = new Axios({
- withCredentials: true,
- transformResponse: [function transformResponse(data, headers) {
- if (headers?.["content-type"].includes("text/html")) {
- const root = document.createElement("html");
- root.innerHTML = data;
- return root;
- } else {
- return JSON.parse(data);
- }
- }]
- });
- }
-
-
- async get(url: string, options?: HttpClientOptions): Promise {
- return this.executeRequest({
- url: url,
- method: "GET"
- }, options);
- }
-
- post(url: string, data?: D, options?: HttpClientOptions): Promise {
- return this.executeRequest({
- url: url,
- method: "POST",
- data: data
- }, options);
- }
-
-
- private async executeRequest(configuration: AxiosRequestConfig, options?: HttpClientOptions): Promise {
- const result = await this.axiosInstance.request(configuration);
- let resultData = result.data;
-
-
- try {
- if (options?.transformer) {
- resultData = options.transformer(resultData);
- }
- } catch (err) {
- return this.processRetries(configuration, options);
+ private readonly axiosInstance;
+
+ constructor() {
+ this.axiosInstance = new Axios({
+ withCredentials: true,
+ transformResponse: [function transformResponse(data, headers) {
+ if (headers?.["content-type"].includes("text/html")) {
+ const root = document.createElement("html");
+ root.innerHTML = data;
+ return root;
+ } else {
+ return JSON.parse(data);
+ }
+ }]
+ });
+ }
+
+
+ async get(url: string, options?: HttpClientOptions): Promise {
+ return this.executeRequest({
+ url: url,
+ method: "GET"
+ }, options);
}
- if (options?.retries !== undefined && options.retries.needRetry(resultData)) {
- return this.processRetries(configuration, options);
+ post(url: string, data?: D, options?: HttpClientOptions): Promise {
+ return this.executeRequest({
+ url: url,
+ method: "POST",
+ data: data
+ }, options);
}
- return await new Promise((resolve) => {
- return resolve(resultData);
- });
- }
- private async processRetries(configuration: AxiosRequestConfig, options?: HttpClientOptions): Promise {
- if (options?.retries === undefined) {
- throw new Error("Can't process request");
+ private async executeRequest(configuration: AxiosRequestConfig, options?: HttpClientOptions): Promise {
+ const result = await this.axiosInstance.request(configuration);
+ let resultData = result.data;
+
+
+ try {
+ if (options?.transformer) {
+ resultData = options.transformer(resultData);
+ }
+ } catch (err) {
+ return this.processRetries(configuration, options, err);
+ }
+
+ if (options?.retries !== undefined && options.retries.needRetry(resultData)) {
+ return this.processRetries(configuration, options);
+ }
+
+ return await new Promise((resolve) => {
+ return resolve(resultData);
+ });
}
- if (options.retries.count > 0) {
- options.retries.count -= 1;
- console.log(`Request ${configuration.url}, was not successfully, retry ${options.retries.count}`);
- await new Promise(s => setTimeout(s, 1500));
- return await this.executeRequest(configuration, options);
+ private async processRetries(configuration: AxiosRequestConfig, options?: HttpClientOptions, err?: any): Promise {
+ if (options?.retries === undefined) {
+ throw new Error("Can't process request");
+ }
+
+ if (options.retries.count > 0) {
+ options.retries.count -= 1;
+ console.warn(`Request ${configuration.url}, was not successfully (${err?.message}), retry ${options.retries.count}`);
+ await new Promise(s => setTimeout(s, 1500));
+ return await this.executeRequest(configuration, options);
+ }
+ throw new Error("Retries was end.");
}
- throw new Error("Retries was end.");
- }
}
diff --git a/src/service/SteamCardTraderProcess.ts b/src/service/SteamCardTraderProcess.ts
index 124cf88..fe83b53 100644
--- a/src/service/SteamCardTraderProcess.ts
+++ b/src/service/SteamCardTraderProcess.ts
@@ -1,80 +1,81 @@
import SteamMarketApi from "../api/steam/SteamMarketApi";
export interface CardOrderOperationContext {
- orderId: string,
- quantity: number
+ orderId: string,
+ quantity: number
}
export enum Status {
- pending,
- finished,
- error
+ pending,
+ need_confirmation,
+ finished,
+ error
}
class SteamCardTraderProcess {
- private readonly steamApi: SteamMarketApi;
- private readonly cardOrderOperationContexts: Array;
- private readonly interval: NodeJS.Timer;
- private readonly sessionId: string;
+ private readonly steamApi: SteamMarketApi;
+ private readonly cardOrderOperationContexts: Array;
+ private readonly interval: NodeJS.Timer;
+ private readonly sessionId: string;
- private currentStatus: Status = Status.pending;
+ private currentStatus: Status = Status.pending;
- constructor(steamApi: SteamMarketApi, sessionId: string, cardOrderOperationContexts: Array) {
- this.steamApi = steamApi;
- this.sessionId = sessionId;
- this.cardOrderOperationContexts = cardOrderOperationContexts;
+ constructor(steamApi: SteamMarketApi, sessionId: string, cardOrderOperationContexts: Array) {
+ this.steamApi = steamApi;
+ this.sessionId = sessionId;
+ this.cardOrderOperationContexts = cardOrderOperationContexts;
- const self = this;
- this.interval = setInterval(async () => {
- await this.checkOrders(self);
- }, 3000);
- }
-
- private async checkOrders(self: SteamCardTraderProcess) {
- if (self.cardOrderOperationContexts.length === 0) {
- console.log("Terminate task");
- clearInterval(self.interval);
- this.currentStatus = Status.error;
+ const self = this;
+ this.interval = setInterval(async () => {
+ await this.checkOrders(self);
+ }, 3000);
}
- for (let context of self.cardOrderOperationContexts) {
- const currentStatus = await self.steamApi.getOrderStatus(self.sessionId, context.orderId);
- if (!currentStatus.active || currentStatus.purchased === context.quantity) {
- this.deleteOrder(context.orderId);
- }
- console.log(currentStatus.purchased);
- }
+ private async checkOrders(self: SteamCardTraderProcess) {
+ if (self.cardOrderOperationContexts.length === 0) {
+ console.log("Terminate task");
+ clearInterval(self.interval);
+ this.currentStatus = Status.error;
+ }
- if (self.cardOrderOperationContexts.length === 0) {
- console.log("Finished task");
- clearInterval(self.interval);
- this.currentStatus = Status.finished;
+ for (let context of self.cardOrderOperationContexts) {
+ const currentStatus = await self.steamApi.getOrderStatus(self.sessionId, context.orderId);
+ if (!currentStatus.active || currentStatus.purchased === context.quantity) {
+ this.deleteOrder(context.orderId);
+ }
+ console.log(currentStatus.purchased);
+ }
+
+ if (self.cardOrderOperationContexts.length === 0) {
+ console.log("Finished task");
+ clearInterval(self.interval);
+ this.currentStatus = Status.finished;
+ }
}
- }
- public getCurrentStatus(): Status {
- return this.currentStatus;
- }
+ public getCurrentStatus(): Status {
+ return this.currentStatus;
+ }
- public async cancel() {
- for (let context of this.cardOrderOperationContexts) {
- await this.steamApi.cancelOrder(this.sessionId, context.orderId);
- this.deleteOrder(context.orderId);
+ public async cancel() {
+ for (let context of this.cardOrderOperationContexts) {
+ await this.steamApi.cancelOrder(this.sessionId, context.orderId);
+ this.deleteOrder(context.orderId);
+ }
}
- }
- private deleteOrder(orderId: string) {
- const result = this.cardOrderOperationContexts.find(context => {
- return context.orderId === orderId;
- });
- if (result !== undefined) {
- console.log(`delete order ${orderId}`);
- this.cardOrderOperationContexts.splice(
- this.cardOrderOperationContexts.indexOf(result), 1
- );
+ private deleteOrder(orderId: string) {
+ const result = this.cardOrderOperationContexts.find(context => {
+ return context.orderId === orderId;
+ });
+ if (result !== undefined) {
+ console.log(`delete order ${orderId}`);
+ this.cardOrderOperationContexts.splice(
+ this.cardOrderOperationContexts.indexOf(result), 1
+ );
+ }
}
- }
}
export default SteamCardTraderProcess;
\ No newline at end of file
diff --git a/src/service/SteamCardTraderService.ts b/src/service/SteamCardTraderService.ts
index b9f9bd4..9018990 100644
--- a/src/service/SteamCardTraderService.ts
+++ b/src/service/SteamCardTraderService.ts
@@ -1,62 +1,58 @@
-import SteamCardTraderProcess, { CardOrderOperationContext } from "./SteamCardTraderProcess";
-import { CardMarketPosition } from "../steam/pages/component/CardBuyerTable";
+import SteamCardTraderProcess, {CardOrderOperationContext} from "./SteamCardTraderProcess";
+import {CardMarketPosition} from "../steam/pages/component/CardBuyerTable";
import Cookies from "js-cookie";
-import { inject, injectable } from "tsyringe";
+import {inject, injectable} from "tsyringe";
import SteamMarketApi from "../api/steam/SteamMarketApi";
-import { Tokens } from "../configuration/Injector";
+import {Tokens} from "../configuration/Injector";
-interface TradeOptions {
-
-}
@injectable()
class SteamCardTraderService {
- private readonly steamMarketApi: SteamMarketApi;
-
- constructor(@inject(Tokens.STEAM_MARKET_API) steamMarketApi: SteamMarketApi) {
- this.steamMarketApi = steamMarketApi;
- }
+ private readonly steamMarketApi: SteamMarketApi;
+ constructor(@inject(Tokens.STEAM_MARKET_API) steamMarketApi: SteamMarketApi) {
+ this.steamMarketApi = steamMarketApi;
+ }
- public async createTrader(positions: Array, currencyId: number): Promise {
- const sessionId = this.getSessionId();
- const cardOrderOperationContexts: Array = [];
+ public async createTrader(positions: Array, currencyId: number): Promise {
+ const sessionId = this.getSessionId();
- for (const position of positions) {
+ const cardOrderOperationContexts: Array = [];
- const result = await this.createOrder(sessionId, position, currencyId);
- cardOrderOperationContexts.push(
- {
- orderId: result,
- quantity: position.quantity
+ for (const position of positions) {
+ const result = await this.createOrder(sessionId, position, currencyId);
+ cardOrderOperationContexts.push(
+ {
+ orderId: result,
+ quantity: position.quantity
+ }
+ );
}
- );
+ return new SteamCardTraderProcess(this.steamMarketApi, sessionId, cardOrderOperationContexts);
}
- return new SteamCardTraderProcess(this.steamMarketApi, sessionId, cardOrderOperationContexts);
- }
- private async createOrder(sessionId: string, position: CardMarketPosition, currencyId: number): Promise {
- const maximumOverprice = 200;// TODO 200 is maximum overprice for position, move to options.
+ private async createOrder(sessionId: string, position: CardMarketPosition, currencyId: number): Promise {
+ const maximumOverprice = 200;// TODO 200 is maximum overprice for position, move to options.
- return await this.steamMarketApi.createOrder({
- sessionId: sessionId,
- currency: currencyId,
- appId: position.appId,
- marketHashName: position.hashName,
- priceTotal: (position.price + maximumOverprice) * position.quantity,
- quantity: position.quantity
- });
- }
+ return await this.steamMarketApi.createOrder({
+ sessionId: sessionId,
+ currency: currencyId,
+ appId: position.appId,
+ marketHashName: position.hashName,
+ priceTotal: (position.price + maximumOverprice) * position.quantity,
+ quantity: position.quantity
+ });
+ }
- private getSessionId(): string {
- const sessionId = Cookies.get("sessionid");
- if (sessionId === undefined) {
- throw new Error("Session id is not initialized");
+ private getSessionId(): string {
+ const sessionId = Cookies.get("sessionid");
+ if (sessionId === undefined) {
+ throw new Error("Session id is not initialized");
+ }
+ return sessionId;
}
- return sessionId;
- }
}
diff --git a/src/steam/pages/CardMarketPage.ts b/src/steam/pages/CardMarketPage.ts
index 3832380..fceb5a5 100644
--- a/src/steam/pages/CardMarketPage.ts
+++ b/src/steam/pages/CardMarketPage.ts
@@ -17,7 +17,7 @@ class CardMarketPage extends SteamPage {
private static readonly configuration: Array = [
{
name: Components.Table,
- selector: "#BG_bottom > table",
+ selector: "#multibuy_ctn > table",
component: new ComponentLoader(CardBuyerTable)
},
{
diff --git a/src/steam/pages/SteamPageLoader.ts b/src/steam/pages/SteamPageLoader.ts
index 1c3989a..fda2d33 100644
--- a/src/steam/pages/SteamPageLoader.ts
+++ b/src/steam/pages/SteamPageLoader.ts
@@ -17,7 +17,6 @@ class SteamPageLoader {
}
public async loadGameCard(steamId: string, appId: number): Promise {
- console.log(`${this.host}/profiles/${steamId}/gamecards/${appId}`)
return await this.httpClient.get(`${this.host}/profiles/${steamId}/gamecards/${appId}`, {
retries: {
count: 4,
diff --git a/src/ui/react/component/Badge.tsx b/src/ui/react/component/Badge.tsx
index 25c8cd9..5ad638d 100644
--- a/src/ui/react/component/Badge.tsx
+++ b/src/ui/react/component/Badge.tsx
@@ -6,6 +6,7 @@ import { injector } from "../../../configuration/Injector";
import SteamCardTraderService from "../../../service/SteamCardTraderService";
import { CardMarketPosition } from "../../../steam/pages/component/CardBuyerTable";
import { Status } from "../../../service/SteamCardTraderProcess";
+import NeedConfirmationStreamApiException from "../../../api/steam/exception/NeedConfirmationStreamApiException";
interface BadgeProperties {
steamId: string,
@@ -17,6 +18,7 @@ enum BadgeStatus {
Waiting,
Processing,
PriceLoaded,
+ NeedConfirmation = 4,
Completed,
Error
}
@@ -98,13 +100,20 @@ Items will be purchased at the cheapest price available, so the order may end up
);
case BadgeStatus.PriceLoaded:
return (
- PLACE ORDER
);
case BadgeStatus.Completed:
return (
✔️
);
+ case BadgeStatus.NeedConfirmation:
+ return (
+
+ Check Steam App, try again
+
+ );
case BadgeStatus.Error:
return (
@@ -163,8 +172,12 @@ Items will be purchased at the cheapest price available, so the order may end up
}
}, 1000);
}).catch(error => {
- console.error(error);
- this.setState({ status: BadgeStatus.Error });
+ if (error instanceof NeedConfirmationStreamApiException){
+ this.setState({ status: BadgeStatus.NeedConfirmation });
+ }else {
+ console.error(error);
+ this.setState({status: BadgeStatus.Error});
+ }
});
}