diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index a07694c58..5d1bc82ca 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -22,8 +22,8 @@ Steps to reproduce the behavior: **Expected behavior** A clear and concise description of what you expected to happen. -**Screenshots** -If applicable, add screenshots to help explain your problem. +**Error messages** +If applicable, add error messages to help explain your problem. **Additional context** Add any other context about the problem here. diff --git a/.github/workflows/doc-publish.yml b/.github/workflows/doc-publish.yml index 29a5a73ec..9cd4d0af6 100644 --- a/.github/workflows/doc-publish.yml +++ b/.github/workflows/doc-publish.yml @@ -10,12 +10,12 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Set up node - uses: actions/setup-node@v1 + uses: actions/setup-node@v4 with: - node-version: 20 + node-version: 24 - name: Install yarn run: npm install -g yarn diff --git a/.github/workflows/npmpublish.yml b/.github/workflows/npmpublish.yml index 133306eff..485713843 100644 --- a/.github/workflows/npmpublish.yml +++ b/.github/workflows/npmpublish.yml @@ -4,22 +4,30 @@ on: pull_request: branches: - master + - next push: branches: - master + - next + +permissions: + contents: write + packages: write + id-token: write + issues: write jobs: test: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Set up node - uses: actions/setup-node@v1 + uses: actions/setup-node@v4 with: - node-version: 20 + node-version: 24 - name: Install yarn run: npm install -g yarn @@ -35,23 +43,13 @@ jobs: if: github.event_name == 'push' runs-on: ubuntu-latest steps: - - name: Checkout code with ADMIN_TOKEN - if: github.event.pull_request.head.repo.full_name == github.repository - uses: actions/checkout@v2 - with: - token: ${{ secrets.ADMIN_TOKEN }} - - name: Checkout code - if: github.event.pull_request.head.repo.full_name != github.repository - uses: actions/checkout@v2 - - - name: Prepare repository - run: git fetch --unshallow --tags + uses: actions/checkout@v4 - name: Set up node - uses: actions/setup-node@v1 + uses: actions/setup-node@v4 with: - node-version: 20 + node-version: 24 - name: Install yarn run: npm install -g yarn @@ -60,7 +58,7 @@ jobs: run: yarn install --frozen-lockfile - name: Cache node modules - uses: actions/cache@v1 + uses: actions/cache@v4 with: path: node_modules key: yarn-deps-${{ hashFiles('yarn.lock') }} @@ -68,8 +66,7 @@ jobs: yarn-deps-${{ hashFiles('yarn.lock') }} - name: Create Release + run: npx semantic-release@25.0.3 env: - token: ${{ secrets.ADMIN_TOKEN }} - NPM_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }} - run: | - npx auto shipit + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 1473bc1ff..773b3f357 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -6,27 +6,44 @@ on: jobs: test: + permissions: + id-token: write + runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Set up node - uses: actions/setup-node@v1 + uses: actions/setup-node@v4 with: - node-version: 20 + node-version: 24 - - name: Install yarn - run: npm install -g yarn + - name: Enable Corepack + run: corepack enable - name: Install dependencies - run: yarn install + run: yarn install --frozen-lockfile - name: Lint lib/ run: yarn lint + + - id: auth + name: Generate ID Token + uses: google-github-actions/auth@v2 + with: + token_format: id_token + workload_identity_provider: ${{ vars.workload_identity_provider }} + service_account: ${{ vars.service_account }} + id_token_audience: "https://${{ vars.forwarder_hostname }}" + id_token_include_email: true + - name: Run tests env: + API_KEY: ${{ secrets.API_KEY }} COOKIE: ${{ secrets.COOKIE }} COOKIE_2: ${{ secrets.COOKIE_2 }} + FORWARDER_HOSTNAME: ${{ vars.forwarder_hostname }} + ID_TOKEN: ${{ steps.auth.outputs.id_token }} run: yarn test diff --git a/README.md b/README.md index b1b776ac0..b0c6b5500 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,8 @@ This NPM package enables operations froms the [Roblox website](https://www.roblo If you are looking for more information on how to create something like this, check out [our sister library, `noblox.js-server`](https://github.com/noblox/noblox.js-server) or [our YouTube series](https://www.youtube.com/playlist?list=PLEW4K4VqMUb_VMA3Yp9LI4gReRyVWGTnU). Keep in mind that these resources may not always be up to date, so it is **highly** encouraged that you learn to use the `noblox.js` library directly. + +Note: We use the semantic release plugin. You should treat npm as the source of truth regarding package versions - the package.json version in this repository will not be up to date. --- ## Prerequisites diff --git a/lib/accountinformation/getUserSocialLinks.js b/lib/accountinformation/getUserSocialLinks.js index bce82e72a..5451eda4f 100644 --- a/lib/accountinformation/getUserSocialLinks.js +++ b/lib/accountinformation/getUserSocialLinks.js @@ -1,5 +1,6 @@ // Includes const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['userId'] @@ -25,14 +26,11 @@ function getUserSocialLinks (userId, jar) { resolveWithFullResponse: true } }) - .then(({ statusCode, body }) => { - const { errors } = JSON.parse(body) - if (statusCode === 200) { - return JSON.parse(body) - } else if (statusCode === 400) { - throw new Error(`${errors[0].message} | userId: ${userId}`) + .then((res) => { + if (res.statusCode === 200) { + return JSON.parse(res.body) } else { - throw new Error(`An unknown error occurred with getUserSocialLinks() | [${statusCode}] userId: ${userId}`) + throw new RobloxAPIError(res) } }) } diff --git a/lib/accountsettings/block.js b/lib/accountsettings/block.js index 81e555048..d88136e99 100644 --- a/lib/accountsettings/block.js +++ b/lib/accountsettings/block.js @@ -1,6 +1,7 @@ // Includes const http = require('../util/http.js').func const getGeneralToken = require('../util/getGeneralToken.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['userId'] @@ -22,7 +23,7 @@ exports.optional = ['jar'] function block (jar, token, userId) { return new Promise((resolve, reject) => { const httpOpt = { - url: `//accountsettings.roblox.com/v1/users/${userId}/block`, + url: `https://apis.roblox.com/user-blocking-api/v1/users/${userId}/block-user`, options: { method: 'POST', jar, @@ -37,13 +38,7 @@ function block (jar, token, userId) { if (res.statusCode === 200) { resolve() } else { - const body = JSON.parse(res.body) || {} - if (body.errors && body.errors.length > 0) { - const errors = body.errors.map((e) => { - return e.message - }) - reject(new Error(`${res.statusCode} ${errors.join(', ')}`)) - } + reject(new RobloxAPIError(res)) } }) }) diff --git a/lib/accountsettings/unblock.js b/lib/accountsettings/unblock.js index 2619e0449..daecaf3e6 100644 --- a/lib/accountsettings/unblock.js +++ b/lib/accountsettings/unblock.js @@ -1,6 +1,7 @@ // Includes const http = require('../util/http.js').func const getGeneralToken = require('../util/getGeneralToken.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['userId'] @@ -22,7 +23,7 @@ exports.optional = ['jar'] function unblock (jar, token, userId) { return new Promise((resolve, reject) => { const httpOpt = { - url: `//accountsettings.roblox.com/v1/users/${userId}/unblock`, + url: `https://apis.roblox.com/user-blocking-api/v1/users/${userId}/unblock-user`, options: { method: 'POST', jar, @@ -37,13 +38,7 @@ function unblock (jar, token, userId) { if (res.statusCode === 200) { resolve() } else { - const body = JSON.parse(res.body) || {} - if (body.errors && body.errors.length > 0) { - const errors = body.errors.map((e) => { - return e.message - }) - reject(new Error(`${res.statusCode} ${errors.join(', ')}`)) - } + reject(new RobloxAPIError(res)) } }) }) diff --git a/lib/asset/deleteFromInventory.js b/lib/asset/deleteFromInventory.js index 46ebfa405..a90357fe9 100644 --- a/lib/asset/deleteFromInventory.js +++ b/lib/asset/deleteFromInventory.js @@ -1,6 +1,7 @@ // Includes const http = require('../util/http.js').func const getGeneralToken = require('../util/getGeneralToken.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['assetId'] @@ -28,30 +29,17 @@ function deleteFromInventory (jar, assetId, xcsrf) { resolveWithFullResponse: true, jar, headers: { - 'X-CSRF-TOKEN': xcsrf, - 'content-type': 'application/x-www-form-urlencoded; charset=UTF-8' + 'X-CSRF-TOKEN': xcsrf } } } return http(httpOpt) .then(function (res) { - const responseData = typeof res.body === 'string' ? JSON.parse(res.body) : res.body - // Roblox likes to error here with 200 status codes too with inconsistency if (res.statusCode === 200) { - let error = 'An unknown error has occurred.' - if (responseData && !responseData.isValid) { - error = responseData.error - reject(new Error(error)) - } else if (responseData && responseData.isValid) { - resolve() - } + resolve() } else { - let error = 'An unknown error has occurred.' - if (responseData && responseData.errors) { - error = responseData.errors.map((e) => e.message).join('\n') - } - reject(new Error(error)) + reject(new RobloxAPIError(res)) } }) .catch(error => reject(error)) diff --git a/lib/asset/getGamePassProductInfo.js b/lib/asset/getGamePassProductInfo.js index 762f64645..978709154 100644 --- a/lib/asset/getGamePassProductInfo.js +++ b/lib/asset/getGamePassProductInfo.js @@ -1,6 +1,7 @@ // Includes const http = require('../util/http.js').func const cache = require('../cache') +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['gamepass'] @@ -33,9 +34,7 @@ function getGamePassProductInfo (gamepass) { if (res.statusCode === 200) { resolve(data) } else { - const errors = data.errors.map((e) => e.message) - - reject(new Error(`${res.statusCode} ${errors.join(', ')}`)) + reject(new RobloxAPIError(res)) } }) .catch(error => reject(error)) diff --git a/lib/asset/getProductInfo.js b/lib/asset/getProductInfo.js index 3e850032c..a5a8fcb04 100644 --- a/lib/asset/getProductInfo.js +++ b/lib/asset/getProductInfo.js @@ -1,6 +1,7 @@ // Includes const http = require('../util/http.js').func const cache = require('../cache') +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['asset'] @@ -30,18 +31,7 @@ function getProductInfo (asset) { if (res.statusCode === 200) { resolve(JSON.parse(res.body)) } else { - // Sourced from: https://stackoverflow.com/a/32278428 - const isAnObject = (val) => !!(val instanceof Array || val instanceof Object) - - const body = isAnObject(res.body) ? JSON.parse(res.body) : {} - if (body.errors && body.errors.length > 0) { - const errors = body.errors.map((e) => { - return e.message - }) - reject(new Error(`${res.statusCode} ${errors.join(', ')}`)) - } else { - reject(new Error(`${res.statusCode} ${res.body}`)) - } + reject(new RobloxAPIError(res)) } }) .catch(error => reject(error)) diff --git a/lib/avatar/avatarRules.js b/lib/avatar/avatarRules.js index 24675b028..416453cb9 100644 --- a/lib/avatar/avatarRules.js +++ b/lib/avatar/avatarRules.js @@ -1,4 +1,5 @@ const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') exports.optional = ['option', 'jar'] @@ -32,7 +33,7 @@ exports.func = (args) => { return result } else { - throw new Error('Error fetching avatar rules') + throw new RobloxAPIError(res) } }) } diff --git a/lib/avatar/currentlyWearing.js b/lib/avatar/currentlyWearing.js index 2f8c0eddf..d8a8ef0d4 100644 --- a/lib/avatar/currentlyWearing.js +++ b/lib/avatar/currentlyWearing.js @@ -1,4 +1,5 @@ const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') exports.required = ['userId'] @@ -26,7 +27,7 @@ exports.func = (args) => { if (res.statusCode === 200) { return JSON.parse(res.body) } else { - throw new Error('User does not exist') + throw new RobloxAPIError(res) } }) } diff --git a/lib/avatar/getAvatar.js b/lib/avatar/getAvatar.js index 30c18a163..8f7d9eb56 100644 --- a/lib/avatar/getAvatar.js +++ b/lib/avatar/getAvatar.js @@ -1,4 +1,5 @@ const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') exports.required = ['userId'] @@ -24,7 +25,7 @@ const getAvatar = (userId) => { if (res.statusCode === 200) { return JSON.parse(res.body) } else { - throw new Error('User does not exist') + throw new RobloxAPIError(res) } }) } diff --git a/lib/avatar/getCurrentAvatar.js b/lib/avatar/getCurrentAvatar.js index 0f2f3dbd4..ca4a21190 100644 --- a/lib/avatar/getCurrentAvatar.js +++ b/lib/avatar/getCurrentAvatar.js @@ -1,4 +1,5 @@ const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') exports.optional = ['option', 'jar'] @@ -28,7 +29,7 @@ exports.func = (args) => { } }).then((res) => { if (res.statusCode !== 200) { - throw new Error('You are not logged in') + throw new RobloxAPIError(res) } else { const json = JSON.parse(res.body) return (option ? json[option] : json) diff --git a/lib/avatar/getRecentItems.js b/lib/avatar/getRecentItems.js index bbde8e1f8..756a30577 100644 --- a/lib/avatar/getRecentItems.js +++ b/lib/avatar/getRecentItems.js @@ -1,4 +1,5 @@ const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') exports.optional = ['listType', 'jar'] @@ -26,12 +27,10 @@ exports.func = (args) => { resolveWithFullResponse: true } }).then((res) => { - if (res.statusCode === 401) { - throw new Error('You are not logged in') - } else if (res.statusCode === 400) { - throw new Error('Invalid list type') - } else { + if (res.statusCode === 200) { return JSON.parse(res.body) + } else { + throw new RobloxAPIError(res) } }) } diff --git a/lib/avatar/outfitDetails.js b/lib/avatar/outfitDetails.js index 8a238d8c2..dcf4b5dde 100644 --- a/lib/avatar/outfitDetails.js +++ b/lib/avatar/outfitDetails.js @@ -1,4 +1,5 @@ const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') exports.required = ['outfitId'] @@ -26,7 +27,7 @@ exports.func = (args) => { if (res.statusCode === 200) { return JSON.parse(res.body) } else { - throw new Error('Outfit does not exist') + throw new RobloxAPIError(res) } }) } diff --git a/lib/avatar/outfits.js b/lib/avatar/outfits.js index 11627c4c8..efca2c2e2 100644 --- a/lib/avatar/outfits.js +++ b/lib/avatar/outfits.js @@ -1,4 +1,5 @@ const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') exports.required = ['userId'] exports.optional = ['page', 'itemsPerPage'] @@ -31,7 +32,7 @@ exports.func = (args) => { if (res.statusCode === 200) { return JSON.parse(res.body) } else { - throw new Error('User does not exist') + throw new RobloxAPIError(res) } }) } diff --git a/lib/avatar/redrawAvatar.js b/lib/avatar/redrawAvatar.js index 30e933da3..8975e128c 100644 --- a/lib/avatar/redrawAvatar.js +++ b/lib/avatar/redrawAvatar.js @@ -1,5 +1,6 @@ const http = require('../util/http.js').func const getGeneralToken = require('../util/getGeneralToken.js').func +const RobloxAPIError = require('../util/apiError.js') exports.optional = ['jar'] @@ -30,10 +31,8 @@ function redrawAvatar (jar, token) { return http(httpOpt).then((res) => { if (res.statusCode === 200) { resolve() - } else if (res.statusCode === 429) { - reject(new Error('Redraw avatar floodchecked')) } else { - reject(new Error('Redraw avatar failed')) + reject(new RobloxAPIError(res)) } }).catch(error => reject(error)) }) diff --git a/lib/avatar/removeAssetId.js b/lib/avatar/removeAssetId.js index 0030f05a2..e2ebe403e 100644 --- a/lib/avatar/removeAssetId.js +++ b/lib/avatar/removeAssetId.js @@ -1,5 +1,6 @@ const http = require('../util/http.js').func const getGeneralToken = require('../util/getGeneralToken.js').func +const RobloxAPIError = require('../util/apiError.js') exports.required = ['assetId'] exports.optional = ['jar'] @@ -32,13 +33,8 @@ function removeAssetId (assetId, jar, xcsrf) { return http(httpOpt) .then(function (res) { - const responseData = JSON.parse(res.body) if (res.statusCode !== 200) { - let error = 'An unknown error has occurred.' - if (responseData && responseData.errors) { - error = responseData.errors.map((e) => e.message).join('\n') - } - reject(new Error(error)) + reject(new RobloxAPIError(res)) } else { resolve() } diff --git a/lib/avatar/setAvatarBodyColors.js b/lib/avatar/setAvatarBodyColors.js index 955de1da8..866371e3b 100644 --- a/lib/avatar/setAvatarBodyColors.js +++ b/lib/avatar/setAvatarBodyColors.js @@ -1,5 +1,6 @@ const http = require('../util/http.js').func const getGeneralToken = require('../util/getGeneralToken.js').func +const RobloxAPIError = require('../util/apiError.js') exports.required = ['headColorId', 'torsoColorId', 'rightArmColorId', 'leftArmColorId', 'rightLegColorId', 'leftLegColorId'] exports.optional = ['jar'] @@ -43,10 +44,10 @@ const nextFunction = (jar, token, headColorId, torsoColorId, rightArmColorId, le }).then((res) => { if (res.statusCode === 200) { if (!res.body.success) { - throw new Error(res.body) + throw new RobloxAPIError(res) } } else { - throw new Error('Set body colors failed') + throw new RobloxAPIError(res) } }) } diff --git a/lib/avatar/setAvatarScales.js b/lib/avatar/setAvatarScales.js index cee36f527..dea4ef99f 100644 --- a/lib/avatar/setAvatarScales.js +++ b/lib/avatar/setAvatarScales.js @@ -1,5 +1,6 @@ const http = require('../util/http.js').func const getGeneralToken = require('../util/getGeneralToken.js').func +const RobloxAPIError = require('../util/apiError.js') exports.required = ['height', 'width', 'head'] exports.optional = ['depth', 'proportion', 'bodyType', 'jar'] @@ -43,10 +44,10 @@ const nextFunction = (jar, token, height, width, head, depth, proportion, bodyTy }).then((res) => { if (res.statusCode === 200) { if (!res.body.success) { - throw new Error(res.body) + throw new RobloxAPIError(res) } } else { - throw new Error('Set avatar scale failed') + throw new RobloxAPIError(res) } }) } diff --git a/lib/avatar/setPlayerAvatarType.js b/lib/avatar/setPlayerAvatarType.js index fa5addaa0..e58018da3 100644 --- a/lib/avatar/setPlayerAvatarType.js +++ b/lib/avatar/setPlayerAvatarType.js @@ -1,5 +1,6 @@ const http = require('../util/http.js').func const getGeneralToken = require('../util/getGeneralToken.js').func +const RobloxAPIError = require('../util/apiError.js') exports.required = ['avatarType'] exports.optional = ['jar'] @@ -33,10 +34,10 @@ const nextFunction = (jar, token, avatarType) => { }).then((res) => { if (res.statusCode === 200) { if (!res.body.success) { - throw new Error(res.body) + throw new RobloxAPIError(res) } } else { - throw new Error('Set avatar type failed') + throw new RobloxAPIError(res) } }) } diff --git a/lib/avatar/setWearingAssets.js b/lib/avatar/setWearingAssets.js index ca5667a8b..2fcce9982 100644 --- a/lib/avatar/setWearingAssets.js +++ b/lib/avatar/setWearingAssets.js @@ -1,5 +1,6 @@ const http = require('../util/http.js').func const getGeneralToken = require('../util/getGeneralToken.js').func +const RobloxAPIError = require('../util/apiError.js') exports.required = ['assetIds'] exports.optional = ['jar'] @@ -33,10 +34,10 @@ const nextFunction = (jar, token, assetIds) => { }).then((res) => { if (res.statusCode === 200) { if (!res.body.success) { - throw new Error('Invalid assets: ' + res.body.invalidAssetIds.join(', ')) + throw new RobloxAPIError(res) } } else { - throw new Error('Wear assets failed') + throw new RobloxAPIError(res) } }) } diff --git a/lib/avatar/wearAssetId.js b/lib/avatar/wearAssetId.js index 6dad06dc5..3cadd1a4e 100644 --- a/lib/avatar/wearAssetId.js +++ b/lib/avatar/wearAssetId.js @@ -1,5 +1,6 @@ const http = require('../util/http.js').func const getGeneralToken = require('../util/getGeneralToken.js').func +const RobloxAPIError = require('../util/apiError.js') exports.required = ['assetId'] exports.optional = ['jar'] @@ -32,13 +33,8 @@ function wearAssetId (assetId, jar, xcsrf) { return http(httpOpt) .then(function (res) { - const responseData = JSON.parse(res.body) if (res.statusCode !== 200) { - let error = 'An unknown error has occurred.' - if (responseData && responseData.errors) { - error = responseData.errors.map((e) => e.message).join('\n') - } - reject(new Error(error)) + reject(new RobloxAPIError(res)) } else { resolve() } diff --git a/lib/badges/getAwardedTimestamps.js b/lib/badges/getAwardedTimestamps.js index 3ba10c3b7..ac6efd612 100644 --- a/lib/badges/getAwardedTimestamps.js +++ b/lib/badges/getAwardedTimestamps.js @@ -1,5 +1,6 @@ // Includes const http = require('../util/http').func +const RobloxAPIError = require('../util/apiError') // Args exports.required = ['userId', 'badgeId'] @@ -31,11 +32,7 @@ const getAwardedTimestamps = (userId, badgeId) => { .then(function (res) { const responseData = JSON.parse(res.body) if (res.statusCode !== 200) { - let error = 'An unknown error has occurred.' - if (responseData && responseData.errors) { - error = responseData.errors.map((e) => e.message).join('\n') - } - reject(new Error(error)) + reject(new RobloxAPIError(res)) } else { resolve(responseData) } diff --git a/lib/badges/getBadgeInfo.js b/lib/badges/getBadgeInfo.js index 5c6a2b42c..fff815fb0 100644 --- a/lib/badges/getBadgeInfo.js +++ b/lib/badges/getBadgeInfo.js @@ -1,5 +1,6 @@ // Includes const http = require('../util/http').func +const RobloxAPIError = require('../util/apiError') // Args exports.required = ['badgeId'] @@ -30,7 +31,7 @@ const badgeInfo = async (id) => { json.updated = new Date(json.updated) return json } else { - throw new Error('Badge is invalid or does not exist.') + throw new RobloxAPIError(res) } }) } diff --git a/lib/badges/getGameBadges.js b/lib/badges/getGameBadges.js index 927f84527..eec7387d0 100644 --- a/lib/badges/getGameBadges.js +++ b/lib/badges/getGameBadges.js @@ -1,5 +1,6 @@ // Includes const http = require('../util/http').func +const RobloxAPIError = require('../util/apiError') // Args exports.required = ['universeId'] @@ -37,7 +38,7 @@ const gameBadges = async (id, limit, cursor, order) => { }) return json.data } else { - throw new Error('The game is invalid or does not exist.') + throw new RobloxAPIError(res) } }) } diff --git a/lib/badges/updateBadgeInfo.js b/lib/badges/updateBadgeInfo.js index f39cad3fa..8407cce22 100644 --- a/lib/badges/updateBadgeInfo.js +++ b/lib/badges/updateBadgeInfo.js @@ -1,6 +1,7 @@ // Includes const http = require('../util/http').func const getGeneralToken = require('../util/getGeneralToken.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['badgeId'] @@ -42,14 +43,8 @@ const updateInfo = (id, name, desc, enabled, xcrsf, jar) => { }).then(res => { if (res.statusCode === 200) { return JSON.parse(res.body) - } else if (res.statusCode === 400) { - throw new Error('Text moderated.') - } else if (res.statusCode === 401) { - throw new Error('Authorization has been denied for this request.') - } else if (res.statusCode === 403) { - throw new Error('Token Validation failed or you do not have permission to manage this badge.') - } else if (res.statusCode === 404) { - throw new Error('Badge is invalid or does not exist.') + } else { + throw new RobloxAPIError(res) } }) } diff --git a/lib/cache/addIf.js b/lib/cache/addIf.js index 41441bb7a..1f55f4543 100644 --- a/lib/cache/addIf.js +++ b/lib/cache/addIf.js @@ -7,7 +7,7 @@ module.exports = function (cache, type, index, callbacks) { const got = get(cache, type, index) const item = got[0] const refresh = got[1] - if (item) { + if (item != null) { callbacks.done(item) if (refresh) { const group = cache[type] diff --git a/lib/chat/addUsersToConversation.js b/lib/chat/addUsersToConversation.js index 7ec357ec5..e0f18a8ab 100644 --- a/lib/chat/addUsersToConversation.js +++ b/lib/chat/addUsersToConversation.js @@ -1,5 +1,6 @@ const http = require('../util/http.js').func const getGeneralToken = require('../util/getGeneralToken.js').func +const RobloxAPIError = require('../util/apiError.js') exports.required = ['conversationId', 'userIds'] exports.optional = ['jar'] @@ -37,16 +38,12 @@ function addUsersToConversation (conversationId, userIds, jar, token) { return http(httpOpt).then((res) => { if (res.statusCode === 200) { if (!res.body.resultType === 'Success') { - reject(new Error(res.body.statusMessage)) + reject(new RobloxAPIError(res)) } else { resolve(res.body) } } else { - let error = 'An unknown error has occurred.' - if (res.body && res.body.errors) { - error = res.body.errors.map((e) => e.message).join('\n') - } - reject(new Error(error)) + reject(new RobloxAPIError(res)) } }).catch(error => reject(error)) }) diff --git a/lib/chat/chatSettings.js b/lib/chat/chatSettings.js index 1098af238..533433062 100644 --- a/lib/chat/chatSettings.js +++ b/lib/chat/chatSettings.js @@ -1,4 +1,5 @@ const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') exports.optional = ['jar'] @@ -25,7 +26,7 @@ exports.func = (args) => { } }).then((res) => { if (res.statusCode !== 200) { - throw new Error('You are not logged in') + throw new RobloxAPIError(res) } else { return JSON.parse(res.body) } diff --git a/lib/chat/getChatMessages.js b/lib/chat/getChatMessages.js index dc08a5819..e1aa87655 100644 --- a/lib/chat/getChatMessages.js +++ b/lib/chat/getChatMessages.js @@ -1,4 +1,5 @@ const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') exports.required = ['conversationId'] exports.optional = ['pageSize', 'exclusiveStartMessageId', 'jar'] @@ -32,7 +33,7 @@ exports.func = (args) => { } }).then((res) => { if (res.statusCode !== 200) { - throw new Error('You are not logged in') + throw new RobloxAPIError(res) } else { return JSON.parse(res.body) } diff --git a/lib/chat/getConversations.js b/lib/chat/getConversations.js index 16838706f..92c4cd032 100644 --- a/lib/chat/getConversations.js +++ b/lib/chat/getConversations.js @@ -1,4 +1,5 @@ const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') exports.required = ['conversationIds'] exports.optional = ['jar'] @@ -28,13 +29,7 @@ exports.func = (args) => { } }).then((res) => { if (res.statusCode !== 200) { - const body = JSON.parse(res.body) || {} - if (body.errors && body.errors.length > 0) { - const errors = body.errors.map((e) => { - return e.message - }) - throw new Error(`${res.statusCode} ${errors.join(', ')}`) - } + throw new RobloxAPIError(res) } else { let response = JSON.parse(res.body) diff --git a/lib/chat/getRolloutSettings.js b/lib/chat/getRolloutSettings.js index 1753e79f0..fd16cd4a5 100644 --- a/lib/chat/getRolloutSettings.js +++ b/lib/chat/getRolloutSettings.js @@ -1,4 +1,5 @@ const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') exports.optional = ['featureNames', 'jar'] @@ -27,7 +28,7 @@ exports.func = (args) => { } }).then((res) => { if (res.statusCode !== 200) { - throw new Error('You are not logged in') + throw new RobloxAPIError(res) } else { return JSON.parse(res.body) } diff --git a/lib/chat/getUnreadConversationCount.js b/lib/chat/getUnreadConversationCount.js index 606ee8c72..02341d3b2 100644 --- a/lib/chat/getUnreadConversationCount.js +++ b/lib/chat/getUnreadConversationCount.js @@ -1,4 +1,5 @@ const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') exports.optional = ['jar'] @@ -25,7 +26,7 @@ exports.func = (args) => { } }).then((res) => { if (res.statusCode !== 200) { - throw new Error('You are not logged in') + throw new RobloxAPIError(res) } else { return JSON.parse(res.body) } diff --git a/lib/chat/getUnreadMessages.js b/lib/chat/getUnreadMessages.js index 9dee2aef2..97663b1d1 100644 --- a/lib/chat/getUnreadMessages.js +++ b/lib/chat/getUnreadMessages.js @@ -1,4 +1,5 @@ const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') exports.required = ['conversationIds'] exports.optional = ['pageSize', 'jar'] @@ -30,7 +31,7 @@ exports.func = (args) => { } }).then((res) => { if (res.statusCode !== 200) { - throw new Error('You are not logged in') + throw new RobloxAPIError(res) } else { return JSON.parse(res.body) } diff --git a/lib/chat/getUserConversations.js b/lib/chat/getUserConversations.js index 48f9a2b42..998b9a9ac 100644 --- a/lib/chat/getUserConversations.js +++ b/lib/chat/getUserConversations.js @@ -1,4 +1,5 @@ const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') exports.optional = ['pageNumber', 'pageSize', 'jar'] @@ -29,7 +30,7 @@ exports.func = (args) => { } }).then((res) => { if (res.statusCode !== 200) { - throw new Error('You are not logged in') + throw new RobloxAPIError(res) } else { return JSON.parse(res.body) } diff --git a/lib/chat/markChatAsRead.js b/lib/chat/markChatAsRead.js index 3615b2dc2..bc70679a6 100644 --- a/lib/chat/markChatAsRead.js +++ b/lib/chat/markChatAsRead.js @@ -1,5 +1,6 @@ const http = require('../util/http.js').func const getGeneralToken = require('../util/getGeneralToken.js').func +const RobloxAPIError = require('../util/apiError.js') exports.required = ['conversationId', 'endMessageId'] exports.optional = ['jar'] @@ -35,10 +36,10 @@ const nextFunction = (jar, token, conversationId, endMessageId) => { }).then((res) => { if (res.statusCode === 200) { if (!res.body.resultType === 'Success') { - throw new Error(res.body.statusMessage) + throw new RobloxAPIError(res) } } else { - throw new Error('Mark as read failed') + throw new RobloxAPIError(res) } }) } diff --git a/lib/chat/markChatAsSeen.js b/lib/chat/markChatAsSeen.js index aae16b0cd..74773c720 100644 --- a/lib/chat/markChatAsSeen.js +++ b/lib/chat/markChatAsSeen.js @@ -1,5 +1,6 @@ const http = require('../util/http.js').func const getGeneralToken = require('../util/getGeneralToken.js').func +const RobloxAPIError = require('../util/apiError.js') exports.required = ['conversationIds'] exports.optional = ['jar'] @@ -33,10 +34,10 @@ const nextFunction = (jar, token, conversationIds) => { }).then((res) => { if (res.statusCode === 200) { if (!res.body.resultType === 'Success') { - throw new Error(res.body.statusMessage) + throw new RobloxAPIError(res) } } else { - throw new Error('Mark as seen failed') + throw new RobloxAPIError(res) } }) } diff --git a/lib/chat/multiGetLatestMessages.js b/lib/chat/multiGetLatestMessages.js index 939fa4728..699a85cc8 100644 --- a/lib/chat/multiGetLatestMessages.js +++ b/lib/chat/multiGetLatestMessages.js @@ -1,4 +1,5 @@ const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') exports.required = ['conversationIds'] exports.optional = ['pageSize', 'jar'] @@ -29,7 +30,7 @@ exports.func = (args) => { } }).then((res) => { if (res.statusCode !== 200) { - throw new Error('You are not logged in') + throw new RobloxAPIError(res) } else { return JSON.parse(res.body) } diff --git a/lib/chat/removeFromGroupConversation.js b/lib/chat/removeFromGroupConversation.js index 1f7be6073..ac2ff1632 100644 --- a/lib/chat/removeFromGroupConversation.js +++ b/lib/chat/removeFromGroupConversation.js @@ -1,5 +1,6 @@ const http = require('../util/http.js').func const getGeneralToken = require('../util/getGeneralToken.js').func +const RobloxAPIError = require('../util/apiError.js') exports.required = ['conversationId', 'userId'] exports.optional = ['jar'] @@ -38,16 +39,12 @@ function removeFromGroupConversation (conversationId, userId, jar, token) { return http(httpOpt).then((res) => { if (res.statusCode === 200) { if (!res.body.resultType === 'Success') { - reject(new Error(res.body.statusMessage)) + reject(new RobloxAPIError(res)) } else { resolve(res.body) } } else { - let error = 'An unknown error has occurred.' - if (res.body && res.body.errors) { - error = res.body.errors.map((e) => e.message).join('\n') - } - reject(new Error(error)) + reject(new RobloxAPIError(res)) } }).catch(error => reject(error)) }) diff --git a/lib/chat/renameGroupConversation.js b/lib/chat/renameGroupConversation.js index 7e2c14509..d70185da1 100644 --- a/lib/chat/renameGroupConversation.js +++ b/lib/chat/renameGroupConversation.js @@ -1,5 +1,6 @@ const http = require('../util/http.js').func const getGeneralToken = require('../util/getGeneralToken.js').func +const RobloxAPIError = require('../util/apiError.js') exports.required = ['conversationId', 'title'] exports.optional = ['jar'] @@ -37,12 +38,12 @@ function renameGroupConversation (conversationId, newTitle, jar, token) { return http(httpOpt).then((res) => { if (res.statusCode === 200) { if (!res.body.resultType === 'Success') { - reject(new Error(res.body.statusMessage)) + reject(new RobloxAPIError(res)) } else { resolve(res.body) } } else { - reject(new Error('Rename group chat failed')) + reject(new RobloxAPIError(res)) } }).catch(error => reject(error)) }) diff --git a/lib/chat/sendChatMessage.js b/lib/chat/sendChatMessage.js index 04ada9da4..f71520d79 100644 --- a/lib/chat/sendChatMessage.js +++ b/lib/chat/sendChatMessage.js @@ -1,5 +1,6 @@ const http = require('../util/http.js').func const getGeneralToken = require('../util/getGeneralToken.js').func +const RobloxAPIError = require('../util/apiError.js') exports.required = ['conversationId', 'message'] exports.optional = ['jar'] @@ -37,12 +38,12 @@ function sendChatMessage (conversationId, messageText, jar, token) { return http(httpOpt).then((res) => { if (res.statusCode === 200) { if (!res.body.resultType === 'Success') { - reject(new Error(res.body.statusMessage)) + reject(new RobloxAPIError(res)) } else { resolve(res.body) } } else { - throw new Error('Send chat message failed') + reject(new RobloxAPIError(res)) } }).catch(error => reject(error)) }) diff --git a/lib/chat/setChatUserTyping.js b/lib/chat/setChatUserTyping.js index 05911afba..f96276ae5 100644 --- a/lib/chat/setChatUserTyping.js +++ b/lib/chat/setChatUserTyping.js @@ -1,5 +1,6 @@ const http = require('../util/http.js').func const getGeneralToken = require('../util/getGeneralToken.js').func +const RobloxAPIError = require('../util/apiError.js') exports.required = ['conversationId', 'isTyping'] exports.optional = ['jar'] @@ -37,16 +38,12 @@ function setChatUserTyping (conversationId, isTyping, jar, token) { return http(httpOpt).then((res) => { if (res.statusCode === 200) { if (!res.body.resultType === 'Success') { - reject(new Error(res.body.statusMessage)) + reject(new RobloxAPIError(res)) } else { resolve(res.body) } } else { - let error = 'An unknown error has occurred.' - if (res.body && res.body.errors) { - error = res.body.errors.map((e) => e.message).join('\n') - } - reject(new Error(error)) + reject(new RobloxAPIError(res)) } }).catch(error => reject(error)) }) diff --git a/lib/chat/start121Conversation.js b/lib/chat/start121Conversation.js index e7118be49..907594ff6 100644 --- a/lib/chat/start121Conversation.js +++ b/lib/chat/start121Conversation.js @@ -1,5 +1,6 @@ const http = require('../util/http.js').func const getGeneralToken = require('../util/getGeneralToken.js').func +const RobloxAPIError = require('../util/apiError.js') exports.required = ['userId'] exports.optional = ['jar'] @@ -33,10 +34,10 @@ const nextFunction = (jar, token, userId) => { }).then((res) => { if (res.statusCode === 200) { if (!res.body.resultType === 'Success') { - throw new Error(res.body.statusMessage) + throw new RobloxAPIError(res) } } else { - throw new Error('Start conversation failed') + throw new RobloxAPIError(res) } }) } diff --git a/lib/chat/startCloudEditConversation.js b/lib/chat/startCloudEditConversation.js index c4458965b..7da4efe81 100644 --- a/lib/chat/startCloudEditConversation.js +++ b/lib/chat/startCloudEditConversation.js @@ -1,5 +1,6 @@ const http = require('../util/http.js').func const getGeneralToken = require('../util/getGeneralToken.js').func +const RobloxAPIError = require('../util/apiError.js') exports.required = ['placeId'] exports.optional = ['jar'] @@ -33,10 +34,10 @@ const nextFunction = (jar, token, placeId) => { }).then((res) => { if (res.statusCode === 200) { if (!res.body.resultType === 'Success') { - throw new Error(res.body.statusMessage) + throw new RobloxAPIError(res) } } else { - throw new Error('Start cloud edit chat failed') + throw new RobloxAPIError(res) } }) } diff --git a/lib/chat/startGroupConversation.js b/lib/chat/startGroupConversation.js index 137879de0..72e93ee83 100644 --- a/lib/chat/startGroupConversation.js +++ b/lib/chat/startGroupConversation.js @@ -1,5 +1,6 @@ const http = require('../util/http.js').func const getGeneralToken = require('../util/getGeneralToken.js').func +const RobloxAPIError = require('../util/apiError.js') exports.required = ['userIds', 'title'] exports.optional = ['jar'] @@ -38,16 +39,12 @@ function startGroupConversation (userIds, chatTitle, jar, token) { return http(httpOpt).then((res) => { if (res.statusCode === 200) { if (!res.body.resultType === 'Success') { - reject(new Error(res.body.statusMessage)) + reject(new RobloxAPIError(res)) } else { resolve(res.body) } } else { - let error = 'An unknown error has occurred.' - if (res.body && res.body.errors) { - error = res.body.errors.map((e) => e.message).join('\n') - } - reject(new Error(error)) + reject(new RobloxAPIError(res)) } }).catch(error => reject(error)) }) diff --git a/lib/datastores/deleteDatastoreEntry.js b/lib/datastores/deleteDatastoreEntry.js index 3240e0630..bc1db1f48 100644 --- a/lib/datastores/deleteDatastoreEntry.js +++ b/lib/datastores/deleteDatastoreEntry.js @@ -1,5 +1,6 @@ // Includes const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['universeId', 'datastoreName', 'entryKey'] @@ -43,18 +44,7 @@ function deleteDatastoreEntry (universeId, datastoreName, entryKey, scope = 'glo if (res.statusCode === 204) { resolve() } else { - // Sourced from: https://stackoverflow.com/a/32278428 - const isAnObject = (val) => !!(val instanceof Array || val instanceof Object) - - let body - - try { - body = isAnObject(JSON.parse(res.body)) ? JSON.parse(res.body) : {} - } catch (error) { - reject(new Error(`${res.statusCode} ${res.statusMessage}`)) - } - - reject(new Error(`${res.statusCode} ${body.error} ${body.message}`)) + reject(new RobloxAPIError(res)) } }) .catch(error => reject(error)) diff --git a/lib/datastores/getDatastoreEntry.js b/lib/datastores/getDatastoreEntry.js index 74008e2ad..a650a5cc4 100644 --- a/lib/datastores/getDatastoreEntry.js +++ b/lib/datastores/getDatastoreEntry.js @@ -1,5 +1,6 @@ // Includes const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['universeId', 'datastoreName', 'entryKey'] @@ -75,18 +76,7 @@ function getDatastoreEntry (universeId, datastoreName, entryKey, scope = 'global } }) } else { - // Sourced from: https://stackoverflow.com/a/32278428 - const isAnObject = (val) => !!(val instanceof Array || val instanceof Object) - - let body - - try { - body = isAnObject(JSON.parse(res.body)) ? JSON.parse(res.body) : {} - } catch (error) { - reject(new Error(`${res.statusCode} ${res.statusMessage}`)) - } - - reject(new Error(`${res.statusCode} ${body.error} ${body.message}`)) + reject(new RobloxAPIError(res)) } }) .catch(error => reject(error)) diff --git a/lib/datastores/getDatastoreEntryVersions.js b/lib/datastores/getDatastoreEntryVersions.js index a4db43b76..01454a600 100644 --- a/lib/datastores/getDatastoreEntryVersions.js +++ b/lib/datastores/getDatastoreEntryVersions.js @@ -1,5 +1,6 @@ // Includes const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['universeId', 'datastoreName', 'entryKey'] @@ -60,18 +61,7 @@ function getDatastoreEntryVersions (universeId, datastoreName, entryKey, scope = resolve(response) } else { - // Sourced from: https://stackoverflow.com/a/32278428 - const isAnObject = (val) => !!(val instanceof Array || val instanceof Object) - - let body - - try { - body = isAnObject(JSON.parse(res.body)) ? JSON.parse(res.body) : {} - } catch (error) { - reject(new Error(`${res.statusCode} ${res.statusMessage}`)) - } - - reject(new Error(`${res.statusCode} ${body.error} ${body.message}`)) + reject(new RobloxAPIError(res)) } }) .catch(error => reject(error)) diff --git a/lib/datastores/getDatastoreKeys.js b/lib/datastores/getDatastoreKeys.js index 737d2923b..212eab512 100644 --- a/lib/datastores/getDatastoreKeys.js +++ b/lib/datastores/getDatastoreKeys.js @@ -1,5 +1,6 @@ // Includes const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['universeId', 'datastoreName'] @@ -50,18 +51,7 @@ function getDatastoreKeys (universeId, datastoreName, scope = 'global', prefix, resolve(response) } else { - // Sourced from: https://stackoverflow.com/a/32278428 - const isAnObject = (val) => !!(val instanceof Array || val instanceof Object) - - let body - - try { - body = isAnObject(JSON.parse(res.body)) ? JSON.parse(res.body) : {} - } catch (error) { - reject(new Error(`${res.statusCode} ${res.statusMessage}`)) - } - - reject(new Error(`${res.statusCode} ${body.error} ${body.message}`)) + reject(new RobloxAPIError(res)) } }) .catch(error => reject(error)) diff --git a/lib/datastores/getDatastores.js b/lib/datastores/getDatastores.js index a094a3d29..8c48847ba 100644 --- a/lib/datastores/getDatastores.js +++ b/lib/datastores/getDatastores.js @@ -1,5 +1,6 @@ // Includes const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['universeId'] @@ -49,18 +50,7 @@ function getDatastores (universeId, prefix, limit, cursor, jar) { resolve(response) } else { - // Sourced from: https://stackoverflow.com/a/32278428 - const isAnObject = (val) => !!(val instanceof Array || val instanceof Object) - - let body - - try { - body = isAnObject(JSON.parse(res.body)) ? JSON.parse(res.body) : {} - } catch (error) { - reject(new Error(`${res.statusCode} ${res.statusMessage}`)) - } - - reject(new Error(`${res.statusCode} ${body.error} ${body.message}`)) + reject(new RobloxAPIError(res)) } }) .catch(error => reject(error)) diff --git a/lib/datastores/incrementDatastoreEntry.js b/lib/datastores/incrementDatastoreEntry.js index 414f01ae1..00d55777f 100644 --- a/lib/datastores/incrementDatastoreEntry.js +++ b/lib/datastores/incrementDatastoreEntry.js @@ -1,6 +1,7 @@ // Includes const http = require('../util/http.js').func const crypto = require('crypto') +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['universeId', 'datastoreName', 'entryKey', 'incrementBy'] @@ -70,18 +71,7 @@ function incrementDatastoreEntry (universeId, datastoreName, entryKey, increment } }) } else { - // Sourced from: https://stackoverflow.com/a/32278428 - const isAnObject = (val) => !!(val instanceof Array || val instanceof Object) - - let body - - try { - body = isAnObject(JSON.parse(res.body)) ? JSON.parse(res.body) : {} - } catch (error) { - reject(new Error(`${res.statusCode} ${res.statusMessage}`)) - } - - reject(new Error(`${res.statusCode} ${body.error} ${body.message}`)) + reject(new RobloxAPIError(res)) } }) .catch(error => reject(error)) diff --git a/lib/datastores/setDatastoreEntry.js b/lib/datastores/setDatastoreEntry.js index 8ea33f155..3178679ae 100644 --- a/lib/datastores/setDatastoreEntry.js +++ b/lib/datastores/setDatastoreEntry.js @@ -1,6 +1,7 @@ // Includes const http = require('../util/http.js').func const crypto = require('crypto') +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['universeId', 'datastoreName', 'entryKey', 'body'] @@ -67,18 +68,7 @@ function setDatastoreEntry (universeId, datastoreName, entryKey, body, scope = ' resolve(response) } else { - // Sourced from: https://stackoverflow.com/a/32278428 - const isAnObject = (val) => !!(val instanceof Array || val instanceof Object) - - let body - - try { - body = isAnObject(JSON.parse(res.body)) ? JSON.parse(res.body) : {} - } catch (error) { - reject(new Error(`${res.statusCode} ${res.statusMessage}`)) - } - - reject(new Error(`${res.statusCode} ${body.error} ${body.message}`)) + reject(new RobloxAPIError(res)) } }) .catch(error => reject(error)) diff --git a/lib/develop/canManage.js b/lib/develop/canManage.js index 12d7fed6e..d498b3281 100644 --- a/lib/develop/canManage.js +++ b/lib/develop/canManage.js @@ -1,5 +1,6 @@ // Includes const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['userId', 'assetId'] @@ -25,16 +26,13 @@ function canManage (userId, assetId) { resolveWithFullResponse: true } }) - .then(function ({ statusCode, body }) { - const { Success: success, CanManage: canManage, ErrorMessage: error } = JSON.parse(body) + .then(function (res) { + const { body } = res + const { Success: success, CanManage: canManage } = JSON.parse(body) if (success) { return canManage } else { - if (error) { - throw new Error(`${error} | userId: ${userId}, assetId: ${assetId}`) - } else { - throw new Error(`An unknown error occurred with canManage() | [${statusCode}] userId: ${userId}, assetId: ${assetId}`) - } + throw new RobloxAPIError(res) } }) } diff --git a/lib/develop/configureItem.js b/lib/develop/configureItem.js index 967488aca..7e63810ef 100644 --- a/lib/develop/configureItem.js +++ b/lib/develop/configureItem.js @@ -1,6 +1,7 @@ // Includes const http = require('../util/http.js').func const getGeneralToken = require('../util/getGeneralToken.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['id', 'name', 'description'] @@ -39,9 +40,12 @@ function configure (jar, token, id, name, description, enableComments, sellForRo enableComments, genres: genreSelection || ['All'], isCopyingAllowed: typeof (sellForRobux) === 'boolean' ? sellForRobux : null - } + }, + resolveWithFullResponse: true } - }).then(function (json) { + }).then(function (res) { + const json = JSON.parse(res.body) + if (!json.errors) { const response = { name, @@ -58,7 +62,7 @@ function configure (jar, token, id, name, description, enableComments, sellForRo if (json.errors[0].code === 13) { // "Only a marketplace asset can be updated with IsCopyingAllowed." throw new Error('Attempting to make a sellable asset copyable; it must be sold for robux. (Use a number for sellForRobux.)') } - throw new Error(json.errors[0].message) + throw new RobloxAPIError(res) } }) } @@ -77,10 +81,13 @@ function configureRobux (args) { priceConfiguration: { priceInRobux: args.sellForRobux || 0 } - } + }, + resolveWithFullResponse: true } }) - .then(function (json) { + .then(function (res) { + const json = res.body + if (!json.errors) { return configure(args.jar, args.token, args.id, args.name, args.description, args.enableComments, args.sellForRobux, args.genreSelection, args.sellForRobux) } else { @@ -98,9 +105,11 @@ function configureRobux (args) { priceConfiguration: { priceInRobux: args.sellForRobux } - } + }, + resolveWithFullResponse: true } - }).then((err) => { + }).then((res) => { + const err = res.body if (!err.errors) { return configure(args.jar, args.token, args.id, args.name, args.description, args.enableComments, args.sellForRobux, args.genreSelection, args.sellForRobux) } else { @@ -159,7 +168,7 @@ function configureRobux (args) { resolveWithFullResponse: true } }).then((response) => { - if (!response.ok) throw new Error(response.body) + if (!response.ok) throw new RobloxAPIError(response) return { name: args.name, @@ -173,7 +182,7 @@ function configureRobux (args) { } else if (json.errors[0].code === 40) { // "Use collecibles publishing endpoint." - Publishing fee has not been paid for this asset throw new Error(`The publishing fee for asset ${args.id} has not been paid, you must pay the fee before setting or updating the price.`) } - throw new Error(`An unknown error occurred: [${json.errors[0].code}] ${json.errors[0].message}`) + throw new RobloxAPIError(res) } }) } diff --git a/lib/develop/updateUniverse.js b/lib/develop/updateUniverse.js index 4eac3c9f5..8c0c9fd7d 100644 --- a/lib/develop/updateUniverse.js +++ b/lib/develop/updateUniverse.js @@ -1,6 +1,7 @@ // Includes const http = require('../util/http.js').func const getGeneralToken = require('../util/getGeneralToken.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['universeId', 'settings'] @@ -33,13 +34,11 @@ function updateUniverse (universeId, settings, jar, token) { json: settings, resolveWithFullResponse: true } - }).then(({ statusCode, body }) => { - if (statusCode === 200) { - resolve(body) - } else if (body && body.errors) { - reject(new Error(`[${statusCode}] ${body.errors[0].message} | universeId: ${universeId}, settings: ${JSON.stringify(settings)} ${body.errors.field ? ` | ${body.errors.field} is incorrect` : ''}`)) + }).then((res) => { + if (res.statusCode === 200) { + resolve(res.body) } else { - reject(new Error(`An unknown error occurred with updateUniverse() | [${statusCode}] universeId: ${universeId}, settings: ${JSON.stringify(settings)}`)) + reject(new RobloxAPIError(res)) } }).catch(reject) }) diff --git a/lib/develop/updateUniverseAccess.js b/lib/develop/updateUniverseAccess.js index a696edfaa..95ca28f2a 100644 --- a/lib/develop/updateUniverseAccess.js +++ b/lib/develop/updateUniverseAccess.js @@ -1,6 +1,7 @@ // Includes const http = require('../util/http.js').func const getGeneralToken = require('../util/getGeneralToken.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['universeId', 'isPublic'] @@ -35,13 +36,11 @@ function updateUniverseAccess (universeId, isPublic, jar, token) { }, resolveWithFullResponse: true } - }).then(({ statusCode, body }) => { - if (statusCode === 200) { + }).then((res) => { + if (res.statusCode === 200) { resolve() - } else if (body && body.errors) { - reject(new Error(`[${statusCode}] ${body.errors[0].message} | universeId: ${universeId}, isPublic: ${isPublic} ${body.errors.field ? ` | ${body.errors.field} is incorrect` : ''}`)) } else { - reject(new Error(`An unknown error occurred with updateUniverseAccess() | [${statusCode}] universeId: ${universeId}, isPublic: ${isPublic}`)) + reject(new RobloxAPIError(res)) } }).catch(error => reject(error)) }) diff --git a/lib/economy/buy.js b/lib/economy/buy.js deleted file mode 100644 index ec5b57596..000000000 --- a/lib/economy/buy.js +++ /dev/null @@ -1,99 +0,0 @@ -// Includes -const http = require('../util/http.js').func -const getProductInfo = require('../asset/getProductInfo.js').func -const getGeneralToken = require('../util/getGeneralToken.js').func - -// Args -exports.required = [['asset', 'product']] -exports.optional = ['price', 'jar'] - -// Docs -/** - * 🔐 Buy an asset from the marketplace. - * @category Assets - * @param {number} asset - The ID of the product. - * @param {number=} price - The price of the product. - * @returns {Promise} - * @example const noblox = require("noblox.js") - * // Login using your cookie - * noblox.buy(1117747196) -**/ - -// Define -function buy (jar, token, product, price) { - const robux = product.PriceInRobux || 0 - const productId = product.ProductId - if (price) { - if (typeof price === 'number') { - if (robux !== price) { - throw new Error('Price requirement not met. Requested price: ' + price + ' Actual price: ' + robux) - } - } else if (typeof price === 'object') { - const high = price.high - const low = price.low - if (high) { - if (robux > high) { - throw new Error('Price requirement not met. Requested price: <=' + high + ' Actual price: ' + robux) - } - } - if (low) { - if (robux < low) { - throw new Error('Price requirement not met. Requested price: >=' + low + ' Actual price: ' + robux) - } - } - } - } - const httpOpt = { - url: '//economy.roblox.com/v1/purchases/products/' + productId, - options: { - method: 'POST', - jar, - headers: { - 'X-CSRF-TOKEN': token - }, - json: { - expectedCurrency: 1, - expectedPrice: robux, - expectedSellerId: product.Creator.Id - } - } - } - return http(httpOpt) - .then(function (json) { - let err = json.errorMsg - if (json.reason === 'InsufficientFunds') { - err = 'You need ' + json.shortfallPrice + ' more robux to purchase this item.' - } else if (json.errorMsg) { - err = json.errorMsg - } - if (!err) { - return { productId, price: robux } - } else { - throw new Error(err) - } - }) -} - -function runWithToken (args) { - const jar = args.jar - return getGeneralToken({ - jar - }) - .then(function (token) { - return buy(jar, token, args.product, args.price) - }) -} - -exports.func = function (args) { - if (!args.product) { - return getProductInfo({ - asset: args.asset - }) - .then(function (product) { - args.product = product - return runWithToken(args) - }) - } else { - return runWithToken(args) - } -} diff --git a/lib/economy/getGroupFunds.js b/lib/economy/getGroupFunds.js index a515bc2b7..3ff249ce1 100644 --- a/lib/economy/getGroupFunds.js +++ b/lib/economy/getGroupFunds.js @@ -1,5 +1,6 @@ // Includes const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['group'] @@ -26,14 +27,12 @@ function getGroupFunds (group, jar) { resolveWithFullResponse: true } }) - .then(({ statusCode, body }) => { - const { robux, errors } = JSON.parse(body) - if (statusCode === 200) { + .then((res) => { + const { robux } = JSON.parse(res.body) + if (res.statusCode === 200) { return robux - } else if (statusCode === 400 || statusCode === 403) { - throw new Error(`${errors[0].message} | groupId: ${group}`) } else { - throw new Error(`An unknown error occurred with getGroupFunds() | [${statusCode}] groupId: ${group}`) + throw new RobloxAPIError(res) } }) } diff --git a/lib/economy/getGroupPayoutEligibility.js b/lib/economy/getGroupPayoutEligibility.js new file mode 100644 index 000000000..2210946de --- /dev/null +++ b/lib/economy/getGroupPayoutEligibility.js @@ -0,0 +1,55 @@ +// Includes +const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') + +// Args +exports.required = ['group', 'members'] +exports.optional = ['jar'] + +// Docs +/** + * 🔐 Get if a user can be paid from group funds. + * @category Group + * @alias getGroupPayoutEligibility + * @param {number} group - The id of the group. + * @param {number[]} members - The members to check payout status for. + * @returns {Promise} + * @example const noblox = require("noblox.js") + * // Log in with cookie + * const payoutStatus = await noblox.getGroupPayoutEligibility(1, [2]) + **/ + +// Define +function getGroupPayoutEligibility (group, members, jar) { + const memberList = [] + + for (const member of members) { + memberList.push(`userIds=${member}`) + } + + return new Promise((resolve, reject) => { + const httpOpt = { + url: `https://economy.roblox.com/v1/groups/${group}/users-payout-eligibility?${memberList.join('&')}`, + options: { + method: 'GET', + resolveWithFullResponse: true, + jar + } + } + + return http(httpOpt) + .then(function (res) { + const responseData = JSON.parse(res.body) + if (res.statusCode !== 200) { + reject(new RobloxAPIError(res)) + } else { + resolve(responseData) + } + }) + .catch(error => reject(error)) + }) +} + +exports.func = function (args) { + return getGroupPayoutEligibility(args.group, args.members, args.jar) +} diff --git a/lib/economy/getGroupRevenueSummary.js b/lib/economy/getGroupRevenueSummary.js index 1756b8d42..679283aaf 100644 --- a/lib/economy/getGroupRevenueSummary.js +++ b/lib/economy/getGroupRevenueSummary.js @@ -1,5 +1,6 @@ // Includes const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['groupId'] @@ -27,18 +28,11 @@ function getGroupRevenueSummary (group, timeFrame, jar) { resolveWithFullResponse: true } }) - .then(({ statusCode, body }) => { - const { errors } = JSON.parse(body) - if (statusCode === 200) { - return JSON.parse(body) - } else if (statusCode === 400) { - throw new Error(`${errors[0].message} | group: ${group}, timeFrame: ${timeFrame}`) - } else if (statusCode === 401) { - throw new Error(`${errors[0].message} (Are you logged in?) | group: ${group}, timeFrame: ${timeFrame}`) - } else if (statusCode === 403) { - throw new Error('Insufficient permissions: "Spend group funds" role permissions required') + .then((res) => { + if (res.statusCode === 200) { + return JSON.parse(res.body) } else { - throw new Error(`An unknown error occurred with getGroupRevenueSummary() | [${statusCode}] group: ${group}, timeFrame: ${timeFrame}`) + throw new RobloxAPIError(res) } }) } diff --git a/lib/economy/getResaleData.js b/lib/economy/getResaleData.js index 5de5b4b65..d995a1325 100644 --- a/lib/economy/getResaleData.js +++ b/lib/economy/getResaleData.js @@ -1,5 +1,6 @@ // Includes const http = require('../util/http').func +const RobloxAPIError = require('../util/apiError') // Args exports.required = ['assetId'] @@ -23,25 +24,18 @@ const getResaleData = async (assetId) => { options: { resolveWithFullResponse: true } - }).then(({ body, statusCode }) => { - const { errors } = JSON.parse(body) - if (statusCode === 200) { - try { - const resaleData = JSON.parse(body) - for (const priceDataPoint of resaleData.priceDataPoints) { - priceDataPoint.date = new Date(priceDataPoint.date) - } - for (const volumeDataPoint of resaleData.volumeDataPoints) { - volumeDataPoint.date = new Date(volumeDataPoint.date) - } - return resaleData - } catch (err) { - throw new Error(`An unknown error occurred with getResaleData() | [${statusCode}] assetId: ${assetId}`) + }).then((res) => { + if (res.statusCode === 200) { + const resaleData = JSON.parse(res.body) + for (const priceDataPoint of resaleData.priceDataPoints) { + priceDataPoint.date = new Date(priceDataPoint.date) } - } else if (statusCode === 400) { - throw new Error(`${errors[0].message} | assetId: ${assetId}`) + for (const volumeDataPoint of resaleData.volumeDataPoints) { + volumeDataPoint.date = new Date(volumeDataPoint.date) + } + return resaleData } else { - throw new Error(`An unknown error occurred with getResaleData() | [${statusCode}] assetId: ${assetId}`) + throw new RobloxAPIError(res) } }) } diff --git a/lib/economy/getUserFunds.js b/lib/economy/getUserFunds.js index d73fc94b1..569c00fff 100644 --- a/lib/economy/getUserFunds.js +++ b/lib/economy/getUserFunds.js @@ -1,5 +1,6 @@ // Includes const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['userId'] @@ -27,14 +28,12 @@ function getUserFunds (userId, jar) { resolveWithFullResponse: true } }) - .then(({ statusCode, body }) => { - const { robux, errors } = JSON.parse(body) - if (statusCode === 200) { + .then((res) => { + const { robux } = JSON.parse(res.body) + if (res.statusCode === 200) { return robux - } else if (statusCode === 400 || statusCode === 403) { - throw new Error(`${errors[0].message} | userId: ${userId}`) } else { - throw new Error(`An unknown error occurred with getUserFunds() | [${statusCode}] userId: ${userId}`) + throw new RobloxAPIError(res) } }) } diff --git a/lib/friends/acceptFriendRequest.js b/lib/friends/acceptFriendRequest.js index d6e81beb9..efd232583 100644 --- a/lib/friends/acceptFriendRequest.js +++ b/lib/friends/acceptFriendRequest.js @@ -1,6 +1,7 @@ // Includes const http = require('../util/http.js').func const getGeneralToken = require('../util/getGeneralToken.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['userId'] @@ -38,13 +39,7 @@ function acceptFriendRequest (jar, token, userId) { if (res.statusCode === 200) { resolve() } else { - const body = JSON.parse(res.body) || {} - if (body.errors && body.errors.length > 0) { - const errors = body.errors.map((e) => { - return e.message - }) - reject(new Error(`${res.statusCode} ${errors.join(', ')}`)) - } + reject(new RobloxAPIError(res)) } }) }) diff --git a/lib/friends/declineAllFriendRequests.js b/lib/friends/declineAllFriendRequests.js index 63f01f344..c2374ad37 100644 --- a/lib/friends/declineAllFriendRequests.js +++ b/lib/friends/declineAllFriendRequests.js @@ -1,6 +1,7 @@ // Includes const http = require('../util/http.js').func const getGeneralToken = require('../util/getGeneralToken.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = [] @@ -36,13 +37,7 @@ function declineAllFriendRequests (jar, token) { if (res.statusCode === 200) { resolve() } else { - const body = JSON.parse(res.body) || {} - if (body.errors && body.errors.length > 0) { - const errors = body.errors.map((e) => { - return e.message - }) - reject(new Error(`${res.statusCode} ${errors.join(', ')}`)) - } + reject(new RobloxAPIError(res)) } }) }) diff --git a/lib/friends/declineFriendRequest.js b/lib/friends/declineFriendRequest.js index c76cd1e29..50bdf9003 100644 --- a/lib/friends/declineFriendRequest.js +++ b/lib/friends/declineFriendRequest.js @@ -1,6 +1,7 @@ // Includes const http = require('../util/http.js').func const getGeneralToken = require('../util/getGeneralToken.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['userId'] @@ -38,13 +39,7 @@ function declineFriendRequest (jar, token, userId) { if (res.statusCode === 200) { resolve() } else { - const body = JSON.parse(res.body) || {} - if (body.errors && body.errors.length > 0) { - const errors = body.errors.map((e) => { - return e.message - }) - reject(new Error(`${res.statusCode} ${errors.join(', ')}`)) - } + reject(new RobloxAPIError(res)) } }) }) diff --git a/lib/friends/getFollowerCount.js b/lib/friends/getFollowerCount.js index 49cf3cc8e..0536723c2 100644 --- a/lib/friends/getFollowerCount.js +++ b/lib/friends/getFollowerCount.js @@ -1,5 +1,6 @@ // Includes const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['userId'] @@ -29,8 +30,6 @@ exports.func = function (args) { return http(httpOpt).then(function (res) { if (res.statusCode === 200) { return res.body.count } - throw new Error( - `Failed to retrieve follower count: (${res.statusCode}) ${JSON.stringify(res.body)}` - ) + throw new RobloxAPIError(res) }) } diff --git a/lib/friends/getFollowers.js b/lib/friends/getFollowers.js index b6abac8eb..68d0e766f 100644 --- a/lib/friends/getFollowers.js +++ b/lib/friends/getFollowers.js @@ -1,5 +1,6 @@ // Includes const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['userId'] @@ -40,13 +41,7 @@ function getFollowers (jar, userId, sortOrder, limit, cursor) { }) resolve(response) } else { - const body = JSON.parse(res.body) || {} - if (body.errors && body.errors.length > 0) { - const errors = body.errors.map((e) => { - return e.message - }) - reject(new Error(`${res.statusCode} ${errors.join(', ')}`)) - } + reject(new RobloxAPIError(res)) } }) }) diff --git a/lib/friends/getFollowingCount.js b/lib/friends/getFollowingCount.js index 7a4548392..d8bf5a9dc 100644 --- a/lib/friends/getFollowingCount.js +++ b/lib/friends/getFollowingCount.js @@ -1,5 +1,6 @@ // Includes const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['userId'] @@ -29,8 +30,6 @@ exports.func = function (args) { return http(httpOpt).then(function (res) { if (res.statusCode === 200) { return res.body.count } - throw new Error( - `Failed to retrieve following count: (${res.statusCode}) ${JSON.stringify(res.body)}` - ) + throw new RobloxAPIError(res) }) } diff --git a/lib/friends/getFollowings.js b/lib/friends/getFollowings.js index 8055eaacd..a2ab157c6 100644 --- a/lib/friends/getFollowings.js +++ b/lib/friends/getFollowings.js @@ -1,5 +1,6 @@ // Includes const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['userId'] @@ -40,13 +41,7 @@ function getFollowings (jar, userId, sortOrder, limit, cursor) { }) resolve(response) } else { - const body = JSON.parse(res.body) || {} - if (body.errors && body.errors.length > 0) { - const errors = body.errors.map((e) => { - return e.message - }) - reject(new Error(`${res.statusCode} ${errors.join(', ')}`)) - } + reject(new RobloxAPIError(res)) } }) }) diff --git a/lib/friends/getFriendCount.js b/lib/friends/getFriendCount.js index 912dd1ff7..61ff1d9c5 100644 --- a/lib/friends/getFriendCount.js +++ b/lib/friends/getFriendCount.js @@ -1,5 +1,6 @@ // Includes const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['userId'] @@ -29,8 +30,6 @@ exports.func = function (args) { return http(httpOpt).then(function (res) { if (res.statusCode === 200) { return res.body.count } - throw new Error( - `Failed to retrieve friend count: (${res.statusCode}) ${JSON.stringify(res.body)}` - ) + throw new RobloxAPIError(res) }) } diff --git a/lib/friends/getFriendRequests.js b/lib/friends/getFriendRequests.js index efee1146d..f6969eccd 100644 --- a/lib/friends/getFriendRequests.js +++ b/lib/friends/getFriendRequests.js @@ -1,5 +1,6 @@ // Includes const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = [] @@ -41,13 +42,7 @@ function getFriendsRequests (args) { }) resolve(response) } else { - const body = JSON.parse(res.body) || {} - if (body.errors && body.errors.length > 0) { - const errors = body.errors.map((e) => { - return e.message - }) - reject(new Error(`${res.statusCode} ${errors.join(', ')}`)) - } + reject(new RobloxAPIError(res)) } }) }) diff --git a/lib/friends/getFriends.js b/lib/friends/getFriends.js index c2a5a9294..318f20f2a 100644 --- a/lib/friends/getFriends.js +++ b/lib/friends/getFriends.js @@ -1,5 +1,6 @@ // Includes const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['userId'] exports.optional = ['jar'] @@ -36,13 +37,7 @@ function getFriends (jar, userId) { }) resolve(response) } else { - const body = JSON.parse(res.body) || {} - if (body.errors && body.errors.length > 0) { - const errors = body.errors.map((e) => { - return e.message - }) - reject(new Error(`${res.statusCode} ${errors.join(', ')}`)) - } + reject(new RobloxAPIError(res)) } }) }) diff --git a/lib/friends/removeFriend.js b/lib/friends/removeFriend.js index e5b4fd665..5d1a83ab6 100644 --- a/lib/friends/removeFriend.js +++ b/lib/friends/removeFriend.js @@ -1,6 +1,7 @@ // Includes const http = require('../util/http.js').func const getGeneralToken = require('../util/getGeneralToken.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['userId'] @@ -37,13 +38,7 @@ function removeFriend (jar, token, userId) { if (res.statusCode === 200) { resolve() } else { - const body = JSON.parse(res.body) || {} - if (body.errors && body.errors.length > 0) { - const errors = body.errors.map((e) => { - return e.message - }) - reject(new Error(`${res.statusCode} ${errors.join(', ')}`)) - } + reject(new RobloxAPIError(res)) } }) }) diff --git a/lib/friends/sendFriendRequest.js b/lib/friends/sendFriendRequest.js index 302244805..f5ca2db27 100644 --- a/lib/friends/sendFriendRequest.js +++ b/lib/friends/sendFriendRequest.js @@ -1,6 +1,7 @@ // Includes const http = require('../util/http.js').func const getGeneralToken = require('../util/getGeneralToken.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['userId'] @@ -38,13 +39,7 @@ function sendFriendRequest (jar, token, userId) { if (res.statusCode === 200) { resolve() } else { - const body = JSON.parse(res.body) || {} - if (body.errors && body.errors.length > 0) { - const errors = body.errors.map((e) => { - return e.message - }) - reject(new Error(`${res.statusCode} ${errors.join(', ')}`)) - } + reject(new RobloxAPIError(res)) } }) }) diff --git a/lib/friends/unfollow.js b/lib/friends/unfollow.js index 0a1ea9440..e56df5a54 100644 --- a/lib/friends/unfollow.js +++ b/lib/friends/unfollow.js @@ -1,6 +1,7 @@ // Includes const http = require('../util/http.js').func const getGeneralToken = require('../util/getGeneralToken.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['userId'] @@ -37,13 +38,7 @@ function unfollow (jar, token, userId) { if (res.statusCode === 200) { resolve() } else { - const body = JSON.parse(res.body) || {} - if (body.errors && body.errors.length > 0) { - const errors = body.errors.map((e) => { - return e.message - }) - reject(new Error(`${res.statusCode} ${errors.join(', ')}`)) - } + reject(new RobloxAPIError(res)) } }) }) diff --git a/lib/games/addDeveloperProduct.js b/lib/games/addDeveloperProduct.js index 939b422fa..30f84ea55 100644 --- a/lib/games/addDeveloperProduct.js +++ b/lib/games/addDeveloperProduct.js @@ -1,5 +1,6 @@ const http = require('../util/http.js').func const getGeneralToken = require('../util/getGeneralToken.js').func +const RobloxAPIError = require('../util/apiError.js') exports.required = ['universeId', 'name', 'priceInRobux'] exports.optional = ['description', 'jar'] @@ -32,14 +33,13 @@ const nextFunction = (jar, token, universeId, name, priceInRobux, description) = resolveWithFullResponse: true } }).then(function (res) { + if (res.statusCode !== 200) { + throw new RobloxAPIError(res) + } try { - const json = JSON.parse(res.body) - if (res.statusCode === 200) { - return json - } - throw new Error(json) - } catch (err) { - throw new Error(res.body) + return JSON.parse(res.body) + } catch (_) { + throw new Error('Failed to parse response body (not valid JSON)') } }) } diff --git a/lib/games/configureGamePass.js b/lib/games/configureGamePass.js index a6f335c60..2f438625d 100644 --- a/lib/games/configureGamePass.js +++ b/lib/games/configureGamePass.js @@ -1,6 +1,7 @@ // Includes const http = require('../util/http').func const getGeneralToken = require('../util/getGeneralToken').func +const RobloxAPIError = require('../util/apiError') // Args exports.required = ['gamePassId', 'name'] @@ -61,12 +62,7 @@ function configureGamePass (gamePassId, name, description, price, icon, jar, tok iconChanged: !!icon // Boolean Cast }) } else { - const priceComment = (typeof (price) === 'number') ? ` | NOTE: Price has successfully been changed to ${price}R.` : '' - if (res.statusCode === 403) { - reject(new Error(`You do not have permission to edit this game pass.${priceComment}`)) - } else { - reject(new Error(`An unexpected error occurred with status code ${res.statusCode}.${priceComment}`)) - } + reject(new RobloxAPIError(res)) } }).catch(error => reject(error)) }) diff --git a/lib/games/getDeveloperProducts.js b/lib/games/getDeveloperProducts.js index 33c3ea027..9e455adc3 100644 --- a/lib/games/getDeveloperProducts.js +++ b/lib/games/getDeveloperProducts.js @@ -1,5 +1,6 @@ // Includes const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['placeId'] @@ -30,15 +31,7 @@ function getDeveloperProducts (jar, placeId, page) { if (res.statusCode === 200) { resolve(JSON.parse(res.body)) } else { - const body = res.body || {} - if (body.errors && body.errors.length > 0) { - const errors = body.errors.map((e) => { - return e.message - }) - reject(new Error(`${res.statusCode} ${errors.join(', ')}`)) - } else { - reject(new Error(`${res.statusCode} An error has occurred ${res.body ? res.body : ''}`)) - } + reject(new RobloxAPIError(res)) } }) .catch(error => reject(error)) diff --git a/lib/games/getGamePasses.js b/lib/games/getGamePasses.js index 2bd1f2dd2..ad04d9d2a 100644 --- a/lib/games/getGamePasses.js +++ b/lib/games/getGamePasses.js @@ -1,9 +1,9 @@ // Includes -const getPageResults = require('../util/getPageResults.js').func +const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['universeId'] -exports.optional = ['limit'] // Docs /** @@ -11,29 +11,31 @@ exports.optional = ['limit'] * @category Game * @alias getGamePasses * @param {number} universeId - The id of the universe. - * @param {Limit=} limit - The max number of game passes to return. * @returns {Promise} * @example const noblox = require("noblox.js") * const gamePasses = await noblox.getGamePasses(1686885941) **/ // Define -const getGamePasses = async (universeId, limit) => { - return getPageResults({ - url: `//games.roblox.com/v1/games/${universeId}/game-passes`, - limit - }).catch(err => { - if (err.message === '404 The requested universe does not exist.') { - err.message += '\n\nYou are possibly providing a placeId instead of a universeId.\nUse getPlaceInfo() to retrieve the universeId: https://noblox.js.org/global.html#getPlaceInfo\n' - throw err +const getGamePasses = async (universeId) => { + const res = await http({ + url: `//apis.roblox.com/game-passes/v1/universes/${universeId}/game-passes?passView=Full`, + options: { + json: true, + resolveWithFullResponse: true } - throw err }) + + if (res.statusCode !== 200) { + throw new RobloxAPIError(res) + } + + return res.body.gamePasses } -exports.func = function ({ universeId, limit }) { +exports.func = function ({ universeId }) { if (isNaN(universeId)) { throw new Error('The provided universe ID is not a number.') } - return getGamePasses(universeId, limit) + return getGamePasses(universeId) } diff --git a/lib/games/getGameRevenue.js b/lib/games/getGameRevenue.js index 81f061db5..31230070d 100644 --- a/lib/games/getGameRevenue.js +++ b/lib/games/getGameRevenue.js @@ -1,5 +1,6 @@ const http = require('../util/http.js').func const getGeneralToken = require('../util/getGeneralToken.js').func +const RobloxAPIError = require('../util/apiError.js') exports.required = ['placeId', 'type', 'granularity'] exports.optional = ['jar'] @@ -32,9 +33,7 @@ function getGameRevenue (placeId, type, granularity, jar, token) { return http(httpOpt) .then(function (res) { if (res.statusCode === 200) resolve(JSON.parse(res.body)) - else if (res.statusCode === 401) reject(new Error('You are not logged in.')) - else if (res.statusCode === 403) reject(new Error('You do not have permission to view this game.')) - else reject(new Error('An unknown error occurred.')) + else reject(new RobloxAPIError(res)) }) .catch(function (err) { console.error(err); reject(err) }) }) diff --git a/lib/games/getGameSocialLinks.js b/lib/games/getGameSocialLinks.js index 91a2d978d..ce2c05685 100644 --- a/lib/games/getGameSocialLinks.js +++ b/lib/games/getGameSocialLinks.js @@ -1,5 +1,6 @@ // Includes const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['universeId'] @@ -26,16 +27,12 @@ function getGameSocialLinks (universeId, jar) { resolveWithFullResponse: true } }) - .then(({ statusCode, body }) => { - const { errors, data } = JSON.parse(body) - if (statusCode === 200 && data) { + .then((res) => { + const { data } = JSON.parse(res.body) + if (res.statusCode === 200) { return data - } else if (statusCode === 400 || statusCode === 403 || statusCode === 404) { - throw new Error(`${errors[0].message} | universeId: ${universeId}`) - } else if (statusCode === 401) { - throw new Error(`${errors[0].message} (Are you logged in?) | universeId: ${universeId}`) } else { - throw new Error(`An unknown error occurred with getGameSocialLinks() | [${statusCode}] universeId: ${universeId}`) + throw new RobloxAPIError(res) } }) } diff --git a/lib/games/getPlaceInfo.js b/lib/games/getPlaceInfo.js index 76120cc25..a1b05a821 100644 --- a/lib/games/getPlaceInfo.js +++ b/lib/games/getPlaceInfo.js @@ -1,5 +1,6 @@ // Includes const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['placeId'] @@ -31,13 +32,11 @@ function getPlaceInfo (placeIds, jar) { } return http(httpOpt) - .then(function ({ statusCode, body }) { - if (statusCode === 200) { - resolve(body) - } else if (body && body.errors) { - reject(new Error(`[${statusCode}] ${body.errors[0].message} | placeIds: ${placeIds.join(',')} ${body.errors.field ? ` | ${body.errors.field} is incorrect` : ''}`)) + .then(function (res) { + if (res.statusCode === 200) { + resolve(res.body) } else { - reject(new Error(`An unknown error occurred with getPlaceInfo() | [${statusCode}] placeIds: ${placeIds.join(',')}`)) + reject(new RobloxAPIError(res)) } }).catch(reject) }) diff --git a/lib/games/getUniverseInfo.js b/lib/games/getUniverseInfo.js index 650f4be6c..db5917e63 100644 --- a/lib/games/getUniverseInfo.js +++ b/lib/games/getUniverseInfo.js @@ -1,4 +1,5 @@ const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') exports.required = ['universeId'] exports.optional = ['jar'] @@ -29,18 +30,16 @@ function getUniverseInfo (universeIds, jar) { } return http(httpOpt) - .then(function ({ statusCode, body }) { - if (statusCode === 200) { - resolve(body.data.map((universe) => { + .then(function (res) { + if (res.statusCode === 200) { + resolve(res.body.data.map((universe) => { universe.created = new Date(universe.created) universe.updated = new Date(universe.updated) return universe })) - } else if (body && body.errors) { - reject(new Error(`[${statusCode}] ${body.errors[0].message} | universeIds: ${universeIds.join(',')} ${body.errors.field ? ` | ${body.errors.field} is incorrect` : ''}`)) } else { - reject(new Error(`An unknown error occurred with getUniverseInfo() | [${statusCode}] universeIds: ${universeIds.join(',')}`)) + reject(new RobloxAPIError(res)) } }).catch(reject) }) diff --git a/lib/games/publishToTopic.js b/lib/games/publishToTopic.js index b1efe0fe7..6f2edbe0d 100644 --- a/lib/games/publishToTopic.js +++ b/lib/games/publishToTopic.js @@ -1,4 +1,5 @@ const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') exports.required = ['universeId', 'topic', 'data'] exports.optional = ['jar'] @@ -39,12 +40,7 @@ function publishToTopic (universeId, topic, data, jar) { if (res.statusCode === 200) { resolve(true) } else { - if (typeof (res.body) === 'string') { - reject(new Error(`[${res.statusCode}] ${res.statusMessage} ${res.body}`)) - } else { - const data = Object.assign(res.body) - reject(new Error(`[${res.statusCode}] ${data.Error} ${data.Message}`)) - } + reject(new RobloxAPIError(res)) } }) .catch(reject) diff --git a/lib/games/sendUserNotification.js b/lib/games/sendUserNotification.js new file mode 100644 index 000000000..e8220b68c --- /dev/null +++ b/lib/games/sendUserNotification.js @@ -0,0 +1,65 @@ +const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') + +exports.required = ['universeId', 'userId', 'assetId', 'parameters'] +exports.optional = ['jar'] + +// Docs +/** + * ☁️ Send a universe notification to a user. + * @category Game + * @alias sendUserNotification + * @param {number} universeId - The id of the universe. + * @param {number} userId - The id of the target player. + * @param {string} assetId - The asset id of the notification. + * @param {UserNotificationPayloadParameters} parameters - The notification parameters. + * @returns {Promise} + * @example const noblox = require("noblox.js") + * // Set API key + * const parameters = { + * myMessage: { stringValue: "Hello world!" } + * } + * const assetId = "774d62e5-3414-b84a-89dd-77d96f1a3d33" + * noblox.sendUserNotification(4434277335, 1210019099, assetId, parameters) + **/ + +function sendUserNotification (universeId, userId, assetId, parameters, jar) { + return new Promise((resolve, reject) => { + const httpOpt = { + url: `//apis.roblox.com/cloud/v2/users/${userId}/notifications`, + options: { + json: true, + resolveWithFullResponse: true, + jar, + method: 'POST', + body: { + source: { + universe: `universes/${universeId}` + }, + payload: { + type: 'MOMENT', + messageId: assetId, + parameters + } + }, + headers: { + 'Content-Type': 'application/json' + } + } + } + + return http(httpOpt) + .then(function (res) { + if (res.statusCode === 200) { + resolve(true) + } else { + reject(new RobloxAPIError(res)) + } + }) + .catch(reject) + }) +} + +exports.func = function (args) { + return sendUserNotification(args.universeId, args.userId, args.assetId, args.parameters, args.jar) +} diff --git a/lib/games/updateDeveloperProduct.js b/lib/games/updateDeveloperProduct.js index 58ddf3b7a..3c16b1b82 100644 --- a/lib/games/updateDeveloperProduct.js +++ b/lib/games/updateDeveloperProduct.js @@ -1,5 +1,6 @@ const http = require('../util/http.js').func const getGeneralToken = require('../util/getGeneralToken.js').func +const RobloxAPIError = require('../util/apiError.js') exports.required = ['universeId', 'productId', 'priceInRobux'] exports.optional = ['name', 'description', 'jar'] @@ -37,21 +38,11 @@ function updateDeveloperProduct (universeId, productId, priceInRobux, name, desc }, resolveWithFullResponse: true } - }).then(({ statusCode, body }) => { - if (statusCode === 200) { - resolve(body) - } else if (body && body.errors) { - reject(new Error(`[${statusCode}] ${body.errors[0].message} | universeId: ${universeId}, body: ${JSON.stringify({ - Name: name, - Description: description, - PriceInRobux: priceInRobux - })}`)) + }).then((res) => { + if (res.statusCode === 200) { + resolve(res.body) } else { - reject(new Error(`An unknown error occurred with updateDeveloperProduct() | [${statusCode}] universeId: ${universeId}, body: ${JSON.stringify({ - Name: name, - Description: description, - PriceInRobux: priceInRobux - })}`)) + reject(new RobloxAPIError(res)) } }).catch(reject) }) diff --git a/lib/groups/banFromGroup.js b/lib/groups/banFromGroup.js new file mode 100644 index 000000000..e62cc55b8 --- /dev/null +++ b/lib/groups/banFromGroup.js @@ -0,0 +1,47 @@ +// Includes +const http = require('../util/http.js') +const getGeneralToken = require('../util/getGeneralToken.js') +const RobloxAPIError = require('../util/apiError.js') + +// Args +exports.required = ['groupId', 'userId'] +exports.optional = ['jar'] + +// Docs +/** + * 🔐 Bans a user from the specified group. + * @alias banFromGroup + * @param {number} groupId - The ID of the group + * @param {number} userId - The ID of the target user + * @returns {Promise} + * @example const noblox = require("noblox.js") + * // Log in + * await noblox.banFromGroup(1, 2) +**/ + +// Define +exports.func = async function (args) { + const { groupId, jar, userId } = args + const token = await getGeneralToken({ jar }) + + const response = await http({ + url: `//groups.roblox.com/v1/groups/${groupId}/bans/${userId}`, + options: { + method: 'POST', + jar, + headers: { + 'x-csrf-token': token + }, + resolveWithFullResponse: true + } + }) + + if (response.statusCode !== 200) { + throw new RobloxAPIError(response) + } + + const body = JSON.parse(response.body) + body.created = new Date(body.created) + + return body +} diff --git a/lib/groups/deleteWallPost.js b/lib/groups/deleteWallPost.js index 45fd42e4e..cc4c1ff2a 100644 --- a/lib/groups/deleteWallPost.js +++ b/lib/groups/deleteWallPost.js @@ -1,6 +1,7 @@ // Includes const http = require('../util/http.js').func const getGeneralToken = require('../util/getGeneralToken.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['group', ['postId', 'post']] @@ -38,13 +39,7 @@ function deleteWallPost (jar, token, group, postId) { if (res.statusCode === 200) { resolve() } else { - const body = JSON.parse(res.body) || {} - if (body.errors && body.errors.length > 0) { - const errors = body.errors.map((e) => { - return e.message - }) - reject(new Error(`${res.statusCode} ${errors.join(', ')}`)) - } + reject(new RobloxAPIError(res)) } }).catch(error => reject(error)) }) diff --git a/lib/groups/deleteWallPostsByUser.js b/lib/groups/deleteWallPostsByUser.js index 56a97d1ca..69a4ce7d3 100644 --- a/lib/groups/deleteWallPostsByUser.js +++ b/lib/groups/deleteWallPostsByUser.js @@ -1,6 +1,7 @@ // Includes const http = require('../util/http.js').func const getGeneralToken = require('../util/getGeneralToken.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['group', 'userId'] @@ -35,13 +36,8 @@ function deleteWallPostsByUser (group, userId, jar, xcsrf) { return http(httpOpt) .then(function (res) { - const responseData = JSON.parse(res.body) if (res.statusCode !== 200) { - let error = 'An unknown error has occurred.' - if (responseData && responseData.errors) { - error = responseData.errors.map((e) => e.message).join('\n') - } - reject(new Error(error)) + reject(new RobloxAPIError(res)) } else { resolve() } diff --git a/lib/groups/exile.js b/lib/groups/exile.js index b63e59588..02460f33f 100644 --- a/lib/groups/exile.js +++ b/lib/groups/exile.js @@ -1,6 +1,7 @@ // Includes const http = require('../util/http.js').func const getGeneralToken = require('../util/getGeneralToken.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['group', 'target'] @@ -35,13 +36,8 @@ function exileUser (group, target, jar, xcsrf) { return http(httpOpt) .then(function (res) { - const responseData = JSON.parse(res.body) if (res.statusCode !== 200) { - let error = 'An unknown error has occurred.' - if (responseData && responseData.errors) { - error = responseData.errors.map((e) => e.message).join('\n') - } - reject(new Error(error)) + reject(new RobloxAPIError(res)) } else { resolve() } diff --git a/lib/groups/getAuditLog.js b/lib/groups/getAuditLog.js index 3b8f8016f..919637b66 100644 --- a/lib/groups/getAuditLog.js +++ b/lib/groups/getAuditLog.js @@ -1,5 +1,6 @@ // Includes const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') exports.required = ['group'] exports.optional = ['actionType', 'userId', 'sortOrder', 'limit', 'cursor', 'jar'] @@ -36,11 +37,7 @@ function getAuditLog (group, actionType, userId, sortOrder, limit, cursor, jar) .then(function (res) { const responseData = JSON.parse(res.body) if (res.statusCode !== 200) { - let error = 'An unknown error has occurred.' - if (responseData && responseData.errors) { - error = responseData.errors.map((e) => e.message).join('\n') - } - reject(new Error(error)) + reject(new RobloxAPIError(res)) } else { responseData.data = responseData.data.map((entry) => { // We need to set milliseconds to 0 because Roblox does this fascinating thing diff --git a/lib/groups/getGroup.js b/lib/groups/getGroup.js index 23dfc301c..7c7bf38c6 100644 --- a/lib/groups/getGroup.js +++ b/lib/groups/getGroup.js @@ -1,5 +1,6 @@ // Includes const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['groupId'] @@ -38,15 +39,7 @@ function getGroup (groupId) { resolve(body) } else { - const body = JSON.parse(res.body) || {} - if (body.errors && body.errors.length > 0) { - const errors = body.errors.map((e) => { - return e.message - }) - reject(new Error(`${res.statusCode} ${errors.join(', ')}`)) - } else { - reject(new Error(`${res.statusCode} ${res.body}`)) - } + reject(new RobloxAPIError(res)) } }).catch(error => reject(error)) }) diff --git a/lib/groups/getGroupBans.js b/lib/groups/getGroupBans.js new file mode 100644 index 000000000..007d2bc4c --- /dev/null +++ b/lib/groups/getGroupBans.js @@ -0,0 +1,37 @@ +// Includes +const getPageResults = require('../util/getPageResults.js').func + +// Args +exports.required = ['groupId'] +exports.optional = ['limit', 'sortOrder', 'pageCursor', 'jar'] + +// Docs +/** + * 🔐 Gets bans of a group + * @category Group + * @alias getGroupBans + * @param {number} groupId - The ID of the group + * @param {number=} limit - The number of bans to fetch maximum per page + * @param {SortOrder=} sortOrder - The order to sort the bans + * @param {string=} pageCursor - The next or previous page's cursor + * @returns {Promise} + * @example const noblox = require("noblox.js") + * await noblox.getGroupBans({ groupId: 1, limit: 100, sortOrder: "Desc" }) +**/ + +// Define +exports.func = async function (args) { + let { groupId, jar, limit, pageCursor, sortOrder } = args + limit ||= 100 + sortOrder ||= 'Desc' + + return await getPageResults({ + url: `//groups.roblox.com/v1/groups/${groupId}/bans`, + query: { + sortOrder + }, + pageCursor, + limit, + jar + }) +} diff --git a/lib/groups/getGroupSocialLinks.js b/lib/groups/getGroupSocialLinks.js index cd2d96a4e..4cb1f070b 100644 --- a/lib/groups/getGroupSocialLinks.js +++ b/lib/groups/getGroupSocialLinks.js @@ -1,6 +1,7 @@ // Includes const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['groupId'] exports.optional = ['jar'] @@ -25,16 +26,12 @@ function getGroupSocialLinks (groupId, jar) { resolveWithFullResponse: true } }) - .then(({ statusCode, body }) => { - const { errors, data } = JSON.parse(body) - if (statusCode === 200 && data) { + .then((res) => { + const { data } = JSON.parse(res.body) + if (res.statusCode === 200 && data) { return data - } else if (statusCode === 400 || statusCode === 403 || statusCode === 404) { - throw new Error(`${errors[0].message} | groupId: ${groupId}`) - } else if (statusCode === 401) { - throw new Error(`${errors[0].message} (Are you logged in?) | groupId: ${groupId}`) } else { - throw new Error(`An unknown error occurred with getGroupSocialLinks() | [${statusCode}] groupId: ${groupId}`) + throw new RobloxAPIError(res) } }) } diff --git a/lib/groups/getGroups.js b/lib/groups/getGroups.js deleted file mode 100644 index db7717ae7..000000000 --- a/lib/groups/getGroups.js +++ /dev/null @@ -1,88 +0,0 @@ -// Includes -const http = require('../util/http.js').func - -// Args -exports.required = ['userId'] -exports.optional = [] - -// Docs -/** - * ✅ Get the groups of a user. - * @category User - * @alias getGroups - * @param {number} userId - The id of the user. - * @returns {Promise} - * @example const noblox = require("noblox.js") - * let groups = await noblox.getGroups(123456) -**/ - -// Define -function getGroups (userId) { - return new Promise((resolve, reject) => { - const requests = [ - constructRequest(`//groups.roblox.com/v2/users/${userId}/groups/roles`), - constructRequest(`//groups.roblox.com/v1/users/${userId}/groups/primary/role`) - ].map(promise => promise.then( - val => ({ status: 'fulfilled', value: val }), - rej => ({ status: 'rejected', reason: rej }) - )) - - const result = [] - - Promise.all(requests).then(async (promiseResponses) => { - let responses = promiseResponses.map(response => response.value) - const failedResponse = (responses[0].statusCode !== 200 || !responses[0].body) // we only check the first request because the second one errors if a primary is not set - - if (failedResponse) { - const body = responses[0].body || {} - if (body.errors && body.errors.length > 0) { - const errors = body.errors.map((e) => { - return e.message - }) - reject(new Error(`${responses[0].statusCode} ${errors.join(', ')}`)) - } - reject(new Error('The provided user ID is not valid.')) - } - - responses = responses.map(r => r.body) - - const groupRoleData = responses[0].data - if (groupRoleData) { - const primaryGroupId = responses[1] && responses[1].group && responses[1].group.id - - const groupThumbails = await constructRequest(`https://thumbnails.roblox.com/v1/groups/icons?groupIds=${groupRoleData.map(data => data.group.id).join(',')}&size=150x150&format=Png&isCircular=false`) - - groupRoleData.forEach(data => { - const insertion = { - Id: data.group.id, - Name: data.group.name, - MemberCount: data.group.memberCount, - IsPrimary: data.group.id === primaryGroupId, - Rank: data.role.rank, - Role: data.role.name, - RoleId: data.role.id, - EmblemUrl: groupThumbails.body.data.find(thumbnail => thumbnail.targetId === data.group.id).imageUrl - } - result.push(insertion) - }) - } - - resolve(result) - }) - }) -} - -function constructRequest (url) { - return http({ - url, - options: { - resolveWithFullResponse: true, - followRedirect: false, - json: true - } - }) -} - -exports.func = function (args) { - return getGroups(args.userId) -} diff --git a/lib/groups/getJoinRequest.js b/lib/groups/getJoinRequest.js index 3b3e6c7ff..4a0c7f59f 100644 --- a/lib/groups/getJoinRequest.js +++ b/lib/groups/getJoinRequest.js @@ -1,5 +1,6 @@ // Includes const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['group', 'userId'] @@ -34,13 +35,7 @@ function getJoinRequest (jar, group, userId) { if (res.statusCode === 200) { resolve(JSON.parse(res.body) || null) } else { - const body = JSON.parse(res.body) || {} - if (body.errors && body.errors.length > 0) { - const errors = body.errors.map((e) => { - return e.message - }) - reject(new Error(`${res.statusCode} ${errors.join(', ')}`)) - } + reject(new RobloxAPIError(res)) } }).catch(error => reject(error)) }) diff --git a/lib/groups/getJoinRequests.js b/lib/groups/getJoinRequests.js index 8746085d9..6f70ff4da 100644 --- a/lib/groups/getJoinRequests.js +++ b/lib/groups/getJoinRequests.js @@ -1,5 +1,6 @@ // Includes const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['group'] @@ -36,13 +37,7 @@ function getJoinRequests (jar, group, sortOrder, limit, cursor) { if (res.statusCode === 200) { resolve(JSON.parse(res.body)) } else { - const body = JSON.parse(res.body) || {} - if (body.errors && body.errors.length > 0) { - const errors = body.errors.map((e) => { - return e.message - }) - reject(new Error(`${res.statusCode} ${errors.join(', ')}`)) - } + reject(new RobloxAPIError(res)) } }) .catch(error => reject(error)) diff --git a/lib/groups/getPlayers.js b/lib/groups/getPlayers.js index 949ac1ef3..20cd7a6b2 100644 --- a/lib/groups/getPlayers.js +++ b/lib/groups/getPlayers.js @@ -1,5 +1,6 @@ // Includes const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['group', ['rolesetId']] @@ -36,13 +37,7 @@ function getPlayersInRoleOnPage (jar, group, rolesetId, sortOrder, limit, cursor if (res.statusCode === 200) { resolve(JSON.parse(res.body)) } else { - const body = JSON.parse(res.body) || {} - if (body.errors && body.errors.length > 0) { - const errors = body.errors.map((e) => { - return e.message - }) - reject(new Error(`${res.statusCode} ${errors.join(', ')}`)) - } + reject(new RobloxAPIError(res)) } }).catch(error => reject(error)) }) diff --git a/lib/groups/getPrimaryGroup.js b/lib/groups/getPrimaryGroup.js new file mode 100644 index 000000000..8498c94b9 --- /dev/null +++ b/lib/groups/getPrimaryGroup.js @@ -0,0 +1,37 @@ +// Includes +const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') + +// Args +exports.required = ['userId'] +exports.optional = [] + +// Docs +/** + * ✅Gets the specified user's primary group. + * @category User + * @alias getPrimaryGroup + * @param {number} userId - The ID of the user. + * @returns {Promise} + * @example const noblox = require("noblox.js") + * const primaryGroup = await noblox.getPrimaryGroup(1) +**/ + +// Define +exports.func = async function (args) { + const { userId } = args + + const response = await http({ + url: `https://groups.roblox.com/v1/users/${userId}/groups/primary/role`, + options: { + json: true, + resolveWithFullResponse: true + } + }) + + if (response.statusCode !== 200) { + throw new RobloxAPIError(response) + } + + return response.body +} diff --git a/lib/groups/getRankInGroup.js b/lib/groups/getRankInGroup.js index 3b779f86a..de0542a6a 100644 --- a/lib/groups/getRankInGroup.js +++ b/lib/groups/getRankInGroup.js @@ -1,6 +1,7 @@ // Includes const http = require('../util/http.js').func const cache = require('../cache') +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['group', 'userId'] @@ -27,18 +28,10 @@ function getRankInGroup (groupId, userId) { throw new Error('Group id should be a number') } } - return http({ url: `//groups.roblox.com/v2/users/${userId}/groups/roles`, options: { json: true } }).then((body) => { - const error = body.errors && body.errors[0] + return http({ url: `//groups.roblox.com/v2/users/${userId}/groups/roles`, options: { json: true, resolveWithFullResponse: true } }).then((res) => { + if (res.statusCode !== 200) throw new RobloxAPIError(res) - if (error) { - if (error.message === 'NotFound') { - throw new Error('An invalid UserID or GroupID was provided.') - } else { - throw new Error(error.message) - } - } - - const groupObject = body.data.find((info) => groupId === info.group.id) + const groupObject = res.body.data.find((info) => groupId === info.group.id) return groupObject ? parseInt(groupObject.role.rank) : 0 }) diff --git a/lib/groups/getRankNameInGroup.js b/lib/groups/getRankNameInGroup.js index 9464306f6..6bb37b99d 100644 --- a/lib/groups/getRankNameInGroup.js +++ b/lib/groups/getRankNameInGroup.js @@ -1,6 +1,7 @@ // Includes const http = require('../util/http.js').func const cache = require('../cache') +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['group', 'userId'] @@ -27,18 +28,9 @@ function getRankNameInGroup (group, userId) { throw new Error('Group id should be a number') } } - return http({ url: `//groups.roblox.com/v2/users/${userId}/groups/roles`, options: { json: true } }).then((body) => { - const error = body.errors && body.errors[0] - - if (error) { - if (error.message === 'NotFound') { - throw new Error('An invalid UserID or GroupID was provided.') - } else { - throw new Error(error.message) - } - } - - const groupObject = body.data.find((info) => group === info.group.id) + return http({ url: `//groups.roblox.com/v2/users/${userId}/groups/roles`, options: { json: true, resolveWithFullResponse: true } }).then((res) => { + if (res.statusCode !== 200) throw new RobloxAPIError(res) + const groupObject = res.body.data.find((info) => group === info.group.id) return groupObject ? groupObject.role.name : 'Guest' }) diff --git a/lib/groups/getRolePermissions.js b/lib/groups/getRolePermissions.js index 9fe345ad6..41fd5a707 100644 --- a/lib/groups/getRolePermissions.js +++ b/lib/groups/getRolePermissions.js @@ -1,5 +1,6 @@ // Includes const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') exports.required = ['group', 'rolesetId'] exports.optional = ['jar'] @@ -32,11 +33,7 @@ function getRolePermissions (group, rolesetId, jar) { .then(function (res) { const responseData = JSON.parse(res.body) if (res.statusCode !== 200) { - let error = 'An unknown error has occurred.' - if (responseData && responseData.errors) { - error = responseData.errors.map((e) => e.message).join('\n') - } - reject(new Error(error)) + reject(new RobloxAPIError(res)) } else { resolve(responseData) } diff --git a/lib/groups/getRoles.js b/lib/groups/getRoles.js index 27f14b548..584240720 100644 --- a/lib/groups/getRoles.js +++ b/lib/groups/getRoles.js @@ -1,6 +1,7 @@ // Includes const http = require('../util/http.js').func const cache = require('../cache') +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['group'] @@ -30,11 +31,7 @@ function getRoles (group) { .then(function (res) { const responseData = JSON.parse(res.body) if (res.statusCode !== 200) { - let error = 'An unknown error has occurred.' - if (responseData && responseData.errors) { - error = responseData.errors.map((e) => e.message).join('\n') - } - reject(new Error(error)) + reject(new RobloxAPIError(res)) } else { let roles = responseData.roles roles = roles.sort((a, b) => a.rank - b.rank) diff --git a/lib/groups/getShout.js b/lib/groups/getShout.js index a12ddd401..1e2817152 100644 --- a/lib/groups/getShout.js +++ b/lib/groups/getShout.js @@ -1,5 +1,6 @@ // Includes const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['group'] @@ -31,11 +32,8 @@ function getShout (group, jar) { return http(httpOpt) .then(function (res) { const responseData = JSON.parse(res.body) - if (res.statusCode === 400) { - reject(new Error('The group is invalid or does not exist.')) - } - if (responseData.shout === null) { - reject(new Error('You do not have permissions to view the shout for the group.')) + if (res.statusCode !== 400) { + reject(new RobloxAPIError(res)) } else { resolve(responseData.shout) } diff --git a/lib/groups/getUserGroups.js b/lib/groups/getUserGroups.js new file mode 100644 index 000000000..68fb388d5 --- /dev/null +++ b/lib/groups/getUserGroups.js @@ -0,0 +1,37 @@ +// Includes +const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') + +// Args +exports.required = ['userId'] +exports.optional = [] + +// Docs +/** + * ✅ Get the groups of a user. + * @category User + * @alias getUserGroups + * @param {number} userId - The id of the user. + * @returns {Promise} + * @example const noblox = require("noblox.js") + * let groups = await noblox.getUserGroups(123456) +**/ + +// Define +exports.func = async function (args) { + const { userId } = args + + const response = await http({ + url: `https://groups.roblox.com/v2/users/${userId}/groups/roles?includeLocked=true`, + options: { + json: true, + resolveWithFullResponse: true + } + }) + + if (response.statusCode !== 200) { + throw new RobloxAPIError(response) + } + + return response.body.data +} diff --git a/lib/groups/getWall.js b/lib/groups/getWall.js index fbc7d3a17..c674b1a28 100644 --- a/lib/groups/getWall.js +++ b/lib/groups/getWall.js @@ -1,4 +1,5 @@ const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') exports.required = ['group'] exports.optional = ['sortOrder', 'limit', 'cursor', 'jar'] @@ -33,11 +34,7 @@ function getPosts (group, sortOrder, limit, cursor, jar) { .then(function (res) { const responseData = JSON.parse(res.body) if (res.statusCode !== 200) { - let error = 'An unknown error has occurred.' - if (responseData && responseData.errors) { - error = responseData.errors.map((e) => e.message).join('\n') - } - reject(new Error(error)) + reject(new RobloxAPIError(res)) } else { responseData.data = responseData.data.map((entry) => { entry.created = new Date(entry.created) diff --git a/lib/groups/handleJoinRequest.js b/lib/groups/handleJoinRequest.js index 0c19b0330..893259c3f 100644 --- a/lib/groups/handleJoinRequest.js +++ b/lib/groups/handleJoinRequest.js @@ -1,3 +1,5 @@ +const RobloxAPIError = require('../util/apiError.js') + // Includes const http = require('../util/http.js').func const getGeneralToken = require('../util/getGeneralToken.js').func @@ -36,13 +38,8 @@ function handleJoinRequest (group, userId, accept, jar, xcsrf) { return http(httpOpt) .then(function (res) { - const responseData = JSON.parse(res.body) if (res.statusCode !== 200) { - let error = 'An unknown error has occurred.' - if (responseData && responseData.errors) { - error = responseData.errors.map((e) => e.message).join('\n') - } - reject(new Error(error)) + reject(new RobloxAPIError(res)) } else { resolve() } diff --git a/lib/groups/handleJoinRequests.js b/lib/groups/handleJoinRequests.js new file mode 100644 index 000000000..bd2e68c20 --- /dev/null +++ b/lib/groups/handleJoinRequests.js @@ -0,0 +1,61 @@ +const RobloxAPIError = require('../util/apiError.js') + +// Includes +const http = require('../util/http.js').func +const getGeneralToken = require('../util/getGeneralToken.js').func + +// Args +exports.required = ['group', 'userIds', 'accept'] +exports.optional = ['jar'] + +// Docs +/** + * 🔐 Batch accept/decline multiple users' join requests. + * @category Group + * @alias handleJoinRequest + * @param {number} group - The id of the group. + * @param {Array} userIds - The ids of the users. + * @param {boolean} accept - If the users should be accepted into the group. + * @returns {Promise} + * @example const noblox = require("noblox.js") + * // Login using your cookie + * noblox.handleJoinRequests(1, [1], true) +**/ + +function handleJoinRequests (group, userIds, accept, jar, xcsrf) { + return new Promise((resolve, reject) => { + const httpOpt = { + url: `https://groups.roblox.com/v1/groups/${group}/join-requests`, + options: { + method: accept ? 'POST' : 'DELETE', + resolveWithFullResponse: true, + jar, + headers: { + 'Content-Type': 'application/json', + 'X-CSRF-TOKEN': xcsrf + }, + body: JSON.stringify({ + UserIds: userIds + }) + } + } + + return http(httpOpt) + .then(function (res) { + if (res.statusCode !== 200) { + reject(new RobloxAPIError(res)) + } else { + resolve() + } + }).catch(error => reject(error)) + }) +} + +// Define +exports.func = function (args) { + const jar = args.jar + return getGeneralToken({ jar }) + .then(function (xcsrf) { + return handleJoinRequests(args.group, args.userIds, args.accept, args.jar, xcsrf) + }) +} diff --git a/lib/groups/leaveGroup.js b/lib/groups/leaveGroup.js index 75d2eefd6..d05cd131f 100644 --- a/lib/groups/leaveGroup.js +++ b/lib/groups/leaveGroup.js @@ -2,6 +2,7 @@ const http = require('../util/http.js').func const getCurrentUser = require('../util/getCurrentUser').func const getGeneralToken = require('../util/getGeneralToken.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['group'] @@ -36,13 +37,8 @@ function leaveGroup (group, jar, xcsrf, userId) { return http(httpOpt) .then(function (res) { - const responseData = JSON.parse(res.body) if (res.statusCode !== 200) { - let error = 'An unknown error has occurred.' - if (responseData && responseData.errors) { - error = responseData.errors.map((e) => e.message).join('\n') - } - reject(new Error(error)) + reject(new RobloxAPIError(res)) } else { resolve() } diff --git a/lib/groups/multigetPartialGroups.js b/lib/groups/multigetPartialGroups.js new file mode 100644 index 000000000..25951c8cd --- /dev/null +++ b/lib/groups/multigetPartialGroups.js @@ -0,0 +1,44 @@ +// Includes +const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') + +// Args +exports.required = ['groupIds'] +exports.optional = [] + +// Docs +/** + * ✅ Gets partial info of multiple groups. + * @category Group + * @alias multigetPartialGroups + * @param {number[]} groupIds - Array of group IDs. + * @returns {Promise} + * @example const noblox = require("noblox.js") + * const groupsInfo = await noblox.multigetPartialGroups([1,2,3]) +**/ + +exports.func = async function (args) { + const { groupIds } = args + + if (!Array.isArray(groupIds)) throw TypeError('Group IDs must be an array') + + const response = await http({ + url: `https://groups.roblox.com/v2/groups?groupIds=${groupIds.join(',')}`, + options: { + json: true, + resolveWithFullResponse: true + } + }) + + if (response.statusCode !== 200) { + throw new RobloxAPIError(response) + } + + const { data } = response.body + + for (let i = 0, len = data.length; i < len; i++) { + data[i].created = new Date(data[i].created) + } + + return data +} diff --git a/lib/groups/setGroupDescription.js b/lib/groups/setGroupDescription.js index 488bfbfd0..56ba860c0 100644 --- a/lib/groups/setGroupDescription.js +++ b/lib/groups/setGroupDescription.js @@ -1,6 +1,7 @@ // Includes const http = require('../util/http.js').func const getGeneralToken = require('../util/getGeneralToken.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['group'] @@ -41,15 +42,7 @@ function changeGroupDesc (group, description = '', jar, xcsrf) { if (res.statusCode === 200) { resolve(res.body) } else { - const body = res.body || {} - if (body.errors && body.errors.length > 0) { - const errors = body.errors.map((e) => { - return e.message - }) - reject(new Error(`${res.statusCode} ${errors.join(', ')}`)) - } else { - reject(new Error(`${res.statusCode} ${res.body}`)) - } + reject(new RobloxAPIError(res)) } }) }) diff --git a/lib/groups/setGroupName.js b/lib/groups/setGroupName.js index b477b956c..db8980e8c 100644 --- a/lib/groups/setGroupName.js +++ b/lib/groups/setGroupName.js @@ -1,6 +1,7 @@ // Includes const http = require('../util/http.js').func const getGeneralToken = require('../util/getGeneralToken.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['group', 'name'] @@ -42,15 +43,7 @@ function changeGroupName (group, name, jar, xcsrf) { if (res.statusCode === 200) { resolve(res.body) } else { - const body = res.body || {} - if (body.errors && body.errors.length > 0) { - const errors = body.errors.map((e) => { - return e.message - }) - reject(new Error(`${res.statusCode} ${errors.join(', ')}`)) - } else { - reject(new Error(`${res.statusCode} ${res.body}`)) - } + reject(new RobloxAPIError(res)) } }) }) diff --git a/lib/groups/setRank.js b/lib/groups/setRank.js index b836c2622..8704244de 100644 --- a/lib/groups/setRank.js +++ b/lib/groups/setRank.js @@ -2,6 +2,7 @@ const http = require('../util/http.js').func const getGeneralToken = require('../util/getGeneralToken.js').func const getRole = require('./getRole.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['group', 'target', 'rank'] @@ -44,13 +45,7 @@ function setRank (jar, xcsrf, group, target, role) { if (res.statusCode === 200) { resolve(role) } else { - const body = JSON.parse(res.body) || {} - if (body.errors && body.errors.length > 0) { - const errors = body.errors.map((e) => { - return e.message - }) - reject(new Error(`${res.statusCode} ${errors.join(', ')}`)) - } + reject(new RobloxAPIError(res)) } }).catch(error => reject(error)) }) diff --git a/lib/groups/shout.js b/lib/groups/shout.js index f9487c350..cd9de606d 100644 --- a/lib/groups/shout.js +++ b/lib/groups/shout.js @@ -1,6 +1,7 @@ // Includes const http = require('../util/http.js').func const getGeneralToken = require('../util/getGeneralToken.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['group'] @@ -41,15 +42,7 @@ function shoutOnGroup (group, message = '', jar, xcsrf) { if (res.statusCode === 200) { resolve(res.body) } else { - const body = res.body || {} - if (body.errors && body.errors.length > 0) { - const errors = body.errors.map((e) => { - return e.message - }) - reject(new Error(`${res.statusCode} ${errors.join(', ')}`)) - } else { - reject(new Error(`${res.statusCode} ${res.body}`)) - } + reject(new RobloxAPIError(res)) } }).catch(error => reject(error)) }) diff --git a/lib/groups/unbanFromGroup.js b/lib/groups/unbanFromGroup.js new file mode 100644 index 000000000..49243d6d9 --- /dev/null +++ b/lib/groups/unbanFromGroup.js @@ -0,0 +1,41 @@ +// Includes +const http = require('../util/http.js') +const getGeneralToken = require('../util/getGeneralToken.js') +const RobloxAPIError = require('../util/apiError.js') + +// Args +exports.required = ['groupId', 'userId'] +exports.optional = ['jar'] + +// Docs +/** + * 🔐 Unbans a user from the specified group. + * @alias unbanFromGroup + * @param {number} groupId - The ID of the group + * @param {number} userId - The ID of the target user + * @returns {Promise} + * @example const noblox = require("noblox.js") + * // Log in + * await noblox.unbanFromGroup(1, 2) +**/ + +// Define +exports.func = async function (args) { + const { groupId, jar, userId } = args + const token = await getGeneralToken({ jar }) + + const response = await http({ + url: `//groups.roblox.com/v1/groups/${groupId}/bans/${userId}`, + options: { + method: 'DELETE', + jar, + headers: { + 'x-csrf-token': token + } + } + }) + + if (response.statusCode !== 200) { + throw new RobloxAPIError(response) + } +} diff --git a/lib/index.js b/lib/index.js index 073544ab1..ca42d895a 100644 --- a/lib/index.js +++ b/lib/index.js @@ -65,7 +65,6 @@ noblox.canManage = require('./develop/canManage.js') noblox.configureItem = require('./develop/configureItem.js') noblox.updateUniverse = require('./develop/updateUniverse.js') noblox.updateUniverseAccess = require('./develop/updateUniverseAccess.js') -noblox.buy = require('./economy/buy.js') noblox.getGroupFunds = require('./economy/getGroupFunds.js') noblox.getGroupRevenueSummary = require('./economy/getGroupRevenueSummary.js') noblox.getGroupTransactions = require('./economy/getGroupTransactions.js') @@ -98,6 +97,7 @@ noblox.getGameSocialLinks = require('./games/getGameSocialLinks.js') noblox.getGroupGames = require('./games/getGroupGames.js') noblox.getPlaceInfo = require('./games/getPlaceInfo.js') noblox.getUniverseInfo = require('./games/getUniverseInfo.js') +noblox.sendUserNotification = require('./games/sendUserNotification.js') noblox.publishToTopic = require('./games/publishToTopic.js') noblox.updateDeveloperProduct = require('./games/updateDeveloperProduct.js') noblox.changeRank = require('./groups/changeRank.js') @@ -107,21 +107,25 @@ noblox.demote = require('./groups/demote.js') noblox.exile = require('./groups/exile.js') noblox.getAuditLog = require('./groups/getAuditLog.js') noblox.getGroup = require('./groups/getGroup.js') +noblox.getGroupPayoutEligibility = require('./economy/getGroupPayoutEligibility.js') noblox.getGroupSocialLinks = require('./groups/getGroupSocialLinks.js') -noblox.getGroups = require('./groups/getGroups.js') noblox.getJoinRequest = require('./groups/getJoinRequest.js') noblox.getJoinRequests = require('./groups/getJoinRequests.js') noblox.getPlayers = require('./groups/getPlayers.js') +noblox.getPrimaryGroup = require('./groups/getPrimaryGroup.js') noblox.getRankInGroup = require('./groups/getRankInGroup.js') noblox.getRankNameInGroup = require('./groups/getRankNameInGroup.js') noblox.getRole = require('./groups/getRole.js') noblox.getRolePermissions = require('./groups/getRolePermissions.js') noblox.getRoles = require('./groups/getRoles.js') noblox.getShout = require('./groups/getShout.js') +noblox.getUserGroups = require('./groups/getUserGroups.js') noblox.getWall = require('./groups/getWall.js') noblox.groupPayout = require('./groups/groupPayout.js') noblox.handleJoinRequest = require('./groups/handleJoinRequest.js') +noblox.handleJoinRequests = require('./groups/handleJoinRequests.js') noblox.leaveGroup = require('./groups/leaveGroup.js') +noblox.multigetPartialGroups = require('./groups/multigetPartialGroups.js') noblox.onAuditLog = require('./groups/onAuditLog.js') noblox.onJoinRequest = require('./groups/onJoinRequest.js') noblox.onJoinRequestHandle = require('./groups/onJoinRequestHandle.js') diff --git a/lib/inventory/getOwnership.js b/lib/inventory/getOwnership.js index cf346f5ba..a305d60de 100644 --- a/lib/inventory/getOwnership.js +++ b/lib/inventory/getOwnership.js @@ -1,5 +1,6 @@ // Includes const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['userId', 'itemTargetId'] @@ -34,15 +35,7 @@ function getOwnership (userId, itemTargetId, itemType) { const body = JSON.parse(res.body) resolve(body.data.length > 0) } else { - const body = JSON.parse(res.body) || {} - if (body.errors && body.errors.length > 0) { - const errors = body.errors.map((e) => { - return e.message - }) - reject(new Error(`${res.statusCode} ${errors.join(', ')}`)) - } else { - reject(new Error(`${res.statusCode} ${res.body}`)) - } + reject(new RobloxAPIError(res)) } }) }) diff --git a/lib/premiumfeatures/getPremium.js b/lib/premiumfeatures/getPremium.js index 6db6141d3..73a728ca6 100644 --- a/lib/premiumfeatures/getPremium.js +++ b/lib/premiumfeatures/getPremium.js @@ -1,5 +1,6 @@ // Includes const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['userId'] @@ -33,13 +34,7 @@ function getPremium (jar, userId) { if (res.statusCode === 200) { resolve(res.body === 'true') } else { - const body = JSON.parse(res.body) || {} - if (body.errors && body.errors.length > 0) { - const errors = body.errors.map((e) => { - return e.message - }) - reject(new Error(`${res.statusCode} ${errors.join(', ')}`)) - } + reject(new RobloxAPIError(res)) } }) }) diff --git a/lib/presence/getPresences.js b/lib/presence/getPresences.js index a27b6c750..3cf889f9f 100644 --- a/lib/presence/getPresences.js +++ b/lib/presence/getPresences.js @@ -1,6 +1,7 @@ // Includes const http = require('../util/http.js').func const getGeneralToken = require('../util/getGeneralToken.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['userIds'] @@ -41,11 +42,7 @@ function getPresences (userIds, jar, xcsrf) { .then(function (res) { const responseData = JSON.parse(res.body) if (res.statusCode !== 200) { - let error = 'An unknown error has occurred.' - if (responseData && responseData.errors) { - error = responseData.errors.map((e) => e.message).join('\n') - } - reject(new Error(error)) + reject(new RobloxAPIError(res)) } else { resolve(responseData) } diff --git a/lib/privatemessages/getMessages.js b/lib/privatemessages/getMessages.js index 801c50f87..8eec1a57b 100644 --- a/lib/privatemessages/getMessages.js +++ b/lib/privatemessages/getMessages.js @@ -1,5 +1,6 @@ // Includes const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = [] exports.optional = ['pageNumber', 'pageSize', 'messageTab', 'jar'] @@ -34,13 +35,7 @@ function getMessages (jar, pageNumber, pageSize, messageTab) { if (res.statusCode === 200) { resolve(JSON.parse(res.body)) } else { - const body = JSON.parse(res.body) || {} - if (body.errors && body.errors.length > 0) { - const errors = body.errors.map((e) => { - return e.message - }) - reject(new Error(`${res.statusCode} ${errors.join(', ')}`)) - } + reject(new RobloxAPIError(res)) } }) }) diff --git a/lib/privatemessages/message.js b/lib/privatemessages/message.js index 9870c2026..4b0fec2b0 100644 --- a/lib/privatemessages/message.js +++ b/lib/privatemessages/message.js @@ -4,6 +4,7 @@ const queue = require('../internal/queue.js') const getGeneralToken = require('../util/getGeneralToken.js').func const getHash = require('../util/getHash.js').func const getSenderId = require('../util/getSenderUserId.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['recipient', 'subject', 'body'] @@ -53,13 +54,7 @@ function message (jar, token, senderId, recipient, subject, body, replyMessageId if (res.statusCode === 200) { resolve(JSON.parse(res.body)) } else { - const body = JSON.parse(res.body) || {} - if (body.errors && body.errors.length > 0) { - const errors = body.errors.map((e) => { - return e.message - }) - reject(new Error(`${res.statusCode} ${errors.join(', ')}`)) - } + reject(new RobloxAPIError(res)) } }) }) diff --git a/lib/thumbnails/getLogo.js b/lib/thumbnails/getLogo.js index 7dfdc810b..3a8547251 100644 --- a/lib/thumbnails/getLogo.js +++ b/lib/thumbnails/getLogo.js @@ -1,60 +1,61 @@ -// Includes -const http = require('../util/http.js').func - -// Args -exports.required = ['group'] -exports.optional = ['size', 'circular', 'format'] - -// Docs -/** - * ✅ Get the group's logo. - * @category Group - * @alias getLogo - * @param {number} group - The id of the group. - * @param {GroupIconSize=} [size=150x150] - The size of the logo. - * @param {boolean=} [circular=false] - Get the circular version of the logo. - * @param {GroupIconFormat=} [format=Png] - The file format of the logo. - * @returns {Promise} - * @example const noblox = require("noblox.js") - * const logo = await noblox.getLogo(1) -**/ - -// Define -function getLogo (group, size, circular, format) { - const httpOpt = { - url: '//thumbnails.roblox.com/v1/groups/icons', - options: { - qs: { - groupIds: group, - size: size || '150x150', - format: format || 'Png', - isCircular: circular - }, - json: true - } - } - return http(httpOpt) - .then(function (body) { - const error = body.errors && body.errors[0] - - if (error) { - if (error.message === 'NotFound') { - throw new Error('An invalid UserID or GroupID was provided.') - } else { - throw new Error(error.message) - } - } - - const thumbnailData = body.data[0] - - if (thumbnailData.state !== 'Completed') { - throw new Error('The requested image has not been approved. Status: ' + thumbnailData.state) - } - - return thumbnailData.imageUrl - }) -} - -exports.func = function (args) { - return getLogo(args.group) -} +// Includes +const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') + +// Args +exports.required = ['group'] +exports.optional = ['size', 'circular', 'format'] + +// Docs +/** + * ✅ Get the group's logo. + * @category Group + * @alias getLogo + * @param {number || number[]} group - The id(s) of the group. + * @param {GroupIconSize=} [size=150x150] - The size of the logo. + * @param {boolean=} [circular=false] - Get the circular version of the logo. + * @param {GroupIconFormat=} [format=Png] - The file format of the logo. + * @returns {Promise || Promise} + * @example const noblox = require("noblox.js") + * const logo = await noblox.getLogo(1) +**/ + +// Define +function getLogo (group, size, circular, format) { + const groupIds = Array.isArray(group) ? group.join(',') : group + const httpOpt = { + url: '//thumbnails.roblox.com/v1/groups/icons', + options: { + qs: { + groupIds, + size: size || '150x150', + format: format || 'Png', + isCircular: circular + }, + json: true, + resolveWithFullResponse: true + } + } + return http(httpOpt) + .then(function (res) { + if (res.statusCode !== 200) { + throw new RobloxAPIError(res) + } + + const urls = [] + + for (const thumb of res.body.data) { + if (thumb.state !== 'Completed') { + throw new Error(`The requested image for group ${thumb.targetId} has not been approved. State: ${thumb.state}`) + } + + urls.push(thumb.imageUrl) + } + + return urls.length > 1 ? urls : urls.at(0) + }) +} + +exports.func = function (args) { + return getLogo(args.group) +} diff --git a/lib/thumbnails/getPlayerThumbnail.js b/lib/thumbnails/getPlayerThumbnail.js index 832bffd2b..8a2529154 100644 --- a/lib/thumbnails/getPlayerThumbnail.js +++ b/lib/thumbnails/getPlayerThumbnail.js @@ -1,6 +1,7 @@ // Includes const http = require('../util/http.js').func const { thumbnail: settings } = require('../../settings.json') +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['userIds'] @@ -85,9 +86,9 @@ function getPlayerThumbnail (userIds, size, format = 'png', isCircular = false, followRedirect: true } }) - .then(async ({ statusCode, body }) => { - let { data, errors } = JSON.parse(body) - if (statusCode === 200) { + .then(async (res) => { + let { data } = JSON.parse(res.body) + if (res.statusCode === 200) { if (retryCount > 0) { const pendingThumbnails = data.filter(obj => { return obj.state === 'Pending' }).map(obj => obj.targetId) // Get 'Pending' thumbnails as array of userIds if (pendingThumbnails.length > 0) { @@ -104,10 +105,8 @@ function getPlayerThumbnail (userIds, size, format = 'png', isCircular = false, return obj }) return data - } else if (statusCode === 400) { - throw new Error(`Error Code ${errors.code}: ${errors.message} | endpoint: ${endpoint}, userIds: ${userIds.join(',')}, size: ${size}, isCircular: ${!!isCircular}`) } else { - throw new Error(`An unknown error occurred with getPlayerThumbnail() | endpoint: ${endpoint}, userIds: ${userIds.join(',')}, size: ${size}, isCircular: ${!!isCircular}`) + throw new RobloxAPIError(res) } }) } diff --git a/lib/thumbnails/getThumbnails.js b/lib/thumbnails/getThumbnails.js index 6c11c4f66..4af13df9e 100644 --- a/lib/thumbnails/getThumbnails.js +++ b/lib/thumbnails/getThumbnails.js @@ -1,6 +1,7 @@ // Includes const http = require('../util/http.js').func const { thumbnail: settings } = require('../../settings.json') +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['thumbnailRequests'] @@ -58,9 +59,9 @@ function getThumbnails (requests, retryCount = settings.maxRetries) { followRedirect: true } }) - .then(async ({ statusCode, body }) => { - let { data, errors } = body - if (statusCode === 200) { + .then(async (res) => { + let { data } = res.body + if (res.statusCode === 200) { if (retryCount > 0) { const pendingThumbnails = data.filter(obj => { return obj.state === 'Pending' }).map(obj => obj.targetId) // Get 'Pending' thumbnails as array of userIds if (pendingThumbnails.length > 0) { @@ -76,10 +77,8 @@ function getThumbnails (requests, retryCount = settings.maxRetries) { return obj }) return data - } else if (statusCode === 400) { - throw new Error(`Error Code ${errors.code}: ${errors.message} | requests: ${JSON.stringify(requests)}`) } else { - throw new Error(`An unknown error occurred with getThumbnails() | requests: ${JSON.stringify(requests)}`) + throw new RobloxAPIError(res) } }) } diff --git a/lib/trades/acceptTrade.js b/lib/trades/acceptTrade.js index d34ba9785..67c542107 100644 --- a/lib/trades/acceptTrade.js +++ b/lib/trades/acceptTrade.js @@ -1,6 +1,7 @@ // Includes const http = require('../util/http.js').func const getGeneralToken = require('../util/getGeneralToken.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['tradeId'] @@ -36,14 +37,7 @@ function acceptTrade (tradeId, jar, xcsrf) { if (res.statusCode === 200) { resolve() } else { - const body = JSON.parse(res.body) || {} - - if (body.errors && body.errors.length > 0) { - const errors = body.errors.map((e) => { - return e.message - }) - reject(new Error(`${res.statusCode} ${errors.join(', ')}`)) - } + reject(new RobloxAPIError(res)) } }).catch(error => reject(error)) }) diff --git a/lib/trades/canTradeWith.js b/lib/trades/canTradeWith.js index 376d504f6..98bb27f79 100644 --- a/lib/trades/canTradeWith.js +++ b/lib/trades/canTradeWith.js @@ -1,5 +1,6 @@ // Includes const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['userId'] @@ -31,13 +32,7 @@ function canTradeWith (jar, userId) { if (res.statusCode === 200) { resolve(JSON.parse(res.body)) } else { - const body = JSON.parse(res.body) || {} - if (body.errors && body.errors.length > 0) { - const errors = body.errors.map((e) => { - return e.message - }) - reject(new Error(`${res.statusCode} ${errors.join(', ')}`)) - } + reject(new RobloxAPIError(res)) } }).catch(error => reject(error)) }) diff --git a/lib/trades/counterTrade.js b/lib/trades/counterTrade.js index 6e24c34ed..29df6e9ad 100644 --- a/lib/trades/counterTrade.js +++ b/lib/trades/counterTrade.js @@ -2,6 +2,7 @@ const http = require('../util/http.js').func const getGeneralToken = require('../util/getGeneralToken.js').func const getCurrentUser = require('../util/getCurrentUser.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['tradeId', 'targetUserId', 'sendingOffer', 'receivingOffer'] @@ -59,14 +60,7 @@ function counterTrade (tradeId, targetUserId, sendingOffer, receivingOffer, jar, if (res.statusCode === 200) { resolve(JSON.parse(res.body)) } else { - const body = JSON.parse(res.body) || {} - - if (body.errors && body.errors.length > 0) { - const errors = body.errors.map((e) => { - return e.message - }) - reject(new Error(`${res.statusCode} ${errors.join(', ')}`)) - } + reject(new RobloxAPIError(res)) } }).catch(error => reject(error)) }) diff --git a/lib/trades/declineTrade.js b/lib/trades/declineTrade.js index ef132b144..4b7dfbce7 100644 --- a/lib/trades/declineTrade.js +++ b/lib/trades/declineTrade.js @@ -1,6 +1,7 @@ // Includes const http = require('../util/http.js').func const getGeneralToken = require('../util/getGeneralToken.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['tradeId'] @@ -36,14 +37,7 @@ function declineTrade (tradeId, jar, xcsrf) { if (res.statusCode === 200) { resolve() } else { - const body = JSON.parse(res.body) || {} - - if (body.errors && body.errors.length > 0) { - const errors = body.errors.map((e) => { - return e.message - }) - reject(new Error(`${res.statusCode} ${errors.join(', ')}`)) - } + reject(new RobloxAPIError(res)) } }).catch(error => reject(error)) }) diff --git a/lib/trades/getTradeInfo.js b/lib/trades/getTradeInfo.js index a49c7d037..a65bd1392 100644 --- a/lib/trades/getTradeInfo.js +++ b/lib/trades/getTradeInfo.js @@ -1,5 +1,6 @@ // Includes const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['tradeId'] @@ -35,13 +36,7 @@ const getTradeInfo = (jar, tradeId) => { resolve(body) } else { - const body = JSON.parse(res.body) || {} - if (body.errors && body.errors.length > 0) { - const errors = body.errors.map((e) => { - return e.message - }) - reject(new Error(`${res.statusCode} ${errors.join(', ')}`)) - } + reject(new RobloxAPIError(res)) } }).catch(error => reject(error)) }) diff --git a/lib/trades/sendTrade.js b/lib/trades/sendTrade.js index 40706d5f8..ec285de43 100644 --- a/lib/trades/sendTrade.js +++ b/lib/trades/sendTrade.js @@ -2,6 +2,7 @@ const http = require('../util/http.js').func const getGeneralToken = require('../util/getGeneralToken.js').func const getCurrentUser = require('../util/getCurrentUser.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['targetUserId', 'sendingOffer', 'receivingOffer'] @@ -57,14 +58,7 @@ function sendTrade (targetUserId, sendingOffer, receivingOffer, jar, xcsrf, logg if (res.statusCode === 200) { resolve(JSON.parse(res.body)) } else { - const body = JSON.parse(res.body) || {} - - if (body.errors && body.errors.length > 0) { - const errors = body.errors.map((e) => { - return e.message - }) - reject(new Error(`${res.statusCode} ${errors.join(', ')}`)) - } + reject(new RobloxAPIError(res)) } }).catch(error => reject(error)) }) diff --git a/lib/users/getBlurb.js b/lib/users/getBlurb.js index ccae641fb..2793a3f4c 100644 --- a/lib/users/getBlurb.js +++ b/lib/users/getBlurb.js @@ -1,5 +1,6 @@ // Includes const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['userId'] @@ -30,7 +31,7 @@ exports.func = function (args) { const parsedBody = JSON.parse(res.body) return parsedBody.description } else { - throw new Error('User does not exist') + throw new RobloxAPIError(res) } }) } diff --git a/lib/users/getIdFromUsername.js b/lib/users/getIdFromUsername.js index d3729fa3a..95ad3ab29 100644 --- a/lib/users/getIdFromUsername.js +++ b/lib/users/getIdFromUsername.js @@ -1,6 +1,7 @@ // Includes const http = require('../util/http.js').func const cache = require('../cache') +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['username'] @@ -27,12 +28,14 @@ function getIdFromUsername (usernames) { json: { usernames, excludeBannedUsers: false - } + }, + resolveWithFullResponse: true } } return http(httpOpt) - .then(function (body) { - const data = body.data + .then(function (res) { + if (res.statusCode !== 200) throw new RobloxAPIError(res) + const data = res.body.data let results = usernames.map((username) => { return data.find((result) => result.requestedUsername === username) diff --git a/lib/users/getUserInfo.js b/lib/users/getUserInfo.js index df1b35cb3..44dfbe2a3 100644 --- a/lib/users/getUserInfo.js +++ b/lib/users/getUserInfo.js @@ -1,5 +1,6 @@ // Includes const http = require('../util/http.js').func +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['userId'] @@ -25,7 +26,7 @@ exports.func = function (args) { } return http(httpOpt).then(function (res) { - if (res.statusCode !== 200) { throw new Error(`Failed to fetch user information: ${res.body?.errors?.at(0)?.message}`) } + if (res.statusCode !== 200) { throw new RobloxAPIError(res) } res.body.created = new Date(res.body.created) diff --git a/lib/users/getUsernameFromId.js b/lib/users/getUsernameFromId.js index cb2f2d969..7e7c515e7 100644 --- a/lib/users/getUsernameFromId.js +++ b/lib/users/getUsernameFromId.js @@ -1,6 +1,7 @@ // Includes const http = require('../util/http.js').func const cache = require('../cache') +const RobloxAPIError = require('../util/apiError.js') // Args exports.required = ['id'] @@ -31,7 +32,7 @@ function getUsernameFromId (id) { const json = JSON.parse(res.body) return json.name } else { - throw new Error('User does not exist') + throw new RobloxAPIError(res) } }) } diff --git a/lib/util/apiError.js b/lib/util/apiError.js index 91796211f..045eb2587 100644 --- a/lib/util/apiError.js +++ b/lib/util/apiError.js @@ -26,6 +26,15 @@ class RobloxAPIError extends Error { return obj } else return { code: 0, message: this.responseBody } // Roblox did a funny (i.e. the platform is down) } + + get caller () { + try { + // https://stackoverflow.com/a/57023880 + return (new Error()).stack?.split('\n')[2]?.trim().split(' ').at(1) ?? null + } catch { + return null + } + } } function getResponseBody (data) { @@ -38,4 +47,4 @@ function getResponseBody (data) { } } -export default RobloxAPIError +module.exports = RobloxAPIError diff --git a/lib/util/getPageResults.js b/lib/util/getPageResults.js index 11c78b06a..bc56094f9 100644 --- a/lib/util/getPageResults.js +++ b/lib/util/getPageResults.js @@ -1,5 +1,6 @@ // Includes const http = require('./http.js').func +const RobloxAPIError = require('./apiError.js') // Args exports.required = ['url', 'query', 'limit'] @@ -46,12 +47,8 @@ function getPageResults (jar, url, query, sortOrder, limit, pageCursor, results) const data = body.data - if (body.errors && body.errors.length > 0) { - const errors = body.errors.map((e) => { - return e.message - }) - - return reject(new Error(`${res.statusCode} ${errors.join(', ')}`)) + if (res.statusCode !== 200) { + return reject(new RobloxAPIError(res)) } results = results ? results.concat(data) : data diff --git a/lib/util/http.js b/lib/util/http.js index 80279f5a8..8675fad78 100644 --- a/lib/util/http.js +++ b/lib/util/http.js @@ -7,6 +7,7 @@ const options = require('../options.js') const settings = require('../../settings.json') const cache = require('../cache') const getHash = require('./getHash.js').func +const { version } = require('../../package.json') // Args exports.required = ['url'] @@ -20,7 +21,12 @@ request = request.defaults({ }, simple: false, gzip: true, - timeout: settings.timeout + timeout: settings.timeout, + headers: settings.use_noblox_ua + ? { + 'user-agent': `noblox-${version}` + } + : undefined }) // Docs @@ -67,6 +73,23 @@ function http (url, opt) { if (url.indexOf('http') !== 0) { url = 'https:' + url } + + /* + In CI, actions does not allow us to use a static ip address (nor guarantees any particular location) + This is a problem as Roblox locks sessions to a particular region + Therefore, we intercept the request during testing and send it to the forwarder (which has a static ip address), the Roblox hostname is set as the Destination-Host header + The ID token is for Google Cloud and allows authenticating with the Cloud Run service that acts as our forwarder + Requests without auth headers do not go through the forwarder as they are unauthenticated and do not need forwarding + */ + if (process?.env.CI && process.env.FORWARDER_HOSTNAME && (opt.headers.cookie || opt.headers['x-api-key'])) { + const urlObj = new URL(url) + const { hostname } = urlObj + + opt.headers['Destination-Host'] = hostname + opt.headers['x-serverless-authorization'] = `Bearer ${process.env.ID_TOKEN}` + urlObj.hostname = process.env.FORWARDER_HOSTNAME + url = urlObj.href + } return request(url, opt) } diff --git a/package.json b/package.json index fd3bf8e8c..c661ba209 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "noblox.js", - "version": "6.2.0", + "version": "7.4.0", "description": "A Node.js API wrapper for Roblox.", "main": "lib/index.js", "types": "typings/index.d.ts", @@ -67,15 +67,11 @@ "lib/*/on*.js" ] }, - "auto": { - "plugins": [ - "npm", - "conventional-commits" - ], - "onlyPublishWithReleaseLabel": true + "release": { + "branches": ["master", "next"] }, "engines": { - "node": ">=18.18" + "node": ">=20.0" }, "packageManager": "yarn@1.22.19+sha1.4ba7fc5c6e704fce2066ecbfb0b0d8976fe62447" } diff --git a/settings.json b/settings.json index 355526523..1daa550cd 100644 --- a/settings.json +++ b/settings.json @@ -1,4 +1,6 @@ { + "use_noblox_ua": true, + "show_deprecation_warnings": true, "show_deprecation_warnings_desc": "Prints console warnings for functions that are being polyfilled by newer methods due to upstream Roblox API changes", diff --git a/test/economy.test.js b/test/economy.test.js index 06dfefc75..ebe009197 100644 --- a/test/economy.test.js +++ b/test/economy.test.js @@ -1,4 +1,4 @@ -const { buy, getGroupFunds, getGroupRevenueSummary, getGroupTransactions, getResaleData, getResellers, getUserTransactions, setCookie } = require('../lib') +const { buy, getGroupFunds, getGroupPayoutEligibility, getGroupRevenueSummary, getGroupTransactions, getResaleData, getResellers, getUserTransactions, setCookie } = require('../lib') beforeAll(() => { return new Promise(resolve => { @@ -24,6 +24,12 @@ describe('Economy Methods', () => { }) }) + it('getGroupPayoutEligibility() returns a list of payout statuses for specified users', () => { + return getGroupPayoutEligibility({ group: 9997719, member: 55549140 }).then((res) => { + return expect(res).toMatchObject({ [expect.any(String)]: expect.any(String) }) + }) + }) + it('getGroupRevenueSummary() returns a revenue summary for a group', () => { return getGroupRevenueSummary(9997719).then((res) => { return expect(res).toMatchObject({ diff --git a/test/games.test.js b/test/games.test.js index ac4ee8c96..dc9a85123 100644 --- a/test/games.test.js +++ b/test/games.test.js @@ -1,6 +1,8 @@ -const { addDeveloperProduct, checkDeveloperProductName, getGroupGames, configureGamePass, getGameInstances, getGamePasses, getGameSocialLinks, getUniverseInfo, setCookie } = require('../lib') +const { addDeveloperProduct, checkDeveloperProductName, getAuthenticatedUser, getGroupGames, configureGamePass, getGameInstances, getGamePasses, getGameSocialLinks, getUniverseInfo, sendUserNotification, setAPIKey, setCookie } = require('../lib') beforeAll(() => { + setAPIKey(process.env.API_KEY) + return new Promise(resolve => { setCookie(process.env.COOKIE).then(() => { resolve() @@ -193,6 +195,21 @@ it('getPlaceInfo() should return an array of information about places', () => { }) }) + it('sendUserNotification() should successfully send a user notification', async () => { + const { id: userId } = await getAuthenticatedUser() + + return await expect( + sendUserNotification({ + universeId: 2152417643, + userId, + assetId: "", + parameters: { + test: "test" + } + }) + ).resolves.not.toThrow() + }) + // Dependency on getDeveloperProducts() which is broken as of 4.14.0 // eslint-disable-next-line jest/no-commented-out-tests // it('updateDeveloperProduct() should update a developer product with new information', () => { diff --git a/test/groups.test.js b/test/groups.test.js index 2ad99d008..ab11ee1b0 100644 --- a/test/groups.test.js +++ b/test/groups.test.js @@ -1,4 +1,4 @@ -const { changeRank, demote, getAuditLog, getGroup, getGroups, getGroupSocialLinks, getJoinRequests, getPlayers, getRankInGroup, getRankNameInGroup, getRole, getRolePermissions, getRoles, getShout, getWall, promote, searchGroups, setRank, shout, setCookie } = require('../lib') +const { banFromGroup, changeRank, demote, getAuditLog, getGroup, getGroupBans, getGroupSocialLinks, getJoinRequests, getPlayers, getPrimaryGroup, getRankInGroup, getRankNameInGroup, getRole, getRolePermissions, getRoles, getShout, getUserGroups, getWall, multigetPartialGroups, promote, searchGroups, setRank, shout, setCookie, unbanFromGroup } = require('../lib') beforeAll(() => { return new Promise(resolve => { @@ -115,25 +115,6 @@ describe('Groups Methods', () => { }) }) - it('getGroups() should return groups the specified user is in', async () => { - return getGroups(55549140).then((res) => { - return expect(res).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - Id: expect.any(Number), - Name: expect.any(String), - EmblemUrl: expect.any(String), - MemberCount: expect.any(Number), - Rank: expect.any(Number), - Role: expect.any(String), - RoleId: expect.any(Number), - IsPrimary: expect.any(Boolean) - }) - ]) - ) - }) - }) - it('getGroupSocialLinks() should return social link information of a game, given universeId', () => { return getGroupSocialLinks(9997719).then((res) => { return expect(res).toEqual( @@ -174,6 +155,36 @@ describe('Groups Methods', () => { }) }) + it('getPrimaryGroup() returns the specified user\'s primary group', () => { + return getPrimaryGroup(55549140).then((res) => { + return expect(res).toEqual( + expect.objectContaining({ + group: expect.objectContaining({ + id: expect.any(Number), + name: expect.any(String), + description: expect.any(String), + owner: expect.objectContaining({ + hasVerifiedBadge: expect.any(Boolean), + userId: expect.any(Number), + username: expect.any(String), + displayName: expect.any(String) + }), + shout: expect.toBeNull(), + isBuildersClubOnly: expect.any(Boolean), + publicEntryAllowed: expect.any(Boolean), + hasVerifiedBadge: expect.any(Boolean), + hasSocialModules: expect.any(Boolean), + }), + role: expect.objectContaining({ + id: expect.any(Number), + name: expect.any(String), + rank: expect.any(Number) + }) + }) + ) + }) + }) + it('getRankInGroup() returns a number reflecting a user\'s rank in a group (0-255)', () => { return getRankInGroup(4591072, 55549140).then((res) => { return expect(res).toEqual(expect.any(Number)) @@ -236,6 +247,28 @@ describe('Groups Methods', () => { }) }) + it('getUserGroups() should return groups the specified user is in', async () => { + return getUserGroups(55549140).then((res) => { + return expect(res).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + group: expect.objectContaining({ + id: expect.any(Number), + name: expect.any(String), + memberCount: expect.any(Number), + hasVerifiedBadge: expect.any(Boolean) + }), + role: expect.objectContaining({ + id: expect.any(Number), + name: expect.any(String), + rank: expect.any(Number) + }) + }) + ]) + ) + }) + }) + it('getWall() returns the latest messages on the group wall', () => { return getWall(4591072).then((res) => { return expect(res).toMatchObject({ @@ -258,8 +291,30 @@ describe('Groups Methods', () => { // PASS: handleJoinRequest, would require being able to request to join a group + // PASS: handleJoinRequests, would require being able to request to join a group + // PASS: leaveGroup, would require being able to request to join a group + it('multigetPartialGroups() returns partial information of multiple groups', () => { + return multigetPartialGroups([4591072]).then((res) => { + return expect(res).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + id: expect.any(Number), + name: expect.any(String), + description: expect.any(String), + owner: expect.objectContaining({ + id: expect.any(Number), + name: expect.any(String) + }), + created: expect.any(Date), + hasVerifiedBadge: expect.any(Boolean) + }) + ]) + ) + }) + }) + it('searchGroups() returns groups that match the query', () => { return searchGroups('noblox.js').then((res) => { return expect(res).toEqual( @@ -308,6 +363,68 @@ describe('Groups Methods', () => { }) }) }) + + it('banFromGroup() should ban a user from the specified group', () => { + return banFromGroup(4591072, 1).then((res) => { + return expect(res).toMatchObject({ + user: { + hasVerifiedBadge: expect.any(Boolean), + userId: expect.any(Number), + username: expect.any(String), + displayName: expect.any(String) + }, + actingUser: { + user: { + hasVerifiedBadge: expect.any(Boolean), + userId: expect.any(Number), + username: expect.any(String), + displayName: expect.any(String) + }, + role: { + id: expect.any(Number), + name: expect.any(String), + rank: expect.any(Number) + } + }, + created: expect.any(Date) + }) + }) + }) + + it('getGroupBans() should retrieve a page of group bans', () => { + return getGroupBans(4591072, 10, 'Asc').then((res) => { + return expect(res).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + user: { + hasVerifiedBadge: expect.any(Boolean), + userId: expect.any(Number), + username: expect.any(String), + displayName: expect.any(String) + }, + actingUser: { + user: { + hasVerifiedBadge: expect.any(Boolean), + userId: expect.any(Number), + username: expect.any(String), + displayName: expect.any(String) + }, + role: { + id: expect.any(Number), + name: expect.any(String), + rank: expect.any(Number) + } + }, + created: expect.any(Date) + }) + ]) + ) + }) + }) + + it('unbanFromGroup() should unban a user from a group', async () => { + await expect(unbanFromGroup(4591072, 1)).resolves.not.toThrow() + }) }) it('setRank() should set a player\'s rank to the specified rank', () => { diff --git a/typings/index.d.ts b/typings/index.d.ts index b81be4ab5..e2736d169 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -11,6 +11,7 @@ declare module "noblox.js" { */ interface CookieJar { session?: string; + apiKey?: string; } /** @@ -23,6 +24,13 @@ declare module "noblox.js" { /** Minimizes data usage and speed up requests by only saving session cookies, disable if you need other cookies to be saved as well. (Default: true) */ session_only: boolean; + /** + * Whether to send the noblox.js library user agent. Defaults to true. + * When enabled, noblox will set the user-agent on requests to 'noblox@{version}' where {version} is your library version. + * This allows Roblox to track endpoint and library usage. If you are privacy or aggregation conscious set this to false. + */ + use_noblox_ua: boolean; + /** This is usually used for functions that have to receive a lot of pages at once. Only this amount will be queued up as to preserve memory, make this as high as possible for fastest responses (although it will be somewhat limited by maxSockets). (Default: 50) */ max_threads: number; @@ -163,15 +171,18 @@ declare module "noblox.js" { HasVerifiedBadge: boolean; } - interface IGroupPartial { - Name: string, - Id: number, - EmblemUrl: string, - MemberCount: number, - Rank: number, - Role: string, - RoleId: number, - IsPrimary: boolean, + interface GroupMemberInfo { + group: { + id: number; + name: string; + memberCount: number; + hasVerifiedBadge: boolean; + }; + role: { + id: number; + name: string; + rank: number; + } } interface GroupGameInfo { @@ -220,23 +231,11 @@ declare module "noblox.js" { type GamePassProductInfo = Omit; - interface BuyProductInfo { - ProductId: number; - Creator: { Id: number }; - PriceInRobux: number; - UserAssetId: number; - } - interface PriceRange { high: number; low: number; } - interface BuyAssetResponse { - productId: number; - price: number; - } - interface ChartDataPointResponse { value?: number; date?: Date; @@ -583,6 +582,12 @@ declare module "noblox.js" { } /// Game + type UserNotificationPayloadParameter = { stringValue: string } | { int64Value: number }; + + interface UserNotificationPayloadParameters { + [key: string]: UserNotificationPayloadParameter + } + interface GameInstance { id: string; maxPlayers: number; @@ -765,6 +770,7 @@ declare module "noblox.js" { memberCount?: number; rank: number; id: number; + color?: number; } interface RoleWithDescription { @@ -832,7 +838,8 @@ declare module "noblox.js" { memberCount: number; isBuildersClubOnly: boolean; publicEntryAllowed: boolean; - isLocked: boolean; + hasVerifiedBadge: boolean; + hasSocialModules: boolean; } interface GroupSearchItem { @@ -866,6 +873,29 @@ declare module "noblox.js" { updated: Date; } + interface GroupMultigetPartial { + id: number; + name: string; + description: string; + owner: { + id: number; + type: string; + }; + created: Date; + hasVerifiedBadge: boolean; + } + + interface PrimaryGroup { + group: Group; + role: Role; + } + + interface PayoutAllowedList { + usersGroupPayoutEligibility: { + [K: string]: string; + } + } + interface GroupDescriptionResult { newDescription: string } @@ -966,6 +996,14 @@ declare module "noblox.js" { data: WallPost[]; } + interface GroupBan { + user: UserEntry; + actingUser: { + user: UserEntry; + }, + created: Date; + } + /// Party interface PartyData { @@ -1091,6 +1129,7 @@ declare module "noblox.js" { // interface UserEntry { + hasVerifiedBadge: boolean; userId: number; name: string; displayName: string; @@ -1759,15 +1798,15 @@ declare module "noblox.js" { /// Economy - /** - * 🔐 Buys asset `asset` with `price` restrictions. This can be a single value or an object with `high` and `low` that sets the respective price limits (both inclusive). This allows you to buy assets with a minimum or maximum amount of robux that can be used or a single required value and therefore guarantees you can't be scammed by a sudden price change. If a price restriction is not set, the asset will be bought for however much it costs (works with free assets). You are able to use product instead of asset, the options in `product` are collected automatically if not provided. - */ - function buy(asset: number | ProductInfo | BuyProductInfo, price?: number | PriceRange, jar?: CookieJar): Promise; - /** * 🔓 Gets the amount of Robux in a group. */ function getGroupFunds(group: number): Promise; + + /** + * 🔐 Gets the payout eligibility status of a group member. + */ + function getGroupPayoutEligibility(groupId: number, userIds: number[], jar?: CookieJar): Promise; /** * 🔐 Gets recent Robux revenue summary for a group; shows pending Robux. | Requires "Spend group funds" permissions. @@ -1917,6 +1956,11 @@ declare module "noblox.js" { */ function publishToTopic(universeId: number, topic: string, data: (Object | string), jar?: CookieJar): Promise; + /** +* ☁️ Send a universe notification to a user. +*/ + function sendUserNotification(universeId: number, userId: number, assetId: string, parameters: UserNotificationPayloadParameters, jar?: CookieJar): Promise; + /** * 🔐 Returns information about the place(s) in question, such as name, description, etc. */ @@ -1928,6 +1972,12 @@ declare module "noblox.js" { function updateDeveloperProduct(universeId: number, productId: number, priceInRobux: number, name?: string, description?: string, jar?: CookieJar): Promise; /// Groups + + /** + * 🔐 Bans a user from the specified group. + */ + function banFromGroup(groupId: number, userId: number, jar?: CookieJar): Promise; + /** * 🔐 Moves the user with userId `target` up or down the list of ranks in `group` by `change`. For example `changeRank(group, target, 1)` would promote the user 1 rank and `changeRank(group, target, -1)` would demote them down 1. Note that this simply follows the list, ignoring ambiguous ranks. The full `newRole` as well as the user's original `oldRole` is returned. */ @@ -1964,9 +2014,9 @@ declare module "noblox.js" { function getGroup(groupId: number): Promise; /** - * ✅ Gets the groups a player is in. + * 🔐 Gets a list of the group's bans. */ - function getGroups(userId: number): Promise + function getGroupBans(groupId: number, limit?: number, sortOrder?: SortOrder, pageCursor?: string, jar?: CookieJar): Promise<{ previousPageCursor?: string, nextPageCursor?: string, data: GroupBan[] }>; /** * 🔐 Get the social link data associated with a group. @@ -1989,8 +2039,13 @@ declare module "noblox.js" { function getPlayers(group: number, rolesetId: number[] | number, sortOrder?: SortOrder, limit?: number, jar?: CookieJar): Promise; /** - * ✅ Gets `rank` of user with `userId` in `group` and caches according to settings. - */ + * ✅Gets the specified user's primary group. + */ + function getPrimaryGroup(userId: number): Promise; + + /** + * ✅ Gets `rank` of user with `userId` in `group` and caches according to settings. + */ function getRankInGroup(group: number, userId: number): Promise; /** @@ -2018,6 +2073,11 @@ declare module "noblox.js" { */ function getShout(group: number, jar?: CookieJar): Promise; + /** + * ✅ Gets the groups a player is in. + */ + function getUserGroups(userId: number): Promise; + /** * 🔓 Gets posts on the `group` wall. Parameter `page` may be a number or array where negative numbers indicate trailing pages, if it is not specified all pages of the wall will be retrieved. * The body of the post is in `content` and the `id` and `name` of the poster are stored in the `author` object. The `id` is the unique ID of the wall post that is internally used by ROBLOX. This serves no real use other than reporting it (although it can be used indirectly to track down specific posts). @@ -2037,11 +2097,21 @@ declare module "noblox.js" { */ function handleJoinRequest(group: number, userId: number, accept: boolean, jar?: CookieJar): Promise; + /** + * 🔐 Batch accept/decline multiple users' join requests. + */ + function handleJoinRequests(group: number, userIds: number[], accept: boolean, jar?: CookieJar): Promise; + /** * 🔐 Leaves the group with id `group`. Unless `useCache` is enabled the function will not cache because errors will occur if joining or leaving the same group multiple times, you can enable it if you are only joining or leaving a group once or many differenct groups once. */ function leaveGroup(group: number, jar?: CookieJar): Promise; + /** + * ✅ Gets partial info of multiple groups. + */ + function multigetPartialGroups(groupIds: number[]): Promise; + /** * 🔐 Alias of `changeRank(group, target, 1)`. */ @@ -2077,6 +2147,11 @@ declare module "noblox.js" { */ function shout(group: number, message: string, jar?: CookieJar): Promise; + /** + * 🔐 Unbans a user from the specified group. + */ + function unbanFromGroup(groupId: number, userId: number, jar?: CookieJar): Promise; + /// Inventory /** @@ -2137,9 +2212,9 @@ declare module "noblox.js" { /// Thumbnails /** - * ✅ Gets the logo of the specified group. + * ✅ Gets the logo of the specified group(s). */ - function getLogo(groupId: number, size?: GroupIconSize, circular?: boolean, format?: GroupIconFormat): Promise; + function getLogo(groupIds: number | number[], size?: GroupIconSize, circular?: boolean, format?: GroupIconFormat): Promise | Promise; /** * ✅ Gets the thumbnail of an array of users. @@ -2247,7 +2322,7 @@ declare module "noblox.js" { * 🔐 Get the current authenticated user. */ function getAuthenticatedUser(jar?: CookieJar): Promise - + /** * 🔐 Gets the current user logged into `jar` and returns an `option` if specified or all options if not. */ diff --git a/typings/jsDocs.ts b/typings/jsDocs.ts index 68f660111..ca0b73d76 100644 --- a/typings/jsDocs.ts +++ b/typings/jsDocs.ts @@ -17,6 +17,13 @@ type NobloxOptions = { /** Prints console warnings for functions that are being polyfilled by newer methods due to upstream Roblox API changes */ show_deprecation_warnings: boolean; + /** + * Whether to send the noblox.js library user agent. Defaults to true. + * When enabled, noblox will set the user-agent on requests to 'noblox@{version}' where {version} is your library version. + * This allows Roblox to track endpoint and library usage. If you are privacy or aggregation conscious, set this to false. + */ + use_noblox_ua: boolean; + /** Minimizes data usage and speed up requests by only saving session cookies, disable if you need other cookies to be saved as well. (Default: true) */ session_only: boolean; @@ -197,16 +204,6 @@ type ProductInfo = { */ type GamePassProductInfo = Omit; -/** - * @typedef -*/ -type BuyProductInfo = { - ProductId: number; - Creator: { Id: number }; - PriceInRobux: number; - UserAssetId: number; -} - /** * @typedef */ @@ -215,14 +212,6 @@ type PriceRange = { low: number; } -/** - * @typedef -*/ -type BuyAssetResponse = { - productId: number; - price: number; -} - /** * @typedef */ @@ -729,6 +718,18 @@ type OnUserTypingChatEvent = { } /// Game +/** + * @typedef + */ +type UserNotificationPayloadParameter = { stringValue: string } | { int64Value: number }; + +/** + * @typedef + */ +type UserNotificationPayloadParameters = { + [key: string]: UserNotificationPayloadParameter +} + /** * @typedef */ @@ -810,7 +811,7 @@ type PlaceInformation = { price: number; imageToken: string; } - + /** * @typedef */ @@ -921,7 +922,7 @@ type UniverseSettings = { universeAnimationType?: "Standard" | "PlayerChoice"; universeCollisionType?: "InnerBox" | "OuterBox"; universeJointPositioningType?: "Standard" | "ArtistIntent"; - + isArchived?: boolean; isFriendsOnly?: boolean; @@ -935,7 +936,7 @@ type UniverseSettings = { isForSale?: boolean; price?: number; - + universeAvatarMinScales?: AvatarScale; universeAvatarMaxScales?: AvatarScale; @@ -963,7 +964,7 @@ type UniverseSettings = { universeAnimationType?: "Standard" | "PlayerChoice"; universeCollisionType?: "InnerBox" | "OuterBox"; universeJointPositioningType?: "Standard" | "ArtistIntent"; - + isArchived?: boolean; isFriendsOnly?: boolean; @@ -977,7 +978,7 @@ type UniverseSettings = { isForSale?: boolean; price?: number; - + universeAvatarMinScales?: AvatarScale; universeAvatarMaxScales?: AvatarScale; @@ -1025,6 +1026,7 @@ type Role = { memberCount?: number; rank: number; id: number; + color?: number; } /** @@ -1119,7 +1121,23 @@ type Group = { memberCount: number; isBuildersClubOnly: boolean; publicEntryAllowed: boolean; - isLocked: boolean; + hasVerifiedBadge: boolean; + hasSocialModules: boolean; +} + +/** + * @typedef +*/ +type GroupMultigetPartial = { + id: number; + name: string; + description: string; + owner: { + id: number; + type: string; + }; + created: Date; + hasVerifiedBadge: boolean; } /** @@ -1160,17 +1178,28 @@ type GroupAssetInfo = { /** * @typedef */ -type IGroupPartial = { - Name: string; - Id: number; - EmblemUrl: string; - MemberCount: number; - Rank: number; - Role: string; - RoleId: number; - IsPrimary: boolean; +type GroupMemberInfo = { + group: { + id: number; + name: string; + memberCount: number; + hasVerifiedBadge: boolean; + }; + role: { + id: number; + name: string; + rank: number; + } } + /** + * @typedef + */ + type PrimaryGroup = { + group: Group; + role: Role; + } + /** * @typedef */ @@ -1201,6 +1230,15 @@ type GroupShout = { updated: Date; } +/** + * @typedef +*/ +type PayoutAllowedList = { + usersGroupPayoutEligibility: { + [k: string]: string; + } +} + /** * @typedef */ @@ -1343,6 +1381,17 @@ type WallPostPage = { data: Array; } +/** + * @typedef +*/ +type GroupBan = { + user: UserEntry; + actingUser: { + user: UserEntry; + } + created: Date; +} + /// Party /** @@ -1504,6 +1553,7 @@ type PrivateMessagesPage = { * @typedef */ type UserEntry = { + hasVerifiedBadge: boolean; userId: number; name: string; displayName: string; @@ -1895,7 +1945,7 @@ type GetLatestResponse = { /** * @typedef */ -type Datastore = { +type Datastore = { name: string; createdTime: Date; } @@ -1903,7 +1953,7 @@ type Datastore = { /** * @typedef */ -type DatastoresResult = { +type DatastoresResult = { datastores: Datastore[]; nextPageCursor?: string; } @@ -1911,7 +1961,7 @@ type DatastoresResult = { /** * @typedef */ -type EntryKey = { +type EntryKey = { scope: string; key: string; } diff --git a/yarn.lock b/yarn.lock index 55ddcb0df..bb385c841 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10,17 +10,17 @@ "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.24" -"@auto-it/bot-list@11.3.0": - version "11.3.0" - resolved "https://registry.npmjs.org/@auto-it/bot-list/-/bot-list-11.3.0.tgz" - integrity sha512-+izoqAyOSiDVt3WcjVkSvLBV9c82VXLSf3oSWWcCeoxW/YDQ2AoInQ3M3EEyuBP+Yw9KQwGTTYHqpR7ZFkZpDQ== +"@auto-it/bot-list@11.3.6": + version "11.3.6" + resolved "https://registry.npmjs.org/@auto-it/bot-list/-/bot-list-11.3.6.tgz" + integrity sha512-BtFOhGv+V47TAYr77uiFz0l807g655Wcui/1KOJpqUYvF07MjG3+D8Ob4sMl8ewDQfgtAMTJKJF3S7AUdKPQng== "@auto-it/conventional-commits@^11.2.0": - version "11.3.0" - resolved "https://registry.npmjs.org/@auto-it/conventional-commits/-/conventional-commits-11.3.0.tgz" - integrity sha512-+1j2Yz8SoyxV+ioeivT8GIYLSlegfvoV36OfI4cphwGB35RyuDAG58340ymhW0v7I3QWHCKSLGTagyJTwcpqoA== + version "11.3.6" + resolved "https://registry.npmjs.org/@auto-it/conventional-commits/-/conventional-commits-11.3.6.tgz" + integrity sha512-da3krzspv7QdZRHrpaX9bjCq6C+0U/TE38mRHeKA+iEqwlDQvZTu+UKXl3Eaayidwmm+efcsi2s1UszG9D+0RA== dependencies: - "@auto-it/core" "11.3.0" + "@auto-it/core" "11.3.6" array.prototype.flatmap "^1.2.2" conventional-changelog-core "^4.2.0" conventional-changelog-preset-loader "^2.3.4" @@ -30,12 +30,12 @@ io-ts "^2.1.2" tslib "2.1.0" -"@auto-it/core@11.3.0": - version "11.3.0" - resolved "https://registry.npmjs.org/@auto-it/core/-/core-11.3.0.tgz" - integrity sha512-3i7ooAhQJulVDG3gmdOioTXLhpFoS75Z/OsLV8ZkrEaEH/sfxlslqFx20VjWva7gMLl2iO8IjbRnlLhkXy5geg== +"@auto-it/core@11.3.6": + version "11.3.6" + resolved "https://registry.npmjs.org/@auto-it/core/-/core-11.3.6.tgz" + integrity sha512-OE7feN8pbpcSCiWaOHYah+oXsinhJ6OfDrsLyPywNSfEPjal4q18ss2iQX1zTmrFIEjDSmptdjqlmwx+dm/8wQ== dependencies: - "@auto-it/bot-list" "11.3.0" + "@auto-it/bot-list" "11.3.6" "@endemolshinegroup/cosmiconfig-typescript-loader" "^3.0.2" "@octokit/core" "^3.5.1" "@octokit/plugin-enterprise-compatibility" "1.3.0" @@ -76,18 +76,18 @@ typescript-memoize "^1.0.0-alpha.3" url-join "^4.0.0" -"@auto-it/npm@11.3.0": - version "11.3.0" - resolved "https://registry.npmjs.org/@auto-it/npm/-/npm-11.3.0.tgz" - integrity sha512-II7u1trzi2hSd1Vww635DmvHqHlgtVPqr4VPJlq1M7zqPwi9+FcaMW5J/DSqlwJgWRWviWqepIhasUQhj69p0A== +"@auto-it/npm@11.3.6": + version "11.3.6" + resolved "https://registry.npmjs.org/@auto-it/npm/-/npm-11.3.6.tgz" + integrity sha512-yKYvlBcIRIOlFLJFpAq2ipdGihqyxAf5KZ9YeDxF/xN54XUV5A5kQqohSpAckxpWKBwxPIKODdLyY5Y0Tm0qfQ== dependencies: - "@auto-it/core" "11.3.0" - "@auto-it/package-json-utils" "11.3.0" + "@auto-it/core" "11.3.6" + "@auto-it/package-json-utils" "11.3.6" await-to-js "^3.0.0" endent "^2.1.0" env-ci "^5.0.1" fp-ts "^2.5.3" - get-monorepo-packages "^1.1.0" + get-monorepo-packages "^1.3.0" io-ts "^2.1.2" registry-url "^5.1.0" semver "^7.0.0" @@ -96,32 +96,32 @@ url-join "^4.0.0" user-home "^2.0.0" -"@auto-it/package-json-utils@11.3.0": - version "11.3.0" - resolved "https://registry.npmjs.org/@auto-it/package-json-utils/-/package-json-utils-11.3.0.tgz" - integrity sha512-wZQLfxYCzqNTlqgYhgm1mZaasA35tuOhGl0npWMZlq0HJ4rbNvUYnjb8bXlyfm/dxTYtYp70IhoV5kv1NmPX8Q== +"@auto-it/package-json-utils@11.3.6": + version "11.3.6" + resolved "https://registry.npmjs.org/@auto-it/package-json-utils/-/package-json-utils-11.3.6.tgz" + integrity sha512-j1GT9alk4kJoyyuAxqqHD7okHQjJuJXeAMTMRt4ZpjDjElPuPbxvzjM+QZNuxaMTyjxRoT2YbFyx0uIt7pqXlQ== dependencies: parse-author "^2.0.0" parse-github-url "1.0.2" -"@auto-it/released@11.3.0": - version "11.3.0" - resolved "https://registry.npmjs.org/@auto-it/released/-/released-11.3.0.tgz" - integrity sha512-8Aw8WGuTi3giKU9+KEutebLhhX+4eNVa7SmVLaRIFECUxI/+PS20yMbWsYjsyk5qju1MdpEQGPOW/4U5OZ6Bdw== +"@auto-it/released@11.3.6": + version "11.3.6" + resolved "https://registry.npmjs.org/@auto-it/released/-/released-11.3.6.tgz" + integrity sha512-mhe1QjEylUjONE24LUij3A0BCXvadABhbyPS+Jxq6hFS5Rh/gkOmxSuCa1HpO6DSsVdM0gOSF8ZYhUJ/9vHT8A== dependencies: - "@auto-it/bot-list" "11.3.0" - "@auto-it/core" "11.3.0" + "@auto-it/bot-list" "11.3.6" + "@auto-it/core" "11.3.6" deepmerge "^4.0.0" fp-ts "^2.5.3" io-ts "^2.1.2" tslib "2.1.0" -"@auto-it/version-file@11.3.0": - version "11.3.0" - resolved "https://registry.npmjs.org/@auto-it/version-file/-/version-file-11.3.0.tgz" - integrity sha512-+ax5/oXKLc5moXrSJuGm3eC10YFapWFwS5MEVwdspPM2YJn1ImuhagXOq5FJ1XK8aeHILZI+2iA+YB5wI1bcLA== +"@auto-it/version-file@11.3.6": + version "11.3.6" + resolved "https://registry.npmjs.org/@auto-it/version-file/-/version-file-11.3.6.tgz" + integrity sha512-dtf2T02ryIdX1GWQ9jeLW7EQj1IOBNFQX4BGS2uAddjszsd65hYNoRFMzQ+T/tr7j5Fn9RDaxXLamwYfaSPn9Q== dependencies: - "@auto-it/core" "11.3.0" + "@auto-it/core" "11.3.6" fp-ts "^2.5.3" io-ts "^2.1.2" semver "^7.0.0" @@ -141,7 +141,7 @@ resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.27.1.tgz" integrity sha512-Q+E+rd/yBzNQhXkG+zQnF58e4zoZfBedaxwzPmicKsiK3nt8iJYrSrDbjwFFDGC4f+rPafqRaPH6TsDoSvMf7A== -"@babel/core@^7.0.0", "@babel/core@^7.0.0-0", "@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.23.9", "@babel/core@^7.7.5", "@babel/core@^7.8.0": +"@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.23.9", "@babel/core@^7.7.5": version "7.27.1" resolved "https://registry.npmjs.org/@babel/core/-/core-7.27.1.tgz" integrity sha512-IaaGWsQqfsQWVLqMn9OB92MNN7zukfVA4s7KKAI0KfrrDsZ0yhi5uV4baBuLuN7n3vsZpwP8asPPcVwApxvjBQ== @@ -700,14 +700,6 @@ resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz" integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== -"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": - version "0.3.25" - resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz" - integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== - dependencies: - "@jridgewell/resolve-uri" "^3.1.0" - "@jridgewell/sourcemap-codec" "^1.4.14" - "@jridgewell/trace-mapping@0.3.9": version "0.3.9" resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz" @@ -716,6 +708,14 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": + version "0.3.25" + resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz" + integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + "@jsdoc/salty@^0.2.1": version "0.2.9" resolved "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.9.tgz" @@ -742,7 +742,7 @@ "@nodelib/fs.stat" "2.0.5" run-parallel "^1.1.9" -"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5": +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": version "2.0.5" resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== @@ -762,7 +762,7 @@ dependencies: "@octokit/types" "^6.0.3" -"@octokit/core@^3.5.0", "@octokit/core@^3.5.1", "@octokit/core@>=2", "@octokit/core@>=3": +"@octokit/core@^3.5.1": version "3.6.0" resolved "https://registry.npmjs.org/@octokit/core/-/core-3.6.0.tgz" integrity sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q== @@ -880,32 +880,6 @@ dependencies: "@octokit/openapi-types" "^12.11.0" -"@postman/form-data@~3.1.1": - version "3.1.1" - resolved "https://registry.npmjs.org/@postman/form-data/-/form-data-3.1.1.tgz" - integrity sha512-vjh8Q2a8S6UCm/KKs31XFJqEEgmbjBmpPNVV2eVav6905wyFAwaUOBGA1NPBI4ERH9MMZc6w0umFgM6WbEPMdg== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.8" - mime-types "^2.1.12" - -"@postman/tough-cookie@~4.1.3-postman.1": - version "4.1.3-postman.1" - resolved "https://registry.npmjs.org/@postman/tough-cookie/-/tough-cookie-4.1.3-postman.1.tgz" - integrity sha512-txpgUqZOnWYnUHZpHjkfb0IwVH4qJmyq77pPnJLlfhMtdCLMFTEeQHlzQiK906aaNCe4NEB5fGJHo9uzGbFMeA== - dependencies: - psl "^1.1.33" - punycode "^2.1.1" - universalify "^0.2.0" - url-parse "^1.5.3" - -"@postman/tunnel-agent@^0.6.4": - version "0.6.4" - resolved "https://registry.npmjs.org/@postman/tunnel-agent/-/tunnel-agent-0.6.4.tgz" - integrity sha512-CJJlq8V7rNKhAw4sBfjixKpJW00SHqebqNUQKxMoepgeWZIbdPcD+rguRcivGhS4N12PymDcKgUgSD4rVC+RjQ== - dependencies: - safe-buffer "^5.0.1" - "@rtsao/scc@^1.1.0": version "1.1.0" resolved "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz" @@ -950,6 +924,11 @@ resolved "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz" integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== +"@types/babel-types@*", "@types/babel-types@^7.0.0": + version "7.0.16" + resolved "https://registry.npmjs.org/@types/babel-types/-/babel-types-7.0.16.tgz" + integrity sha512-5QXs9GBFTNTmilLlWBhnsprqpjfrotyrnzUdwDrywEL/DA4LuCWQT300BTOXA3Y9ngT9F2uvmCoIxI6z8DlJEA== + "@types/babel__core@^7.1.14": version "7.20.5" resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz" @@ -983,11 +962,6 @@ dependencies: "@babel/types" "^7.20.7" -"@types/babel-types@*", "@types/babel-types@^7.0.0": - version "7.0.16" - resolved "https://registry.npmjs.org/@types/babel-types/-/babel-types-7.0.16.tgz" - integrity sha512-5QXs9GBFTNTmilLlWBhnsprqpjfrotyrnzUdwDrywEL/DA4LuCWQT300BTOXA3Y9ngT9F2uvmCoIxI6z8DlJEA== - "@types/babylon@^6.16.2": version "6.16.9" resolved "https://registry.npmjs.org/@types/babylon/-/babylon-6.16.9.tgz" @@ -1041,7 +1015,7 @@ resolved "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz" integrity sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q== -"@types/markdown-it@*", "@types/markdown-it@^14.1.1": +"@types/markdown-it@^14.1.1": version "14.1.2" resolved "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz" integrity sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog== @@ -1098,6 +1072,14 @@ resolved "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz" integrity sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g== +JSONStream@^1.0.4, JSONStream@^1.3.1: + version "1.3.5" + resolved "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz" + integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ== + dependencies: + jsonparse "^1.2.0" + through ">=2.2.7 <3" + abort-controller@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz" @@ -1134,21 +1116,16 @@ acorn@^3.1.0: resolved "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz" integrity sha512-OLUyIIZ7mF5oaAUT1w0TFqQS81q3saT46x8t7ukpPjMNk+nbs4ZHhs7ToV8EWnLYLepjETXd4XaCE4uxkMeqUw== -acorn@^4.0.4: +acorn@^4.0.4, acorn@~4.0.2: version "4.0.13" resolved "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz" integrity sha512-fu2ygVGuMmlzG8ZeRJ0bvR41nsAkxxhbyk8bZ1SS521Z7vmgJFTQQlfz/Mp/nJexGBz+v8sC9bM6+lNgskt4Ug== -"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^8.11.0, acorn@^8.4.1, acorn@^8.9.0: +acorn@^8.11.0, acorn@^8.4.1, acorn@^8.9.0: version "8.14.1" resolved "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz" integrity sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg== -acorn@~4.0.2: - version "4.0.13" - resolved "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz" - integrity sha512-fu2ygVGuMmlzG8ZeRJ0bvR41nsAkxxhbyk8bZ1SS521Z7vmgJFTQQlfz/Mp/nJexGBz+v8sC9bM6+lNgskt4Ug== - add-stream@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/add-stream/-/add-stream-1.0.0.tgz" @@ -1161,10 +1138,10 @@ agent-base@6: dependencies: debug "4" -ajv@^6.12.4: - version "6.12.6" - resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" - integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== +ajv@^6.12.3, ajv@^6.12.4: + version "6.14.0" + resolved "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz" + integrity sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw== dependencies: fast-deep-equal "^3.1.1" fast-json-stable-stringify "^2.0.0" @@ -1204,14 +1181,7 @@ ansi-styles@^3.2.1: dependencies: color-convert "^1.9.0" -ansi-styles@^4.0.0: - version "4.3.0" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - -ansi-styles@^4.1.0: +ansi-styles@^4.0.0, ansi-styles@^4.1.0: version "4.3.0" resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== @@ -1253,12 +1223,7 @@ array-back@^3.0.1, array-back@^3.1.0: resolved "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz" integrity sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q== -array-back@^4.0.1: - version "4.0.2" - resolved "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz" - integrity sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg== - -array-back@^4.0.2: +array-back@^4.0.1, array-back@^4.0.2: version "4.0.2" resolved "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz" integrity sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg== @@ -1381,12 +1346,12 @@ asn1@~0.2.3: dependencies: safer-buffer "~2.1.0" -assert-plus@^1.0.0, assert-plus@1.0.0: +assert-plus@1.0.0, assert-plus@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz" integrity sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw== -ast-types@^0.12.2: +ast-types@0.12.4, ast-types@^0.12.2: version "0.12.4" resolved "https://registry.npmjs.org/ast-types/-/ast-types-0.12.4.tgz" integrity sha512-ky/YVYCbtVAS8TdMIaTiPFHwEpRB5z1hctepJplTr3UW5q8TDrpIMCILyk8pmLxGtn2KCtC/lSn7zOsaI7nzDw== @@ -1398,11 +1363,6 @@ ast-types@^0.14.2: dependencies: tslib "^2.0.1" -ast-types@0.12.4: - version "0.12.4" - resolved "https://registry.npmjs.org/ast-types/-/ast-types-0.12.4.tgz" - integrity sha512-ky/YVYCbtVAS8TdMIaTiPFHwEpRB5z1hctepJplTr3UW5q8TDrpIMCILyk8pmLxGtn2KCtC/lSn7zOsaI7nzDw== - async-function@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz" @@ -1419,14 +1379,14 @@ author-regex@^1.0.0: integrity sha512-KbWgR8wOYRAPekEmMXrYYdc7BRyhn2Ftk7KWfMUnQ43hFdojWEFRxhhRUm3/OFEdPa1r0KAvTTg9YQK57xTe0g== auto@^11.2.0: - version "11.3.0" - resolved "https://registry.npmjs.org/auto/-/auto-11.3.0.tgz" - integrity sha512-7FWjxrfsVKaToAcjxsijdpL8prbffZk5ovPCTVDk6c0Yq3pNKd2AMm5fkPR5lDbnYNeoU7lbm+0wVtJSoTQhpw== - dependencies: - "@auto-it/core" "11.3.0" - "@auto-it/npm" "11.3.0" - "@auto-it/released" "11.3.0" - "@auto-it/version-file" "11.3.0" + version "11.3.6" + resolved "https://registry.npmjs.org/auto/-/auto-11.3.6.tgz" + integrity sha512-Db13X4WVNPzPtWKSoiOzhfW2g3zNUTDR1X3wkQPdIW21xtajwm5Taqg3BXWR2u7/45W0bU+6YykVgioNRwrwIw== + dependencies: + "@auto-it/core" "11.3.6" + "@auto-it/npm" "11.3.6" + "@auto-it/released" "11.3.6" + "@auto-it/version-file" "11.3.6" await-to-js "^3.0.0" chalk "^4.0.0" command-line-application "^0.10.1" @@ -1453,7 +1413,7 @@ aws-sign2@~0.7.0: resolved "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz" integrity sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA== -aws4@^1.12.0: +aws4@^1.8.0: version "1.13.2" resolved "https://registry.npmjs.org/aws4/-/aws4-1.13.2.tgz" integrity sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw== @@ -1596,9 +1556,9 @@ bottleneck@^2.15.3: integrity sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw== brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + version "1.1.13" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz" + integrity sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w== dependencies: balanced-match "^1.0.0" concat-map "0.0.1" @@ -1615,7 +1575,7 @@ braces@^3.0.3: dependencies: fill-range "^7.1.1" -browserslist@^4.24.0, "browserslist@>= 4.21.0": +browserslist@^4.24.0: version "4.24.5" resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.24.5.tgz" integrity sha512-FDToo4Wo82hIdgc1CQ+NQD0hEhmpPjrZ3hiUgwgOG6IuTdlpr8jdjyG24P6cNP1yJpTLzS5OcGgSw0xmDU1/Tw== @@ -1742,25 +1702,7 @@ center-align@^0.1.1: align-text "^0.1.3" lazy-cache "^1.0.3" -chalk@^2.3.2: - version "2.4.2" - resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -chalk@^2.4.1: - version "2.4.2" - resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -chalk@^2.4.2: +chalk@^2.3.2, chalk@^2.4.1, chalk@^2.4.2: version "2.4.2" resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -1769,15 +1711,7 @@ chalk@^2.4.2: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@^4.0.0: - version "4.1.2" - resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -chalk@^4.1.0: +chalk@^4.0.0, chalk@^4.1.0: version "4.1.2" resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -1899,17 +1833,17 @@ color-convert@^2.0.1: dependencies: color-name "~1.1.4" -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - color-name@1.1.3: version "1.1.3" resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== -combined-stream@^1.0.8, combined-stream@~1.0.6: +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +combined-stream@^1.0.6, combined-stream@~1.0.6: version "1.0.8" resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz" integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== @@ -2023,8 +1957,8 @@ conventional-commits-parser@^3.1.0, conventional-commits-parser@^3.2.0: resolved "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.2.4.tgz" integrity sha512-nK7sAtfi+QXbxHCYfhpZsfRtaitZLIA6889kFIouLvz6repszQDgxBu7wf2WbU+Dco7sAnNCJYERCwt54WPC2Q== dependencies: - is-text-path "^1.0.1" JSONStream "^1.0.4" + is-text-path "^1.0.1" lodash "^4.17.15" meow "^8.0.0" split2 "^3.0.0" @@ -2040,12 +1974,12 @@ core-js@^2.4.0: resolved "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz" integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== -core-util-is@~1.0.0, core-util-is@1.0.2: +core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz" integrity sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ== -cosmiconfig@>=6, cosmiconfig@7.0.0: +cosmiconfig@7.0.0: version "7.0.0" resolved "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz" integrity sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA== @@ -2148,6 +2082,13 @@ de-indent@^1.0.2: resolved "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz" integrity sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg== +debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2: + version "4.4.0" + resolved "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz" + integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== + dependencies: + ms "^2.1.3" + debug@^3.2.7: version "3.2.7" resolved "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz" @@ -2155,13 +2096,6 @@ debug@^3.2.7: dependencies: ms "^2.1.1" -debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@4: - version "4.4.0" - resolved "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz" - integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== - dependencies: - ms "^2.1.3" - decamelize-keys@^1.1.0: version "1.1.1" resolved "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz" @@ -2244,9 +2178,9 @@ diff-sequences@^29.6.3: integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q== diff@^4.0.1: - version "4.0.2" - resolved "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz" - integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== + version "4.0.4" + resolved "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz" + integrity sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ== dir-glob@^2.0.0: version "2.2.2" @@ -2304,16 +2238,16 @@ domutils@^3.0.1, domutils@^3.1.0: domelementtype "^2.3.0" domhandler "^5.0.3" -dotenv@^8.0.0: - version "8.6.0" - resolved "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz" - integrity sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g== - dotenv@16.4.5: version "16.4.5" resolved "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz" integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg== +dotenv@^8.0.0: + version "8.6.0" + resolved "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz" + integrity sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g== + dunder-proto@^1.0.0, dunder-proto@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz" @@ -2371,17 +2305,7 @@ enquirer@^2.3.4: ansi-colors "^4.1.1" strip-ansi "^6.0.1" -entities@^4.2.0: - version "4.5.0" - resolved "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz" - integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== - -entities@^4.4.0: - version "4.5.0" - resolved "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz" - integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== - -entities@^4.5.0: +entities@^4.2.0, entities@^4.4.0, entities@^4.5.0: version "4.5.0" resolved "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz" integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== @@ -2588,7 +2512,7 @@ eslint-plugin-es@^4.1.0: eslint-utils "^2.0.0" regexpp "^3.0.0" -eslint-plugin-import@^2.25.2, eslint-plugin-import@^2.27.5: +eslint-plugin-import@^2.27.5: version "2.31.0" resolved "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz" integrity sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A== @@ -2613,7 +2537,7 @@ eslint-plugin-import@^2.25.2, eslint-plugin-import@^2.27.5: string.prototype.trimend "^1.0.8" tsconfig-paths "^3.15.0" -"eslint-plugin-n@^15.0.0 || ^16.0.0 ", eslint-plugin-n@^15.7.0: +eslint-plugin-n@^15.7.0: version "15.7.0" resolved "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-15.7.0.tgz" integrity sha512-jDex9s7D/Qial8AGVIHq4W7NswpUD5DPDL2RH8Lzd9EloWUuvUkHfv4FRLMipH5q2UtyurorBkPeNi1wVWNh3Q== @@ -2627,12 +2551,12 @@ eslint-plugin-import@^2.25.2, eslint-plugin-import@^2.27.5: resolve "^1.22.1" semver "^7.3.8" -eslint-plugin-promise@^6.0.0, eslint-plugin-promise@^6.1.1: +eslint-plugin-promise@^6.1.1: version "6.6.0" resolved "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.6.0.tgz" integrity sha512-57Zzfw8G6+Gq7axm2Pdo3gW/Rx3h9Yywgn61uE/3elTCOePEHVrn2i5CdfBwA1BLK0Q0WqctICIUSqXZW/VprQ== -eslint-plugin-react@^7.28.0, eslint-plugin-react@^7.36.1: +eslint-plugin-react@^7.36.1: version "7.37.5" resolved "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz" integrity sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA== @@ -2693,7 +2617,7 @@ eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz" integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== -"eslint@^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9", "eslint@^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7", "eslint@^6.0.0 || ^7.0.0 || >=8.0.0", "eslint@^7.0.0 || ^8.0.0 || ^9.0.0", eslint@^8.0.1, eslint@^8.41.0, eslint@^8.8.0, eslint@>=4.19.1, eslint@>=5, eslint@>=7.0.0: +eslint@^8.41.0: version "8.57.1" resolved "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz" integrity sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA== @@ -2830,7 +2754,7 @@ extend@~3.0.2: resolved "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz" integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== -extsprintf@^1.2.0, extsprintf@1.3.0: +extsprintf@1.3.0, extsprintf@^1.2.0: version "1.3.0" resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz" integrity sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g== @@ -2961,9 +2885,9 @@ flat-cache@^3.0.4: rimraf "^3.0.2" flatted@^3.2.9: - version "3.3.3" - resolved "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz" - integrity sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg== + version "3.4.2" + resolved "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz" + integrity sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA== for-each@^0.3.3, for-each@^0.3.5: version "0.3.5" @@ -2985,7 +2909,16 @@ forever-agent@~0.6.1: resolved "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz" integrity sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw== -fp-ts@^2.5.0, fp-ts@^2.5.3: +form-data@~2.3.2: + version "2.3.3" + resolved "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz" + integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" + +fp-ts@^2.5.3: version "2.16.10" resolved "https://registry.npmjs.org/fp-ts/-/fp-ts-2.16.10.tgz" integrity sha512-vuROzbNVfCmUkZSUbnWSltR1sbheyQbTzug7LB/46fEa1c0EucLeBaCEUE0gF3ZGUGBt9lVUiziGOhhj6K1ORA== @@ -3000,6 +2933,11 @@ fs.realpath@^1.0.0: resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== +fsevents@^2.3.2: + version "2.3.3" + resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + function-bind@^1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" @@ -3048,7 +2986,7 @@ get-intrinsic@^1.2.4, get-intrinsic@^1.2.5, get-intrinsic@^1.2.6, get-intrinsic@ hasown "^2.0.2" math-intrinsics "^1.1.0" -get-monorepo-packages@^1.1.0: +get-monorepo-packages@^1.3.0: version "1.3.0" resolved "https://registry.npmjs.org/get-monorepo-packages/-/get-monorepo-packages-1.3.0.tgz" integrity sha512-A/s881nNcKhoM7RgkvYFTOtGO+dy4EWbyRaatncPEhhlJAaZRlpfHwuT68p5GJenEt81nnjJOwGg0WKLkR5ZdQ== @@ -3221,9 +3159,9 @@ graphemer@^1.4.0: integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== handlebars@^4.7.7: - version "4.7.8" - resolved "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz" - integrity sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ== + version "4.7.9" + resolved "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz" + integrity sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ== dependencies: minimist "^1.2.5" neo-async "^2.6.2" @@ -3232,6 +3170,19 @@ handlebars@^4.7.7: optionalDependencies: uglify-js "^3.1.4" +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz" + integrity sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q== + +har-validator@~5.1.3: + version "5.1.5" + resolved "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz" + integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w== + dependencies: + ajv "^6.12.3" + har-schema "^2.0.0" + hard-rejection@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz" @@ -3322,14 +3273,14 @@ htmlparser2@^9.1.0: domutils "^3.1.0" entities "^4.5.0" -http-signature@~1.4.0: - version "1.4.0" - resolved "https://registry.npmjs.org/http-signature/-/http-signature-1.4.0.tgz" - integrity sha512-G5akfn7eKbpDN+8nPS/cb57YeA1jLTVxjpCj7tmm3QKPdyDy7T+qSC40e9ptydSWvkwjSXw1VbkpyEm39ukeAg== +http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz" + integrity sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ== dependencies: assert-plus "^1.0.0" - jsprim "^2.0.2" - sshpk "^1.18.0" + jsprim "^1.2.2" + sshpk "^1.7.0" https-proxy-agent@^5.0.0: version "5.0.1" @@ -3344,7 +3295,7 @@ human-signals@^2.1.0: resolved "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz" integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== -iconv-lite@^0.6.3, iconv-lite@0.6.3: +iconv-lite@0.6.3, iconv-lite@^0.6.3: version "0.6.3" resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz" integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== @@ -3356,12 +3307,7 @@ ignore@^3.3.5: resolved "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz" integrity sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug== -ignore@^5.1.1: - version "5.3.2" - resolved "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz" - integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== - -ignore@^5.2.0: +ignore@^5.1.1, ignore@^5.2.0: version "5.3.2" resolved "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz" integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== @@ -3414,7 +3360,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@^2.0.3, inherits@~2.0.3, inherits@2: +inherits@2, inherits@^2.0.3, inherits@~2.0.3: version "2.0.4" resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -3987,7 +3933,7 @@ jest-resolve-dependencies@^29.7.0: jest-regex-util "^29.6.3" jest-snapshot "^29.7.0" -jest-resolve@*, jest-resolve@^29.7.0: +jest-resolve@^29.7.0: version "29.7.0" resolved "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz" integrity sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA== @@ -4131,7 +4077,7 @@ jest-worker@^29.7.0: merge-stream "^2.0.0" supports-color "^8.0.0" -jest@^29.7.0, jest@>=27.2.5: +jest@^29.7.0: version "29.7.0" resolved "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz" integrity sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw== @@ -4152,17 +4098,17 @@ js-stringify@^1.0.1: integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== js-yaml@^3.13.1: - version "3.14.1" - resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz" - integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + version "3.14.2" + resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz" + integrity sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg== dependencies: argparse "^1.0.7" esprima "^4.0.0" js-yaml@^4.1.0: - version "4.1.0" - resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz" - integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + version "4.1.1" + resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz" + integrity sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA== dependencies: argparse "^2.0.1" @@ -4256,18 +4202,10 @@ jsonparse@^1.2.0: resolved "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz" integrity sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg== -JSONStream@^1.0.4, JSONStream@^1.3.1: - version "1.3.5" - resolved "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz" - integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ== - dependencies: - jsonparse "^1.2.0" - through ">=2.2.7 <3" - -jsprim@^2.0.2: - version "2.0.2" - resolved "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz" - integrity sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ== +jsprim@^1.2.2: + version "1.4.2" + resolved "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz" + integrity sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw== dependencies: assert-plus "1.0.0" extsprintf "1.3.0" @@ -4435,9 +4373,9 @@ lodash.merge@^4.6.2: integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== lodash@^4.17.15, lodash@^4.17.21, lodash@^4.17.4: - version "4.17.21" - resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + version "4.17.23" + resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz" + integrity sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w== log-symbols@^4.0.0: version "4.1.0" @@ -4452,7 +4390,7 @@ longest@^1.0.1: resolved "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz" integrity sha512-k+yt5n3l48JU4k8ftnKG6V7u32wyH2NfKzeMto9F/QRE0amxy/LayxwlvjjkZEIzqR+19IrtFO8p5kB9QaYUFg== -loose-envify@^1.1.0, loose-envify@^1.4.0: +loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== @@ -4515,10 +4453,10 @@ markdown-it-anchor@^8.6.7: resolved "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.7.tgz" integrity sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA== -markdown-it@*, markdown-it@^14.1.0: - version "14.1.0" - resolved "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz" - integrity sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg== +markdown-it@^14.1.0: + version "14.1.1" + resolved "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.1.tgz" + integrity sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA== dependencies: argparse "^2.0.1" entities "^4.4.0" @@ -4587,7 +4525,7 @@ mime-db@1.52.0: resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== -mime-types@^2.1.12, mime-types@^2.1.35: +mime-types@^2.1.12, mime-types@~2.1.19: version "2.1.35" resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== @@ -4605,9 +4543,9 @@ min-indent@^1.0.0: integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== minimatch@^3.0.2, minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: - version "3.1.2" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + version "3.1.5" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz" + integrity sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w== dependencies: brace-expansion "^1.1.7" @@ -4667,7 +4605,7 @@ node-dir@^0.1.10: dependencies: minimatch "^3.0.2" -node-fetch@^2.6.7, node-fetch@2.6.7: +node-fetch@2.6.7, node-fetch@^2.6.7: version "2.6.7" resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz" integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== @@ -4684,17 +4622,7 @@ node-releases@^2.0.19: resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz" integrity sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw== -normalize-package-data@^2.3.2: - version "2.5.0" - resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz" - integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== - dependencies: - hosted-git-info "^2.1.4" - resolve "^1.10.0" - semver "2 || 3 || 4 || 5" - validate-npm-package-license "^3.0.1" - -normalize-package-data@^2.5.0: +normalize-package-data@^2.3.2, normalize-package-data@^2.5.0: version "2.5.0" resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz" integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== @@ -4856,14 +4784,7 @@ p-limit@^1.1.0: dependencies: p-try "^1.0.0" -p-limit@^2.0.0: - version "2.3.0" - resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz" - integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== - dependencies: - p-try "^2.0.0" - -p-limit@^2.2.0: +p-limit@^2.0.0, p-limit@^2.2.0: version "2.3.0" resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz" integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== @@ -5016,15 +4937,20 @@ path-type@^4.0.0: resolved "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz" + integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow== + picocolors@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz" integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== picomatch@^2.0.4, picomatch@^2.2.3, picomatch@^2.3.1: - version "2.3.1" - resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" - integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + version "2.3.2" + resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz" + integrity sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA== pify@^2.3.0: version "2.3.0" @@ -5075,29 +5001,37 @@ possible-typed-array-names@^1.0.0: integrity sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg== postman-request@^2.88.1-postman.34: - version "2.88.1-postman.42" - resolved "https://registry.npmjs.org/postman-request/-/postman-request-2.88.1-postman.42.tgz" - integrity sha512-lepCE8QU0izagxxA31O/MHj8IUguwLlpqeVK7A8vHK401FPvN/PTIzWHm29c/L3j3kTUE7dhZbq8vvbyQ7S2Bw== + version "2.88.1-postman.8-beta.1" + resolved "https://registry.npmjs.org/postman-request/-/postman-request-2.88.1-postman.8-beta.1.tgz" + integrity sha512-deC5UZlM1VimFhQdPN1NcbQMvLEtpUCTHZHMXWNv6vyNW7H98O3MJGTlk2xTlzB9BOpU2MCCgXNOPeNP2SU6iA== dependencies: - "@postman/form-data" "~3.1.1" - "@postman/tough-cookie" "~4.1.3-postman.1" - "@postman/tunnel-agent" "^0.6.4" aws-sign2 "~0.7.0" - aws4 "^1.12.0" + aws4 "^1.8.0" caseless "~0.12.0" combined-stream "~1.0.6" extend "~3.0.2" forever-agent "~0.6.1" - http-signature "~1.4.0" + form-data "~2.3.2" + har-validator "~5.1.3" + http-signature "~1.2.0" is-typedarray "~1.0.0" isstream "~0.1.2" json-stringify-safe "~5.0.1" - mime-types "^2.1.35" + mime-types "~2.1.19" oauth-sign "~0.9.0" - qs "~6.5.3" + performance-now "^2.1.0" + postman-url-encoder "1.0.1" + qs "~6.5.2" safe-buffer "^5.1.2" stream-length "^1.0.2" - uuid "^8.3.2" + tough-cookie "~2.5.0" + tunnel-agent "^0.6.0" + uuid "^3.3.2" + +postman-url-encoder@1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/postman-url-encoder/-/postman-url-encoder-1.0.1.tgz" + integrity sha512-ned2lpcMpEG+n3ce2LEoGqUJeZsKNRYkViqKfJXe7rUQhLxjrrcp/lQ8TLycvX74lQZm52gkNVVgczmcJBOJ8w== prelude-ls@^1.2.1: version "1.2.1" @@ -5145,7 +5079,7 @@ prompts@^2.0.1: kleur "^3.0.3" sisteransi "^1.0.5" -prop-types@^15.5.9, prop-types@^15.7.2, prop-types@^15.8.1: +prop-types@^15.7.2, prop-types@^15.8.1: version "15.8.1" resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz" integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== @@ -5159,7 +5093,7 @@ pseudomap@^1.0.2: resolved "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz" integrity sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ== -psl@^1.1.33: +psl@^1.1.28, psl@^1.1.33: version "1.15.0" resolved "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz" integrity sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w== @@ -5291,10 +5225,10 @@ q@^1.5.1: resolved "https://registry.npmjs.org/q/-/q-1.5.1.tgz" integrity sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw== -qs@~6.5.3: - version "6.5.3" - resolved "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz" - integrity sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA== +qs@~6.5.2: + version "6.5.5" + resolved "https://registry.npmjs.org/qs/-/qs-6.5.5.tgz" + integrity sha512-mzR4sElr1bfCaPJe7m8ilJ6ZXdDaGoObcYR0ZHSsktM/Lt21MVHj5De30GQH2eiZ1qGRTO7LCAzQsUeXTNexWQ== querystringify@^2.1.1: version "2.2.0" @@ -5348,15 +5282,6 @@ react-docgen@^5.4.0: node-dir "^0.1.10" strip-indent "^3.0.0" -"react-dom@^0.13.0 || ^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0", react-dom@^17.0.2, "react-dom@>= 16.3": - version "17.0.2" - resolved "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz" - integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - scheduler "^0.20.2" - react-frame-component@^5.2.1: version "5.2.7" resolved "https://registry.npmjs.org/react-frame-component/-/react-frame-component-5.2.7.tgz" @@ -5372,14 +5297,6 @@ react-is@^18.0.0: resolved "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz" integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== -"react@^0.13.0 || ^0.14.0 || ^15.0.1 || ^16.0.0 || ^17.0.0", react@^17.0.2, "react@>= 16.3", react@17.0.2: - version "17.0.2" - resolved "https://registry.npmjs.org/react/-/react-17.0.2.tgz" - integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - read-pkg-up@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz" @@ -5416,7 +5333,7 @@ read-pkg@^5.2.0: parse-json "^5.0.0" type-fest "^0.6.0" -readable-stream@^3.0.0, readable-stream@3: +readable-stream@3, readable-stream@^3.0.0: version "3.6.2" resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz" integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== @@ -5651,30 +5568,17 @@ safe-regex-test@^1.1.0: es-errors "^1.3.0" is-regex "^1.2.1" -safer-buffer@^2.0.2, safer-buffer@^2.1.0, "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@~2.1.0: +"safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: version "2.1.2" resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -scheduler@^0.20.2: - version "0.20.2" - resolved "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz" - integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - -semver@^6.0.0: - version "6.3.1" - resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz" - integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== - -semver@^6.3.0: - version "6.3.1" - resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz" - integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== +"semver@2 || 3 || 4 || 5": + version "5.7.2" + resolved "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz" + integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== -semver@^6.3.1: +semver@^6.0.0, semver@^6.3.0, semver@^6.3.1: version "6.3.1" resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== @@ -5684,11 +5588,6 @@ semver@^7.0.0, semver@^7.3.4, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4: resolved "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz" integrity sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA== -"semver@2 || 3 || 4 || 5": - version "5.7.2" - resolved "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz" - integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== - set-cookie-parser@^2.4.8: version "2.7.1" resolved "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz" @@ -5806,14 +5705,6 @@ slash@^3.0.0: resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== -source-map-support@^0.5.17: - version "0.5.21" - resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz" - integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - source-map-support@0.5.13: version "0.5.13" resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz" @@ -5822,6 +5713,14 @@ source-map-support@0.5.13: buffer-from "^1.0.0" source-map "^0.6.0" +source-map-support@^0.5.17: + version "0.5.21" + resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: version "0.6.1" resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" @@ -5858,13 +5757,6 @@ spdx-license-ids@^3.0.0: resolved "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.21.tgz" integrity sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg== -split@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/split/-/split-1.0.1.tgz" - integrity sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg== - dependencies: - through "2" - split2@^3.0.0: version "3.2.2" resolved "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz" @@ -5872,12 +5764,19 @@ split2@^3.0.0: dependencies: readable-stream "^3.0.0" +split@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/split/-/split-1.0.1.tgz" + integrity sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg== + dependencies: + through "2" + sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz" integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== -sshpk@^1.18.0: +sshpk@^1.7.0: version "1.18.0" resolved "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz" integrity sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ== @@ -5931,20 +5830,6 @@ stream-length@^1.0.2: dependencies: bluebird "^2.6.2" -string_decoder@^1.1.1: - version "1.3.0" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz" - integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== - dependencies: - safe-buffer "~5.2.0" - -string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== - dependencies: - safe-buffer "~5.1.0" - string-length@^4.0.1: version "4.0.2" resolved "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz" @@ -6021,6 +5906,20 @@ string.prototype.trimstart@^1.0.8: define-properties "^1.2.1" es-object-atoms "^1.0.0" +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" @@ -6105,9 +6004,9 @@ table-layout@^1.0.2: wordwrapjs "^4.0.0" tapable@^2.2.0: - version "2.2.1" - resolved "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz" - integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== + version "2.3.2" + resolved "https://registry.npmjs.org/tapable/-/tapable-2.3.2.tgz" + integrity sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA== terminal-link@^2.1.1: version "2.1.1" @@ -6136,11 +6035,6 @@ text-table@^0.2.0: resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== -"through@>=2.2.7 <3", through@2: - version "2.3.8" - resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz" - integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== - through2@^2.0.0: version "2.0.5" resolved "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz" @@ -6156,6 +6050,11 @@ through2@^4.0.0: dependencies: readable-stream "3" +through@2, "through@>=2.2.7 <3": + version "2.3.8" + resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz" + integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== + tinycolor2@^1.4.1: version "1.6.0" resolved "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz" @@ -6193,6 +6092,14 @@ tough-cookie@^4.0.0: universalify "^0.2.0" url-parse "^1.5.3" +tough-cookie@~2.5.0: + version "2.5.0" + resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz" + integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== + dependencies: + psl "^1.1.28" + punycode "^2.1.1" + tr46@~0.0.3: version "0.0.3" resolved "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz" @@ -6208,7 +6115,7 @@ ts-map@^1.0.3: resolved "https://registry.npmjs.org/ts-map/-/ts-map-1.0.3.tgz" integrity sha512-vDWbsl26LIcPGmDpoVzjEP6+hvHZkBkLW7JpvwbCv/5IYPJlsbzCVXY3wsCeAxAUeTclNOUZxnLdGh3VBD/J6w== -ts-node@^10.9.1, ts-node@>=9.0.0: +ts-node@^10.9.1: version "10.9.2" resolved "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz" integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== @@ -6249,7 +6156,12 @@ tsconfig-paths@^3.15.0: minimist "^1.2.6" strip-bom "^3.0.0" -tslib@^2, tslib@^2.0.1, tslib@2.1.0: +tslib@1.10.0: + version "1.10.0" + resolved "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz" + integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== + +tslib@2.1.0, tslib@^2, tslib@^2.0.1: version "2.1.0" resolved "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz" integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A== @@ -6259,10 +6171,12 @@ tslib@^2.5.0: resolved "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz" integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== -tslib@1.10.0: - version "1.10.0" - resolved "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz" - integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz" + integrity sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w== + dependencies: + safe-buffer "^5.0.1" tweetnacl@^0.14.3, tweetnacl@~0.14.0: version "0.14.5" @@ -6371,11 +6285,6 @@ typescript@^4.5.4: resolved "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz" integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== -typescript@>=2.7: - version "5.8.3" - resolved "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz" - integrity sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ== - typical@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz" @@ -6422,9 +6331,9 @@ unbox-primitive@^1.1.0: which-boxed-primitive "^1.1.1" underscore@^1.13.2, underscore@~1.13.2: - version "1.13.7" - resolved "https://registry.npmjs.org/underscore/-/underscore-1.13.7.tgz" - integrity sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g== + version "1.13.8" + resolved "https://registry.npmjs.org/underscore/-/underscore-1.13.8.tgz" + integrity sha512-DXtD3ZtEQzc7M8m4cXotyHR+FAS18C64asBYY5vqZexfYryNNnDc02W4hKg3rdQuqOYas1jkseX0+nZXjTXnvQ== undici-types@~6.21.0: version "6.21.0" @@ -6432,9 +6341,9 @@ undici-types@~6.21.0: integrity sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ== undici@^6.19.5: - version "6.21.2" - resolved "https://registry.npmjs.org/undici/-/undici-6.21.2.tgz" - integrity sha512-uROZWze0R0itiAKVPsYhFov9LxrPMHLMEQFszeI2gCN6bnIIZ8twzBCJcN2LJrBBLfrP0t1FW0g+JmKVl8Vk1g== + version "6.24.1" + resolved "https://registry.npmjs.org/undici/-/undici-6.24.1.tgz" + integrity sha512-sC+b0tB1whOCzbtlx20fx3WgCXwkW627p4EA9uM+/tNNPkSS+eSEld6pAs9nDv7WbY1UUljBMYPtu9BCOrCWKA== universal-user-agent@^6.0.0: version "6.0.1" @@ -6486,10 +6395,10 @@ util-deprecate@^1.0.1, util-deprecate@~1.0.1: resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== -uuid@^8.3.2: - version "8.3.2" - resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz" - integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== +uuid@^3.3.2: + version "3.4.0" + resolved "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz" + integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== v8-compile-cache-lib@^3.0.1: version "3.0.1" @@ -6673,16 +6582,16 @@ word-wrap@^1.2.5: resolved "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz" integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== -wordwrap@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz" - integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== - wordwrap@0.0.2: version "0.0.2" resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz" integrity sha512-xSBsCeh+g+dinoBv3GAOWM4LcVVO68wLXRanibtBSdUvkGWQRGeE9P7IwU9EmDDi4jA6L44lz15CGMwdw9N5+Q== +wordwrap@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz" + integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== + wordwrapjs@^4.0.0: version "4.0.1" resolved "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-4.0.1.tgz" @@ -6754,9 +6663,9 @@ yallist@^4.0.0: integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== yaml@^1.10.0: - version "1.10.2" - resolved "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz" - integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== + version "1.10.3" + resolved "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz" + integrity sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA== yargs-parser@^20.2.2, yargs-parser@^20.2.3, yargs-parser@^20.2.9: version "20.2.9"