diff options
author | dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> | 2021-09-06 21:06:22 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-09-06 21:06:22 +0000 |
commit | 487f208565894f332ca58c13e1b208c3beb9c8c6 (patch) | |
tree | b3209e94cc63658b5430bc1949b80140cc27efe4 /build | |
parent | 4f03cb71b30978b277ff292dbddeba182117a7cb (diff) | |
download | skyblock-api-487f208565894f332ca58c13e1b208c3beb9c8c6.tar.gz skyblock-api-487f208565894f332ca58c13e1b208c3beb9c8c6.tar.bz2 skyblock-api-487f208565894f332ca58c13e1b208c3beb9c8c6.zip |
Bump node-fetch from 2.6.1 to 3.0.0 (#116)
* Bump node-fetch from 2.6.1 to 3.0.0
Bumps [node-fetch](https://github.com/node-fetch/node-fetch) from 2.6.1 to 3.0.0.
- [Release notes](https://github.com/node-fetch/node-fetch/releases)
- [Changelog](https://github.com/node-fetch/node-fetch/blob/main/docs/CHANGELOG.md)
- [Commits](https://github.com/node-fetch/node-fetch/compare/v2.6.1...v3.0.0)
---
updated-dependencies:
- dependency-name: node-fetch
dependency-type: direct:production
update-type: version-update:semver-major
...
Signed-off-by: dependabot[bot] <support@github.com>
* fix issues with node fetch 3.0
* change module to esnext instead of commonjs
* fix imports and tests
* fix package-lock.json
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: mat <github@matdoes.dev>
Co-authored-by: mat <27899617+mat-1@users.noreply.github.com>
Diffstat (limited to 'build')
26 files changed, 443 insertions, 818 deletions
diff --git a/build/cleaners/player.js b/build/cleaners/player.js index 42c76b8..214be1f 100644 --- a/build/cleaners/player.js +++ b/build/cleaners/player.js @@ -1,22 +1,17 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.cleanPlayerResponse = void 0; -const profiles_1 = require("./skyblock/profiles"); -const socialmedia_1 = require("./socialmedia"); -const rank_1 = require("./rank"); -const util_1 = require("../util"); -async function cleanPlayerResponse(data) { - var _a, _b; +import { cleanPlayerSkyblockProfiles } from './skyblock/profiles.js'; +import { cleanSocialMedia } from './socialmedia.js'; +import { cleanRank } from './rank.js'; +import { undashUuid } from '../util.js'; +export async function cleanPlayerResponse(data) { // Cleans up a 'player' api response if (!data) return null; // bruh return { - uuid: util_1.undashUuid(data.uuid), + uuid: undashUuid(data.uuid), username: data.displayname, - rank: rank_1.cleanRank(data), - socials: socialmedia_1.cleanSocialMedia(data), + rank: cleanRank(data), + socials: cleanSocialMedia(data), // first_join: data.firstLogin / 1000, - profiles: profiles_1.cleanPlayerSkyblockProfiles((_b = (_a = data.stats) === null || _a === void 0 ? void 0 : _a.SkyBlock) === null || _b === void 0 ? void 0 : _b.profiles) + profiles: cleanPlayerSkyblockProfiles(data.stats?.SkyBlock?.profiles) }; } -exports.cleanPlayerResponse = cleanPlayerResponse; diff --git a/build/cleaners/rank.js b/build/cleaners/rank.js index 19e4938..1d80d2c 100644 --- a/build/cleaners/rank.js +++ b/build/cleaners/rank.js @@ -1,7 +1,4 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.cleanRank = void 0; -const util_1 = require("../util"); +import { colorCodeFromName, minecraftColorCodes } from '../util.js'; const rankColors = { 'NONE': '7', 'VIP': 'a', @@ -16,15 +13,14 @@ const rankColors = { 'ADMIN': 'c' }; /** Response cleaning (reformatting to be nicer) */ -function cleanRank({ packageRank, newPackageRank, monthlyPackageRank, rankPlusColor, rank, prefix }) { - var _a; +export function cleanRank({ packageRank, newPackageRank, monthlyPackageRank, rankPlusColor, rank, prefix }) { let name; let color; let colored; let bracketColor; if (prefix) { // derive values from prefix colored = prefix; - color = util_1.minecraftColorCodes[colored.match(/§./)[0][1]]; + color = minecraftColorCodes[colored.match(/§./)[0][1]]; name = colored.replace(/§./g, '').replace(/[\[\]]/g, ''); } else { @@ -33,7 +29,8 @@ function cleanRank({ packageRank, newPackageRank, monthlyPackageRank, rankPlusCo else if (rank && rank !== 'NORMAL') name = rank; else - name = (_a = newPackageRank === null || newPackageRank === void 0 ? void 0 : newPackageRank.replace('_PLUS', '+')) !== null && _a !== void 0 ? _a : packageRank === null || packageRank === void 0 ? void 0 : packageRank.replace('_PLUS', '+'); + name = newPackageRank?.replace('_PLUS', '+') + ?? packageRank?.replace('_PLUS', '+'); switch (name) { // MVP++ is called Superstar for some reason case 'SUPERSTAR': @@ -54,8 +51,8 @@ function cleanRank({ packageRank, newPackageRank, monthlyPackageRank, rankPlusCo name = 'NONE'; break; } - const plusColor = rankPlusColor ? util_1.colorCodeFromName(rankPlusColor) : null; - color = util_1.minecraftColorCodes[rankColors[name]]; + const plusColor = rankPlusColor ? colorCodeFromName(rankPlusColor) : null; + color = minecraftColorCodes[rankColors[name]]; let rankColorPrefix = rankColors[name] ? '§' + rankColors[name] : ''; // the text is white, but only in the prefix if (name === 'YOUTUBE') @@ -82,4 +79,3 @@ function cleanRank({ packageRank, newPackageRank, monthlyPackageRank, rankPlusCo colored }; } -exports.cleanRank = cleanRank; diff --git a/build/cleaners/skyblock/bank.js b/build/cleaners/skyblock/bank.js index 9836685..fb08af5 100644 --- a/build/cleaners/skyblock/bank.js +++ b/build/cleaners/skyblock/bank.js @@ -1,13 +1,8 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.cleanBank = void 0; -function cleanBank(data) { - var _a, _b; +export function cleanBank(data) { return { - balance: (_b = (_a = data === null || data === void 0 ? void 0 : data.banking) === null || _a === void 0 ? void 0 : _a.balance) !== null && _b !== void 0 ? _b : 0, + balance: data?.banking?.balance ?? 0, // TODO: make transactions good // history: data?.banking?.transactions ?? [] history: [] }; } -exports.cleanBank = cleanBank; diff --git a/build/cleaners/skyblock/collections.js b/build/cleaners/skyblock/collections.js index 0bb4cb5..4a5b34e 100644 --- a/build/cleaners/skyblock/collections.js +++ b/build/cleaners/skyblock/collections.js @@ -1,7 +1,4 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.cleanCollections = void 0; -const itemId_1 = require("./itemId"); +import { cleanItemId } from './itemId.js'; const COLLECTIONS = { 'farming': [ 'wheat', @@ -83,15 +80,14 @@ function getCategory(collectionName) { return categoryName; } } -function cleanCollections(data) { - var _a, _b, _c; +export function cleanCollections(data) { // collection tiers show up like this: [ GRAVEL_3, GOLD_INGOT_2, MELON_-1, LOG_2:1_7, RAW_FISH:3_-1] // these tiers are the same for all players in a coop - const playerCollectionTiersRaw = (_a = data === null || data === void 0 ? void 0 : data.unlocked_coll_tiers) !== null && _a !== void 0 ? _a : []; + const playerCollectionTiersRaw = data?.unlocked_coll_tiers ?? []; const playerCollectionTiers = {}; for (const collectionTierNameValueRaw of playerCollectionTiersRaw) { const [collectionTierNameRaw, collectionTierValueRaw] = collectionTierNameValueRaw.split(/_(?=-?\d+$)/); - const collectionName = itemId_1.cleanItemId(collectionTierNameRaw); + const collectionName = cleanItemId(collectionTierNameRaw); // ensure it's at least 0 const collectionValue = Math.max(parseInt(collectionTierValueRaw), 0); // if the collection hasn't been checked yet, or the new value is higher than the old, replace it @@ -100,13 +96,13 @@ function cleanCollections(data) { } // collection names show up like this: { LOG: 49789, LOG:2: 26219, MUSHROOM_COLLECTION: 2923} // these values are different for each player in a coop - const playerCollectionXpsRaw = (_b = data === null || data === void 0 ? void 0 : data.collection) !== null && _b !== void 0 ? _b : {}; + const playerCollectionXpsRaw = data?.collection ?? {}; const playerCollections = []; for (const collectionNameRaw in playerCollectionXpsRaw) { const collectionXp = playerCollectionXpsRaw[collectionNameRaw]; - const collectionName = itemId_1.cleanItemId(collectionNameRaw); + const collectionName = cleanItemId(collectionNameRaw); const collectionLevel = playerCollectionTiers[collectionName]; - const collectionCategory = (_c = getCategory(collectionName)) !== null && _c !== void 0 ? _c : 'unknown'; + const collectionCategory = getCategory(collectionName) ?? 'unknown'; // in some very weird cases the collection level will be undefined, we should ignore these collections if (collectionLevel !== undefined) playerCollections.push({ @@ -118,4 +114,3 @@ function cleanCollections(data) { } return playerCollections; } -exports.cleanCollections = cleanCollections; diff --git a/build/cleaners/skyblock/fairysouls.js b/build/cleaners/skyblock/fairysouls.js index 1c6cef6..8ec8078 100644 --- a/build/cleaners/skyblock/fairysouls.js +++ b/build/cleaners/skyblock/fairysouls.js @@ -1,12 +1,7 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.cleanFairySouls = void 0; -function cleanFairySouls(data) { - var _a, _b, _c; +export function cleanFairySouls(data) { return { - total: (_a = data === null || data === void 0 ? void 0 : data.fairy_souls_collected) !== null && _a !== void 0 ? _a : 0, - unexchanged: (_b = data === null || data === void 0 ? void 0 : data.fairy_souls) !== null && _b !== void 0 ? _b : 0, - exchanges: (_c = data === null || data === void 0 ? void 0 : data.fairy_exchanges) !== null && _c !== void 0 ? _c : 0, + total: data?.fairy_souls_collected ?? 0, + unexchanged: data?.fairy_souls ?? 0, + exchanges: data?.fairy_exchanges ?? 0, }; } -exports.cleanFairySouls = cleanFairySouls; diff --git a/build/cleaners/skyblock/inventory.js b/build/cleaners/skyblock/inventory.js index 098b8d4..714a302 100644 --- a/build/cleaners/skyblock/inventory.js +++ b/build/cleaners/skyblock/inventory.js @@ -1,32 +1,9 @@ -"use strict"; -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.cleanInventories = exports.INVENTORIES = exports.cleanInventory = void 0; // maybe todo?: create a fast replacement for prismarine-nbt -const nbt = __importStar(require("prismarine-nbt")); +import * as nbt from 'prismarine-nbt'; function base64decode(base64) { return Buffer.from(base64, 'base64'); } function cleanItem(rawItem) { - var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o; // if the item doesn't have an id, it isn't an item if (rawItem.id === undefined) return null; @@ -34,13 +11,13 @@ function cleanItem(rawItem) { const itemCount = rawItem.Count; const damageValue = rawItem.Damage; const itemTag = rawItem.tag; - const extraAttributes = (_a = itemTag === null || itemTag === void 0 ? void 0 : itemTag.ExtraAttributes) !== null && _a !== void 0 ? _a : {}; + const extraAttributes = itemTag?.ExtraAttributes ?? {}; let headId; if (vanillaId === 397) { - const headDataBase64 = (_e = (_d = (_c = (_b = itemTag === null || itemTag === void 0 ? void 0 : itemTag.SkullOwner) === null || _b === void 0 ? void 0 : _b.Properties) === null || _c === void 0 ? void 0 : _c.textures) === null || _d === void 0 ? void 0 : _d[0]) === null || _e === void 0 ? void 0 : _e.Value; + const headDataBase64 = itemTag?.SkullOwner?.Properties?.textures?.[0]?.Value; if (headDataBase64) { const headData = JSON.parse(base64decode(headDataBase64).toString()); - const headDataUrl = (_g = (_f = headData === null || headData === void 0 ? void 0 : headData.textures) === null || _f === void 0 ? void 0 : _f.SKIN) === null || _g === void 0 ? void 0 : _g.url; + const headDataUrl = headData?.textures?.SKIN?.url; if (headDataUrl) { const splitUrl = headDataUrl.split('/'); headId = splitUrl[splitUrl.length - 1]; @@ -48,26 +25,26 @@ function cleanItem(rawItem) { } } return { - id: (_h = extraAttributes === null || extraAttributes === void 0 ? void 0 : extraAttributes.id) !== null && _h !== void 0 ? _h : null, - count: itemCount !== null && itemCount !== void 0 ? itemCount : 1, + id: extraAttributes?.id ?? null, + count: itemCount ?? 1, vanillaId: damageValue ? `${vanillaId}:${damageValue}` : vanillaId.toString(), display: { - name: (_k = (_j = itemTag === null || itemTag === void 0 ? void 0 : itemTag.display) === null || _j === void 0 ? void 0 : _j.Name) !== null && _k !== void 0 ? _k : 'null', - lore: (_m = (_l = itemTag === null || itemTag === void 0 ? void 0 : itemTag.display) === null || _l === void 0 ? void 0 : _l.Lore) !== null && _m !== void 0 ? _m : [], + name: itemTag?.display?.Name ?? 'null', + lore: itemTag?.display?.Lore ?? [], // if it has an ench value in the tag, then it should have an enchant glint effect - glint: ((_o = itemTag === null || itemTag === void 0 ? void 0 : itemTag.ench) !== null && _o !== void 0 ? _o : []).length > 0 + glint: (itemTag?.ench ?? []).length > 0 }, - reforge: extraAttributes === null || extraAttributes === void 0 ? void 0 : extraAttributes.modifier, - enchantments: extraAttributes === null || extraAttributes === void 0 ? void 0 : extraAttributes.enchantments, - anvil_uses: extraAttributes === null || extraAttributes === void 0 ? void 0 : extraAttributes.anvil_uses, - timestamp: extraAttributes === null || extraAttributes === void 0 ? void 0 : extraAttributes.timestamp, + reforge: extraAttributes?.modifier, + enchantments: extraAttributes?.enchantments, + anvil_uses: extraAttributes?.anvil_uses, + timestamp: extraAttributes?.timestamp, head_texture: headId, }; } function cleanItems(rawItems) { return rawItems.map(cleanItem); } -function cleanInventory(encodedNbt) { +export function cleanInventory(encodedNbt) { return new Promise(resolve => { const base64Data = base64decode(encodedNbt); nbt.parse(base64Data, false, (err, value) => { @@ -77,8 +54,7 @@ function cleanInventory(encodedNbt) { }); }); } -exports.cleanInventory = cleanInventory; -exports.INVENTORIES = { +export const INVENTORIES = { armor: 'inv_armor', inventory: 'inv_contents', ender_chest: 'ender_chest_contents', @@ -89,12 +65,11 @@ exports.INVENTORIES = { trick_or_treat_bag: 'candy_inventory_contents', wardrobe: 'wardrobe_contents' }; -async function cleanInventories(data) { - var _a; +export async function cleanInventories(data) { const cleanInventories = {}; - for (const cleanInventoryName in exports.INVENTORIES) { - const hypixelInventoryName = exports.INVENTORIES[cleanInventoryName]; - const encodedInventoryContents = (_a = data[hypixelInventoryName]) === null || _a === void 0 ? void 0 : _a.data; + for (const cleanInventoryName in INVENTORIES) { + const hypixelInventoryName = INVENTORIES[cleanInventoryName]; + const encodedInventoryContents = data[hypixelInventoryName]?.data; let inventoryContents; if (encodedInventoryContents) { inventoryContents = await cleanInventory(encodedInventoryContents); @@ -106,4 +81,3 @@ async function cleanInventories(data) { } return cleanInventories; } -exports.cleanInventories = cleanInventories; diff --git a/build/cleaners/skyblock/itemId.js b/build/cleaners/skyblock/itemId.js index 7bf5402..ea94771 100644 --- a/build/cleaners/skyblock/itemId.js +++ b/build/cleaners/skyblock/itemId.js @@ -1,6 +1,3 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.cleanItemId = void 0; // change weird item names to be more consistent with vanilla const ITEMS = { 'log': 'oak_log', @@ -55,8 +52,6 @@ const ITEMS = { 'enchanted_glistering_melon': 'enchanted_glistering_melon_slice' }; /** Clean an item with a weird name (log_2:1) and make it have a better name (dark_oak_log) */ -function cleanItemId(itemId) { - var _a; - return (_a = ITEMS[itemId.toLowerCase()]) !== null && _a !== void 0 ? _a : itemId.toLowerCase(); +export function cleanItemId(itemId) { + return ITEMS[itemId.toLowerCase()] ?? itemId.toLowerCase(); } -exports.cleanItemId = cleanItemId; diff --git a/build/cleaners/skyblock/member.js b/build/cleaners/skyblock/member.js index cc66488..2242828 100644 --- a/build/cleaners/skyblock/member.js +++ b/build/cleaners/skyblock/member.js @@ -1,37 +1,15 @@ -"use strict"; -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.cleanSkyBlockProfileMemberResponse = exports.cleanSkyBlockProfileMemberResponseBasic = void 0; -const collections_1 = require("./collections"); -const inventory_1 = require("./inventory"); -const fairysouls_1 = require("./fairysouls"); -const objectives_1 = require("./objectives"); -const stats_1 = require("./stats"); -const minions_1 = require("./minions"); -const slayers_1 = require("./slayers"); -const zones_1 = require("./zones"); -const skills_1 = require("./skills"); -const cached = __importStar(require("../../hypixelCached")); -const constants = __importStar(require("../../constants")); -async function cleanSkyBlockProfileMemberResponseBasic(member) { +import { cleanCollections } from './collections.js'; +import { cleanInventories } from './inventory.js'; +import { cleanFairySouls } from './fairysouls.js'; +import { cleanObjectives } from './objectives.js'; +import { cleanProfileStats } from './stats.js'; +import { cleanMinions } from './minions.js'; +import { cleanSlayers } from './slayers.js'; +import { cleanVisitedZones } from './zones.js'; +import { cleanSkills } from './skills.js'; +import * as cached from '../../hypixelCached.js'; +import * as constants from '../../constants.js'; +export async function cleanSkyBlockProfileMemberResponseBasic(member) { const player = await cached.fetchPlayer(member.uuid); if (!player) return null; @@ -43,18 +21,16 @@ async function cleanSkyBlockProfileMemberResponseBasic(member) { rank: player.rank }; } -exports.cleanSkyBlockProfileMemberResponseBasic = cleanSkyBlockProfileMemberResponseBasic; /** Cleans up a member (from skyblock/profile) */ -async function cleanSkyBlockProfileMemberResponse(member, included = undefined) { - var _a; +export async function cleanSkyBlockProfileMemberResponse(member, included = undefined) { // profiles.members[] const inventoriesIncluded = included === undefined || included.includes('inventories'); const player = await cached.fetchPlayer(member.uuid); if (!player) return null; - const fairySouls = fairysouls_1.cleanFairySouls(member); + const fairySouls = cleanFairySouls(member); const { max_fairy_souls: maxFairySouls } = await constants.fetchConstantValues(); - if (fairySouls.total > (maxFairySouls !== null && maxFairySouls !== void 0 ? maxFairySouls : 0)) + if (fairySouls.total > (maxFairySouls ?? 0)) await constants.setConstantValues({ max_fairy_souls: fairySouls.total }); return { uuid: member.uuid, @@ -63,17 +39,16 @@ async function cleanSkyBlockProfileMemberResponse(member, included = undefined) first_join: member.first_join / 1000, rank: player.rank, purse: member.coin_purse, - stats: stats_1.cleanProfileStats(member), + stats: cleanProfileStats(member), // this is used for leaderboards - rawHypixelStats: (_a = member.stats) !== null && _a !== void 0 ? _a : {}, - minions: await minions_1.cleanMinions(member), + rawHypixelStats: member.stats ?? {}, + minions: await cleanMinions(member), fairy_souls: fairySouls, - inventories: inventoriesIncluded ? await inventory_1.cleanInventories(member) : undefined, - objectives: objectives_1.cleanObjectives(member), - skills: await skills_1.cleanSkills(member), - visited_zones: zones_1.cleanVisitedZones(member), - collections: collections_1.cleanCollections(member), - slayers: slayers_1.cleanSlayers(member) + inventories: inventoriesIncluded ? await cleanInventories(member) : undefined, + objectives: cleanObjectives(member), + skills: await cleanSkills(member), + visited_zones: cleanVisitedZones(member), + collections: cleanCollections(member), + slayers: cleanSlayers(member) }; } -exports.cleanSkyBlockProfileMemberResponse = cleanSkyBlockProfileMemberResponse; diff --git a/build/cleaners/skyblock/minions.js b/build/cleaners/skyblock/minions.js index d2bfc41..5c0bd9a 100644 --- a/build/cleaners/skyblock/minions.js +++ b/build/cleaners/skyblock/minions.js @@ -1,36 +1,13 @@ -"use strict"; -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.countUniqueMinions = exports.combineMinionArrays = exports.cleanMinions = void 0; -const hypixel_1 = require("../../hypixel"); -const constants = __importStar(require("../../constants")); +import { maxMinion } from '../../hypixel.js'; +import * as constants from '../../constants.js'; /** * Clean the minions provided by Hypixel * @param minionsRaw The minion data provided by the Hypixel API */ -async function cleanMinions(member) { - var _a; +export async function cleanMinions(member) { const minions = []; const processedMinionNames = new Set(); - for (const minionRaw of (_a = member === null || member === void 0 ? void 0 : member.crafted_generators) !== null && _a !== void 0 ? _a : []) { + for (const minionRaw of member?.crafted_generators ?? []) { // do some regex magic to get the minion name and level // examples of potential minion names: CLAY_11, PIG_1, MAGMA_CUBE_4 const minionName = minionRaw.split(/_\d/)[0].toLowerCase(); @@ -40,7 +17,7 @@ async function cleanMinions(member) { // if the minion doesnt already exist in the minions array, then create it matchingMinion = { name: minionName, - levels: new Array(hypixel_1.maxMinion).fill(false) + levels: new Array(maxMinion).fill(false) }; minions.push(matchingMinion); } @@ -63,18 +40,17 @@ async function cleanMinions(member) { processedMinionNames.add(minionName); minions.push({ name: minionName, - levels: new Array(hypixel_1.maxMinion).fill(false) + levels: new Array(maxMinion).fill(false) }); } } return minions.sort((a, b) => a.name > b.name ? 1 : (a.name < b.name ? -1 : 0)); } -exports.cleanMinions = cleanMinions; /** * Combine multiple arrays of minions into one, useful when getting the minions for members * @param minions An array of arrays of minions */ -function combineMinionArrays(minions) { +export function combineMinionArrays(minions) { const resultMinions = []; for (const memberMinions of minions) { for (const minion of memberMinions) { @@ -99,8 +75,7 @@ function combineMinionArrays(minions) { } return resultMinions; } -exports.combineMinionArrays = combineMinionArrays; -function countUniqueMinions(minions) { +export function countUniqueMinions(minions) { let uniqueMinions = 0; for (const minion of minions) { // find the number of times `true` is in the list and add it to uniqueMinions @@ -108,4 +83,3 @@ function countUniqueMinions(minions) { } return uniqueMinions; } -exports.countUniqueMinions = countUniqueMinions; diff --git a/build/cleaners/skyblock/objectives.js b/build/cleaners/skyblock/objectives.js index d45307c..52e92db 100644 --- a/build/cleaners/skyblock/objectives.js +++ b/build/cleaners/skyblock/objectives.js @@ -1,8 +1,5 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.cleanObjectives = void 0; -function cleanObjectives(data) { - const rawObjectives = (data === null || data === void 0 ? void 0 : data.objectives) || {}; +export function cleanObjectives(data) { + const rawObjectives = data?.objectives || {}; const objectives = []; for (const rawObjectiveName in rawObjectives) { const rawObjectiveValue = rawObjectives[rawObjectiveName]; @@ -13,4 +10,3 @@ function cleanObjectives(data) { } return objectives; } -exports.cleanObjectives = cleanObjectives; diff --git a/build/cleaners/skyblock/profile.js b/build/cleaners/skyblock/profile.js index 6460c3b..42e26b3 100644 --- a/build/cleaners/skyblock/profile.js +++ b/build/cleaners/skyblock/profile.js @@ -1,38 +1,16 @@ -"use strict"; -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.cleanSkyblockProfileResponse = exports.cleanSkyblockProfileResponseLighter = void 0; -const member_1 = require("./member"); -const minions_1 = require("./minions"); -const bank_1 = require("./bank"); -const constants = __importStar(require("../../constants")); +import { cleanSkyBlockProfileMemberResponse, cleanSkyBlockProfileMemberResponseBasic } from './member.js'; +import { combineMinionArrays, countUniqueMinions } from './minions.js'; +import * as constants from '../../constants.js'; +import { cleanBank } from './bank.js'; /** Return a `CleanProfile` instead of a `CleanFullProfile`, useful when we need to get members but don't want to waste much ram */ -async function cleanSkyblockProfileResponseLighter(data) { +export async function cleanSkyblockProfileResponseLighter(data) { // We use Promise.all so it can fetch all the usernames at once instead of waiting for the previous promise to complete const promises = []; for (const memberUUID in data.members) { const memberRaw = data.members[memberUUID]; memberRaw.uuid = memberUUID; // we pass an empty array to make it not check stats - promises.push(member_1.cleanSkyBlockProfileMemberResponseBasic(memberRaw)); + promises.push(cleanSkyBlockProfileMemberResponseBasic(memberRaw)); } const cleanedMembers = (await Promise.all(promises)).filter(m => m); return { @@ -41,11 +19,10 @@ async function cleanSkyblockProfileResponseLighter(data) { members: cleanedMembers, }; } -exports.cleanSkyblockProfileResponseLighter = cleanSkyblockProfileResponseLighter; /** * This function is somewhat costly and shouldn't be called often. Use cleanSkyblockProfileResponseLighter if you don't need all the data */ -async function cleanSkyblockProfileResponse(data, options) { +export async function cleanSkyblockProfileResponse(data, options) { // We use Promise.all so it can fetch all the users at once instead of waiting for the previous promise to complete const promises = []; if (!data) @@ -53,13 +30,13 @@ async function cleanSkyblockProfileResponse(data, options) { for (const memberUUID in data.members) { const memberRaw = data.members[memberUUID]; memberRaw.uuid = memberUUID; - promises.push(member_1.cleanSkyBlockProfileMemberResponse(memberRaw, [ - !(options === null || options === void 0 ? void 0 : options.basic) ? 'stats' : undefined, - (options === null || options === void 0 ? void 0 : options.mainMemberUuid) === memberUUID ? 'inventories' : undefined + promises.push(cleanSkyBlockProfileMemberResponse(memberRaw, [ + !options?.basic ? 'stats' : undefined, + options?.mainMemberUuid === memberUUID ? 'inventories' : undefined ])); } const cleanedMembers = (await Promise.all(promises)).filter(m => m !== null && m !== undefined); - if (options === null || options === void 0 ? void 0 : options.basic) { + if (options?.basic) { return { uuid: data.profile_id, name: data.cute_name, @@ -70,19 +47,18 @@ async function cleanSkyblockProfileResponse(data, options) { for (const member of cleanedMembers) { memberMinions.push(member.minions); } - const minions = minions_1.combineMinionArrays(memberMinions); + const minions = combineMinionArrays(memberMinions); const { max_minions: maxUniqueMinions } = await constants.fetchConstantValues(); - const uniqueMinions = minions_1.countUniqueMinions(minions); - if (uniqueMinions > (maxUniqueMinions !== null && maxUniqueMinions !== void 0 ? maxUniqueMinions : 0)) + const uniqueMinions = countUniqueMinions(minions); + if (uniqueMinions > (maxUniqueMinions ?? 0)) await constants.setConstantValues({ max_minions: uniqueMinions }); // return more detailed info return { uuid: data.profile_id, name: data.cute_name, members: cleanedMembers, - bank: bank_1.cleanBank(data), + bank: cleanBank(data), minions: minions, minion_count: uniqueMinions }; } -exports.cleanSkyblockProfileResponse = cleanSkyblockProfileResponse; diff --git a/build/cleaners/skyblock/profiles.js b/build/cleaners/skyblock/profiles.js index b916209..a85b1f3 100644 --- a/build/cleaners/skyblock/profiles.js +++ b/build/cleaners/skyblock/profiles.js @@ -1,10 +1,7 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.cleanSkyblockProfilesResponse = exports.cleanPlayerSkyblockProfiles = void 0; -const profile_1 = require("./profile"); -function cleanPlayerSkyblockProfiles(rawProfiles) { +import { cleanSkyblockProfileResponse } from './profile.js'; +export function cleanPlayerSkyblockProfiles(rawProfiles) { let profiles = []; - for (const profile of Object.values(rawProfiles !== null && rawProfiles !== void 0 ? rawProfiles : {})) { + for (const profile of Object.values(rawProfiles ?? {})) { profiles.push({ uuid: profile.profile_id, name: profile.cute_name @@ -12,15 +9,13 @@ function cleanPlayerSkyblockProfiles(rawProfiles) { } return profiles; } -exports.cleanPlayerSkyblockProfiles = cleanPlayerSkyblockProfiles; /** Convert an array of raw profiles into clean profiles */ -async function cleanSkyblockProfilesResponse(data) { +export async function cleanSkyblockProfilesResponse(data) { const promises = []; - for (const profile of data !== null && data !== void 0 ? data : []) { + for (const profile of data ?? []) { // let cleanedProfile = await cleanSkyblockProfileResponseLighter(profile) - promises.push(profile_1.cleanSkyblockProfileResponse(profile)); + promises.push(cleanSkyblockProfileResponse(profile)); } const cleanedProfiles = (await Promise.all(promises)).filter(p => p); return cleanedProfiles; } -exports.cleanSkyblockProfilesResponse = cleanSkyblockProfilesResponse; diff --git a/build/cleaners/skyblock/skills.js b/build/cleaners/skyblock/skills.js index 2518d60..e9b19f8 100644 --- a/build/cleaners/skyblock/skills.js +++ b/build/cleaners/skyblock/skills.js @@ -1,6 +1,3 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.cleanSkills = exports.levelForSkillXp = void 0; // the highest level you can have in each skill // numbers taken from https://hypixel-skyblock.fandom.com/wiki/Skills const skillsMaxLevel = { @@ -113,21 +110,19 @@ const skillsDefaultMaxLevel = 50; * @param xp The xp we're finding the level for * @param easierLevel Whether it should use the alternate leveling xp table (used for cosmetic skills and dungeoneering) */ -function levelForSkillXp(xp, maxLevel) { +export function levelForSkillXp(xp, maxLevel) { const xpTable = (maxLevel <= 25 ? skillXpTableEasier : skillXpTable).slice(0, maxLevel); const skillLevel = [...xpTable].reverse().findIndex(levelXp => xp >= levelXp); return skillLevel === -1 ? 0 : xpTable.length - skillLevel; } -exports.levelForSkillXp = levelForSkillXp; -async function cleanSkills(data) { - var _a; +export async function cleanSkills(data) { const skills = []; for (const item in data) { if (item.startsWith('experience_skill_')) { const skillName = item.substr('experience_skill_'.length); // the amount of total xp you have in this skill const skillXp = data[item]; - const skillMaxLevel = (_a = skillsMaxLevel[skillName]) !== null && _a !== void 0 ? _a : skillsDefaultMaxLevel; + const skillMaxLevel = skillsMaxLevel[skillName] ?? skillsDefaultMaxLevel; const xpTable = (skillMaxLevel <= 25 ? skillXpTableEasier : skillXpTable).slice(0, skillMaxLevel); // the level you're at for this skill const skillLevel = levelForSkillXp(skillXp, skillMaxLevel); @@ -149,4 +144,3 @@ async function cleanSkills(data) { } return skills; } -exports.cleanSkills = cleanSkills; diff --git a/build/cleaners/skyblock/slayers.js b/build/cleaners/skyblock/slayers.js index 8575d43..75894f7 100644 --- a/build/cleaners/skyblock/slayers.js +++ b/build/cleaners/skyblock/slayers.js @@ -1,30 +1,26 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.cleanSlayers = exports.slayerLevels = void 0; -exports.slayerLevels = 5; +export const slayerLevels = 5; const SLAYER_NAMES = { spider: 'tarantula', zombie: 'revenant', wolf: 'sven' }; -function cleanSlayers(data) { - var _a, _b; +export function cleanSlayers(data) { const slayers = []; - const slayersDataRaw = data === null || data === void 0 ? void 0 : data.slayer_bosses; + const slayersDataRaw = data?.slayer_bosses; let totalXp = 0; let totalKills = 0; for (const slayerNameRaw in slayersDataRaw) { const slayerDataRaw = slayersDataRaw[slayerNameRaw]; // convert name provided by api (spider) to the real name (tarantula) const slayerName = SLAYER_NAMES[slayerNameRaw]; - const slayerXp = (_a = slayerDataRaw.xp) !== null && _a !== void 0 ? _a : 0; + const slayerXp = slayerDataRaw.xp ?? 0; let slayerKills = 0; const slayerTiers = []; for (const slayerDataKey in slayerDataRaw) { // if a key starts with boss_kills_tier_ (boss_kills_tier_1), get the last number if (slayerDataKey.startsWith('boss_kills_tier_')) { const slayerTierRaw = parseInt(slayerDataKey.substr('boss_kills_tier_'.length)); - const slayerTierKills = (_b = slayerDataRaw[slayerDataKey]) !== null && _b !== void 0 ? _b : 0; + const slayerTierKills = slayerDataRaw[slayerDataKey] ?? 0; // add 1 since hypixel is using 0 indexed tiers const slayerTier = slayerTierRaw + 1; slayerTiers.push({ @@ -37,7 +33,7 @@ function cleanSlayers(data) { } } // if the slayer tier length is less than the max, add more empty ones - while (slayerTiers.length < exports.slayerLevels) + while (slayerTiers.length < slayerLevels) slayerTiers.push({ tier: slayerTiers.length + 1, kills: 0 @@ -46,7 +42,7 @@ function cleanSlayers(data) { name: slayerName, raw_name: slayerNameRaw, tiers: slayerTiers, - xp: slayerXp !== null && slayerXp !== void 0 ? slayerXp : 0, + xp: slayerXp ?? 0, kills: slayerKills }; slayers.push(slayer); @@ -62,4 +58,3 @@ function cleanSlayers(data) { bosses: slayers }; } -exports.cleanSlayers = cleanSlayers; diff --git a/build/cleaners/skyblock/stats.js b/build/cleaners/skyblock/stats.js index 1f72201..361f1ba 100644 --- a/build/cleaners/skyblock/stats.js +++ b/build/cleaners/skyblock/stats.js @@ -1,6 +1,3 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.cleanProfileStats = exports.getStatUnit = exports.statUnits = exports.categorizeStat = void 0; const statCategories = { 'deaths': ['deaths_', 'deaths'], 'kills': ['kills_', 'kills'], @@ -13,7 +10,7 @@ const statCategories = { 'slayer': ['slayer_'], 'misc': null // everything else goes here }; -function categorizeStat(statNameRaw) { +export function categorizeStat(statNameRaw) { // 'deaths_void' for (const statCategory in statCategories) { // 'deaths' @@ -56,15 +53,14 @@ function categorizeStat(statNameRaw) { name: statNameRaw }; } -exports.categorizeStat = categorizeStat; -exports.statUnits = { +export const statUnits = { time: ['_best_time', '_best_time_2'], date: ['first_join'], coins: ['purse'], leaderboards: ['leaderboards_count', 'top_1_leaderboards_count'] }; -function getStatUnit(name) { - for (const [unitName, statMatchers] of Object.entries(exports.statUnits)) { +export function getStatUnit(name) { + for (const [unitName, statMatchers] of Object.entries(statUnits)) { for (const statMatch of statMatchers) { let trailingEnd = statMatch[0] === '_'; let trailingStart = statMatch.substr(-1) === '_'; @@ -76,23 +72,20 @@ function getStatUnit(name) { } return null; } -exports.getStatUnit = getStatUnit; -function cleanProfileStats(data) { - var _a, _b; +export function cleanProfileStats(data) { // TODO: add type for statsRaw (probably in hypixelApi.ts since its coming from there) const stats = []; - const rawStats = (_a = data === null || data === void 0 ? void 0 : data.stats) !== null && _a !== void 0 ? _a : {}; + const rawStats = data?.stats ?? {}; for (const statNameRaw in rawStats) { const statValue = rawStats[statNameRaw]; let { category: statCategory, name: statName } = categorizeStat(statNameRaw); stats.push({ - categorizedName: statName !== null && statName !== void 0 ? statName : 'total', + categorizedName: statName ?? 'total', value: statValue, rawName: statNameRaw, category: statCategory, - unit: (_b = getStatUnit(statNameRaw)) !== null && _b !== void 0 ? _b : null + unit: getStatUnit(statNameRaw) ?? null }); } return stats; } -exports.cleanProfileStats = cleanProfileStats; diff --git a/build/cleaners/skyblock/zones.js b/build/cleaners/skyblock/zones.js index fb79441..ef7015e 100644 --- a/build/cleaners/skyblock/zones.js +++ b/build/cleaners/skyblock/zones.js @@ -1,8 +1,5 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.cleanVisitedZones = void 0; -function cleanVisitedZones(data) { - const rawZones = (data === null || data === void 0 ? void 0 : data.visited_zones) || []; +export function cleanVisitedZones(data) { + const rawZones = data?.visited_zones || []; // TODO: store all the zones that exist in SkyBlock, add add those to the array with visited being false const zones = []; for (const rawZoneName of rawZones) { @@ -13,4 +10,3 @@ function cleanVisitedZones(data) { } return zones; } -exports.cleanVisitedZones = cleanVisitedZones; diff --git a/build/cleaners/socialmedia.js b/build/cleaners/socialmedia.js index 4883cc4..c901725 100644 --- a/build/cleaners/socialmedia.js +++ b/build/cleaners/socialmedia.js @@ -1,11 +1,6 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.cleanSocialMedia = void 0; -function cleanSocialMedia(data) { - var _a, _b, _c, _d; +export function cleanSocialMedia(data) { return { - discord: ((_b = (_a = data === null || data === void 0 ? void 0 : data.socialMedia) === null || _a === void 0 ? void 0 : _a.links) === null || _b === void 0 ? void 0 : _b.DISCORD) || null, - forums: ((_d = (_c = data === null || data === void 0 ? void 0 : data.socialMedia) === null || _c === void 0 ? void 0 : _c.links) === null || _d === void 0 ? void 0 : _d.HYPIXEL) || null + discord: data?.socialMedia?.links?.DISCORD || null, + forums: data?.socialMedia?.links?.HYPIXEL || null }; } -exports.cleanSocialMedia = cleanSocialMedia; diff --git a/build/constants.js b/build/constants.js index 414a6c5..7dcb210 100644 --- a/build/constants.js +++ b/build/constants.js @@ -1,46 +1,21 @@ -"use strict"; /** * Fetch and edit constants from the skyblock-constants repo */ -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.setConstantValues = exports.fetchConstantValues = exports.addMinions = exports.fetchSkillXpEasier = exports.fetchSkillXp = exports.fetchMinions = exports.addSlayers = exports.fetchSlayers = exports.addZones = exports.fetchZones = exports.addSkills = exports.fetchSkills = exports.addCollections = exports.fetchCollections = exports.addStats = exports.fetchStats = exports.addJSONConstants = exports.fetchJSONConstant = void 0; // we have to do this so we can mock the function from the tests properly -const constants = __importStar(require("./constants")); -const node_cache_1 = __importDefault(require("node-cache")); -const queue_promise_1 = __importDefault(require("queue-promise")); -const node_fetch_1 = __importDefault(require("node-fetch")); -const https_1 = require("https"); -const _1 = require("."); -const httpsAgent = new https_1.Agent({ +import * as constants from './constants.js'; +import NodeCache from 'node-cache'; +import { debug } from './index.js'; +import Queue from 'queue-promise'; +import fetch from 'node-fetch'; +import { Agent } from 'https'; +const httpsAgent = new Agent({ keepAlive: true }); const githubApiBase = 'https://api.github.com'; const owner = 'skyblockstats'; const repo = 'skyblock-constants'; // we use a queue for editing so it always utilizes the cache if possible, and to avoid hitting the github rateimit -const queue = new queue_promise_1.default({ +const queue = new Queue({ concurrent: 1, interval: 10 }); @@ -53,9 +28,9 @@ const queue = new queue_promise_1.default({ */ async function fetchGithubApi(method, route, headers, json) { try { - if (_1.debug) + if (debug) console.debug('fetching github api', method, route); - const data = await node_fetch_1.default(githubApiBase + route, { + const data = await fetch(githubApiBase + route, { agent: () => httpsAgent, body: json ? JSON.stringify(json) : undefined, method, @@ -63,7 +38,7 @@ async function fetchGithubApi(method, route, headers, json) { 'Authorization': `token ${process.env.github_token}` }, headers), }); - if (_1.debug) + if (debug) console.debug('fetched github api', method, route); return data; } @@ -74,7 +49,7 @@ async function fetchGithubApi(method, route, headers, json) { } } // cache files for an hour -const fileCache = new node_cache_1.default({ +const fileCache = new NodeCache({ stdTTL: 60 * 60, checkperiod: 60, useClones: false, @@ -122,7 +97,7 @@ async function editFile(file, message, newContent) { sha: data.content.sha }); } -async function fetchJSONConstant(filename) { +export let fetchJSONConstant = async function fetchJSONConstant(filename) { const file = await fetchFile(filename); try { return JSON.parse(file.content); @@ -131,10 +106,9 @@ async function fetchJSONConstant(filename) { // probably invalid json, return an empty array return []; } -} -exports.fetchJSONConstant = fetchJSONConstant; +}; /** Add stats to skyblock-constants. This has caching so it's fine to call many times */ -async function addJSONConstants(filename, addingValues, unit = 'stat') { +export let addJSONConstants = async function addJSONConstants(filename, addingValues, unit = 'stat') { if (addingValues.length === 0) return; // no stats provided, just return let file = await fetchFile(filename); @@ -166,81 +140,65 @@ async function addJSONConstants(filename, addingValues, unit = 'stat') { file = await fetchFile(filename); await editFile(file, commitMessage, JSON.stringify(updatedStats, null, 2)); } -} -exports.addJSONConstants = addJSONConstants; +}; /** Fetch all the known SkyBlock stats as an array of strings */ -async function fetchStats() { +export async function fetchStats() { return await constants.fetchJSONConstant('stats.json'); } -exports.fetchStats = fetchStats; /** Add stats to skyblock-constants. This has caching so it's fine to call many times */ -async function addStats(addingStats) { +export async function addStats(addingStats) { await constants.addJSONConstants('stats.json', addingStats, 'stat'); } -exports.addStats = addStats; /** Fetch all the known SkyBlock collections as an array of strings */ -async function fetchCollections() { +export async function fetchCollections() { return await constants.fetchJSONConstant('collections.json'); } -exports.fetchCollections = fetchCollections; /** Add collections to skyblock-constants. This has caching so it's fine to call many times */ -async function addCollections(addingCollections) { +export async function addCollections(addingCollections) { await constants.addJSONConstants('collections.json', addingCollections, 'collection'); } -exports.addCollections = addCollections; /** Fetch all the known SkyBlock collections as an array of strings */ -async function fetchSkills() { +export async function fetchSkills() { return await constants.fetchJSONConstant('skills.json'); } -exports.fetchSkills = fetchSkills; /** Add skills to skyblock-constants. This has caching so it's fine to call many times */ -async function addSkills(addingSkills) { +export async function addSkills(addingSkills) { await constants.addJSONConstants('skills.json', addingSkills, 'skill'); } -exports.addSkills = addSkills; /** Fetch all the known SkyBlock collections as an array of strings */ -async function fetchZones() { +export async function fetchZones() { return await constants.fetchJSONConstant('zones.json'); } -exports.fetchZones = fetchZones; /** Add skills to skyblock-constants. This has caching so it's fine to call many times */ -async function addZones(addingZones) { +export async function addZones(addingZones) { await constants.addJSONConstants('zones.json', addingZones, 'zone'); } -exports.addZones = addZones; /** Fetch all the known SkyBlock slayer names as an array of strings */ -async function fetchSlayers() { +export async function fetchSlayers() { return await constants.fetchJSONConstant('slayers.json'); } -exports.fetchSlayers = fetchSlayers; /** Add skills to skyblock-constants. This has caching so it's fine to call many times */ -async function addSlayers(addingSlayers) { +export async function addSlayers(addingSlayers) { await constants.addJSONConstants('slayers.json', addingSlayers, 'slayer'); } -exports.addSlayers = addSlayers; /** Fetch all the known SkyBlock slayer names as an array of strings */ -async function fetchMinions() { +export async function fetchMinions() { return await constants.fetchJSONConstant('minions.json'); } -exports.fetchMinions = fetchMinions; -async function fetchSkillXp() { +export async function fetchSkillXp() { return await constants.fetchJSONConstant('manual/skill_xp.json'); } -exports.fetchSkillXp = fetchSkillXp; -async function fetchSkillXpEasier() { +export async function fetchSkillXpEasier() { return await constants.fetchJSONConstant('manual/skill_xp_easier.json'); } -exports.fetchSkillXpEasier = fetchSkillXpEasier; /** Add skills to skyblock-constants. This has caching so it's fine to call many times */ -async function addMinions(addingMinions) { +export async function addMinions(addingMinions) { await constants.addJSONConstants('minions.json', addingMinions, 'minion'); } -exports.addMinions = addMinions; -async function fetchConstantValues() { +export async function fetchConstantValues() { return await constants.fetchJSONConstant('values.json'); } -exports.fetchConstantValues = fetchConstantValues; -async function setConstantValues(newValues) { +export async function setConstantValues(newValues) { let file = await fetchFile('values.json'); if (!file.path) return; @@ -263,4 +221,6 @@ async function setConstantValues(newValues) { } catch { } } -exports.setConstantValues = setConstantValues; +// this is necessary for mocking in the tests because es6 +export function mockAddJSONConstants($value) { addJSONConstants = $value; } +export function mockFetchJSONConstant($value) { fetchJSONConstant = $value; } diff --git a/build/database.js b/build/database.js index a12fc9e..b55a4ae 100644 --- a/build/database.js +++ b/build/database.js @@ -1,54 +1,29 @@ -"use strict"; /** * Store data about members for leaderboards */ -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.updateAccount = exports.fetchAccountFromDiscord = exports.fetchAccount = exports.fetchSession = exports.createSession = exports.finishedCachingRawLeaderboards = exports.queueUpdateDatabaseProfile = exports.queueUpdateDatabaseMember = exports.leaderboardUpdateProfileQueue = exports.leaderboardUpdateMemberQueue = exports.updateDatabaseProfile = exports.updateDatabaseMember = exports.fetchMemberLeaderboardSpots = exports.fetchLeaderboard = exports.fetchProfileLeaderboard = exports.fetchMemberLeaderboard = exports.fetchAllMemberLeaderboardAttributes = exports.fetchSlayerLeaderboards = exports.fetchAllLeaderboardsCategorized = exports.cachedRawLeaderboards = void 0; -const stats_1 = require("./cleaners/skyblock/stats"); -const slayers_1 = require("./cleaners/skyblock/slayers"); -const mongodb_1 = require("mongodb"); -const cached = __importStar(require("./hypixelCached")); -const constants = __importStar(require("./constants")); -const util_1 = require("./util"); -const node_cache_1 = __importDefault(require("node-cache")); -const uuid_1 = require("uuid"); -const queue_promise_1 = __importDefault(require("queue-promise")); -const _1 = require("."); +import { categorizeStat, getStatUnit } from './cleaners/skyblock/stats.js'; +import { slayerLevels } from './cleaners/skyblock/slayers.js'; +import { MongoClient } from 'mongodb'; +import * as cached from './hypixelCached.js'; +import * as constants from './constants.js'; +import { shuffle, sleep } from './util.js'; +import NodeCache from 'node-cache'; +import { v4 as uuid4 } from 'uuid'; +import Queue from 'queue-promise'; +import { debug } from './index.js'; // don't update the user for 3 minutes -const recentlyUpdated = new node_cache_1.default({ +const recentlyUpdated = new NodeCache({ stdTTL: 60 * 3, checkperiod: 60, useClones: false, }); // don't add stuff to the queue within the same 5 minutes -const recentlyQueued = new node_cache_1.default({ +const recentlyQueued = new NodeCache({ stdTTL: 60 * 5, checkperiod: 60, useClones: false, }); -exports.cachedRawLeaderboards = new Map(); +export const cachedRawLeaderboards = new Map(); const leaderboardMax = 100; const reversedLeaderboards = [ 'first_join', @@ -71,7 +46,7 @@ async function connect() { return console.warn('Warning: db_uri was not found in .env. Features that utilize the database such as leaderboards won\'t work.'); if (!process.env.db_name) return console.warn('Warning: db_name was not found in .env. Features that utilize the database such as leaderboards won\'t work.'); - client = await mongodb_1.MongoClient.connect(process.env.db_uri, { useNewUrlParser: true, useUnifiedTopology: true }); + client = await MongoClient.connect(process.env.db_uri); database = client.db(process.env.db_name); memberLeaderboardsCollection = database.collection('member-leaderboards'); profileLeaderboardsCollection = database.collection('profile-leaderboards'); @@ -132,12 +107,12 @@ function getProfileLeaderboardAttributes(profile) { unique_minions: profile.minion_count }; } -async function fetchAllLeaderboardsCategorized() { +export async function fetchAllLeaderboardsCategorized() { const memberLeaderboardAttributes = await fetchAllMemberLeaderboardAttributes(); const profileLeaderboardAttributes = await fetchAllProfileLeaderboardAttributes(); const categorizedLeaderboards = {}; for (const leaderboard of [...memberLeaderboardAttributes, ...profileLeaderboardAttributes]) { - const { category } = stats_1.categorizeStat(leaderboard); + const { category } = categorizeStat(leaderboard); if (category) { if (!categorizedLeaderboards[category]) categorizedLeaderboards[category] = []; @@ -150,9 +125,8 @@ async function fetchAllLeaderboardsCategorized() { categorizedLeaderboards.misc = misc; return categorizedLeaderboards; } -exports.fetchAllLeaderboardsCategorized = fetchAllLeaderboardsCategorized; /** Fetch the raw names for the slayer leaderboards */ -async function fetchSlayerLeaderboards() { +export async function fetchSlayerLeaderboards() { const rawSlayerNames = await constants.fetchSlayers(); let leaderboardNames = [ 'slayer_total_xp', @@ -162,15 +136,14 @@ async function fetchSlayerLeaderboards() { for (const slayerNameRaw of rawSlayerNames) { leaderboardNames.push(`slayer_${slayerNameRaw}_total_xp`); leaderboardNames.push(`slayer_${slayerNameRaw}_total_kills`); - for (let slayerTier = 1; slayerTier <= slayers_1.slayerLevels; slayerTier++) { + for (let slayerTier = 1; slayerTier <= slayerLevels; slayerTier++) { leaderboardNames.push(`slayer_${slayerNameRaw}_${slayerTier}_kills`); } } return leaderboardNames; } -exports.fetchSlayerLeaderboards = fetchSlayerLeaderboards; /** Fetch the names of all the leaderboards that rank members */ -async function fetchAllMemberLeaderboardAttributes() { +export async function fetchAllMemberLeaderboardAttributes() { return [ // we use the raw stat names rather than the clean stats in case hypixel adds a new stat and it takes a while for us to clean it ...await constants.fetchStats(), @@ -188,7 +161,6 @@ async function fetchAllMemberLeaderboardAttributes() { 'top_1_leaderboards_count' ]; } -exports.fetchAllMemberLeaderboardAttributes = fetchAllMemberLeaderboardAttributes; /** Fetch the names of all the leaderboards that rank profiles */ async function fetchAllProfileLeaderboardAttributes() { return [ @@ -211,14 +183,14 @@ const fetchingRawLeaderboardNames = new Set(); async function fetchMemberLeaderboardRaw(name) { if (!client) throw Error('Client isn\'t initialized yet'); - if (exports.cachedRawLeaderboards.has(name)) - return exports.cachedRawLeaderboards.get(name); + if (cachedRawLeaderboards.has(name)) + return cachedRawLeaderboards.get(name); // if it's currently being fetched, check every 100ms until it's in cachedRawLeaderboards if (fetchingRawLeaderboardNames.has(name)) { while (true) { - await util_1.sleep(100); - if (exports.cachedRawLeaderboards.has(name)) - return exports.cachedRawLeaderboards.get(name); + await sleep(100); + if (cachedRawLeaderboards.has(name)) + return cachedRawLeaderboards.get(name); } } // typescript forces us to make a new variable and set it this way because it gives an error otherwise @@ -240,18 +212,18 @@ async function fetchMemberLeaderboardRaw(name) { }; }); fetchingRawLeaderboardNames.delete(name); - exports.cachedRawLeaderboards.set(name, leaderboardRaw); + cachedRawLeaderboards.set(name, leaderboardRaw); return leaderboardRaw; } async function fetchProfileLeaderboardRaw(name) { - if (exports.cachedRawLeaderboards.has(name)) - return exports.cachedRawLeaderboards.get(name); + if (cachedRawLeaderboards.has(name)) + return cachedRawLeaderboards.get(name); // if it's currently being fetched, check every 100ms until it's in cachedRawLeaderboards if (fetchingRawLeaderboardNames.has(name)) { while (true) { - await util_1.sleep(100); - if (exports.cachedRawLeaderboards.has(name)) - return exports.cachedRawLeaderboards.get(name); + await sleep(100); + if (cachedRawLeaderboards.has(name)) + return cachedRawLeaderboards.get(name); } } // typescript forces us to make a new variable and set it this way because it gives an error otherwise @@ -273,12 +245,11 @@ async function fetchProfileLeaderboardRaw(name) { }; }); fetchingRawLeaderboardNames.delete(name); - exports.cachedRawLeaderboards.set(name, leaderboardRaw); + cachedRawLeaderboards.set(name, leaderboardRaw); return leaderboardRaw; } /** Fetch a leaderboard that ranks members, as opposed to profiles */ -async function fetchMemberLeaderboard(name) { - var _a; +export async function fetchMemberLeaderboard(name) { const leaderboardRaw = await fetchMemberLeaderboardRaw(name); const fetchLeaderboardPlayer = async (i) => { const player = await cached.fetchBasicPlayer(i.uuid); @@ -295,14 +266,12 @@ async function fetchMemberLeaderboard(name) { const leaderboard = await Promise.all(promises); return { name: name, - unit: (_a = stats_1.getStatUnit(name)) !== null && _a !== void 0 ? _a : null, + unit: getStatUnit(name) ?? null, list: leaderboard }; } -exports.fetchMemberLeaderboard = fetchMemberLeaderboard; /** Fetch a leaderboard that ranks profiles, as opposed to members */ -async function fetchProfileLeaderboard(name) { - var _a; +export async function fetchProfileLeaderboard(name) { const leaderboardRaw = await fetchProfileLeaderboardRaw(name); const fetchLeaderboardProfile = async (i) => { const players = []; @@ -324,13 +293,12 @@ async function fetchProfileLeaderboard(name) { const leaderboard = await Promise.all(promises); return { name: name, - unit: (_a = stats_1.getStatUnit(name)) !== null && _a !== void 0 ? _a : null, + unit: getStatUnit(name) ?? null, list: leaderboard }; } -exports.fetchProfileLeaderboard = fetchProfileLeaderboard; /** Fetch a leaderboard */ -async function fetchLeaderboard(name) { +export async function fetchLeaderboard(name) { const profileLeaderboards = await fetchAllProfileLeaderboardAttributes(); let leaderboard; if (profileLeaderboards.includes(name)) { @@ -343,10 +311,8 @@ async function fetchLeaderboard(name) { leaderboard.info = leaderboardInfos[name]; return leaderboard; } -exports.fetchLeaderboard = fetchLeaderboard; /** Get the leaderboard positions a member is on. This may take a while depending on whether stuff is cached */ -async function fetchMemberLeaderboardSpots(player, profile) { - var _a; +export async function fetchMemberLeaderboardSpots(player, profile) { const fullProfile = await cached.fetchProfile(player, profile); if (!fullProfile) return null; @@ -364,14 +330,12 @@ async function fetchMemberLeaderboardSpots(player, profile) { name: leaderboardName, positionIndex: leaderboardPositionIndex, value: applicableAttributes[leaderboardName], - unit: (_a = stats_1.getStatUnit(leaderboardName)) !== null && _a !== void 0 ? _a : null + unit: getStatUnit(leaderboardName) ?? null }); } return memberLeaderboardSpots; } -exports.fetchMemberLeaderboardSpots = fetchMemberLeaderboardSpots; async function getLeaderboardRequirement(name, leaderboardType) { - var _a, _b, _c, _d; let leaderboard; if (leaderboardType === 'member') leaderboard = await fetchMemberLeaderboardRaw(name); @@ -379,8 +343,8 @@ async function getLeaderboardRequirement(name, leaderboardType) { leaderboard = await fetchProfileLeaderboardRaw(name); // if there's more than 100 items, return the 100th. if there's less, return null return { - top_100: (_b = (_a = leaderboard[leaderboardMax - 1]) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : null, - top_1: (_d = (_c = leaderboard[1]) === null || _c === void 0 ? void 0 : _c.value) !== null && _d !== void 0 ? _d : null + top_100: leaderboard[leaderboardMax - 1]?.value ?? null, + top_1: leaderboard[1]?.value ?? null }; } /** Get the attributes for the member, but only ones that would put them on the top 100 for leaderboards */ @@ -438,17 +402,17 @@ async function getApplicableProfileLeaderboardAttributes(profile) { return applicableAttributes; } /** Update the member's leaderboard data on the server if applicable */ -async function updateDatabaseMember(member, profile) { +export async function updateDatabaseMember(member, profile) { if (!client) return; // the db client hasn't been initialized - if (_1.debug) + if (debug) console.debug('updateDatabaseMember', member.username); // the member's been updated too recently, just return if (recentlyUpdated.get(profile.uuid + member.uuid)) return; // store the member in recentlyUpdated so it cant update for 3 more minutes recentlyUpdated.set(profile.uuid + member.uuid, true); - if (_1.debug) + if (debug) console.debug('adding member to leaderboards', member.username); if (member.rawHypixelStats) await constants.addStats(Object.keys(member.rawHypixelStats)); @@ -456,10 +420,10 @@ async function updateDatabaseMember(member, profile) { await constants.addSkills(member.skills.map(skill => skill.name)); await constants.addZones(member.visited_zones.map(zone => zone.name)); await constants.addSlayers(member.slayers.bosses.map(s => s.raw_name)); - if (_1.debug) + if (debug) console.debug('done constants..'); const leaderboardAttributes = await getApplicableMemberLeaderboardAttributes(member); - if (_1.debug) + if (debug) console.debug('done getApplicableMemberLeaderboardAttributes..', leaderboardAttributes, member.username, profile.name); await memberLeaderboardsCollection.updateOne({ uuid: member.uuid, @@ -483,30 +447,29 @@ async function updateDatabaseMember(member, profile) { }]) .sort((a, b) => leaderboardReverse ? a.value - b.value : b.value - a.value) .slice(0, 100); - exports.cachedRawLeaderboards.set(attributeName, newRawLeaderboard); + cachedRawLeaderboards.set(attributeName, newRawLeaderboard); } - if (_1.debug) + if (debug) console.debug('added member to leaderboards', member.username, leaderboardAttributes); } -exports.updateDatabaseMember = updateDatabaseMember; /** * Update the profiles's leaderboard data on the server if applicable. * This will not also update the members, you have to call updateDatabaseMember separately for that */ -async function updateDatabaseProfile(profile) { +export async function updateDatabaseProfile(profile) { if (!client) return; // the db client hasn't been initialized - if (_1.debug) + if (debug) console.debug('updateDatabaseProfile', profile.name); // the profile's been updated too recently, just return if (recentlyUpdated.get(profile.uuid + 'profile')) return; // store the profile in recentlyUpdated so it cant update for 3 more minutes recentlyUpdated.set(profile.uuid + 'profile', true); - if (_1.debug) + if (debug) console.debug('adding profile to leaderboards', profile.name); const leaderboardAttributes = await getApplicableProfileLeaderboardAttributes(profile); - if (_1.debug) + if (debug) console.debug('done getApplicableProfileLeaderboardAttributes..', leaderboardAttributes, profile.name); await profileLeaderboardsCollection.updateOne({ uuid: profile.uuid @@ -531,47 +494,44 @@ async function updateDatabaseProfile(profile) { }]) .sort((a, b) => leaderboardReverse ? a.value - b.value : b.value - a.value) .slice(0, 100); - exports.cachedRawLeaderboards.set(attributeName, newRawLeaderboard); + cachedRawLeaderboards.set(attributeName, newRawLeaderboard); } - if (_1.debug) + if (debug) console.debug('added profile to leaderboards', profile.name, leaderboardAttributes); } -exports.updateDatabaseProfile = updateDatabaseProfile; -exports.leaderboardUpdateMemberQueue = new queue_promise_1.default({ +export const leaderboardUpdateMemberQueue = new Queue({ concurrent: 1, interval: 50 }); -exports.leaderboardUpdateProfileQueue = new queue_promise_1.default({ +export const leaderboardUpdateProfileQueue = new Queue({ concurrent: 1, interval: 500 }); /** Queue an update for the member's leaderboard data on the server if applicable */ -function queueUpdateDatabaseMember(member, profile) { +export function queueUpdateDatabaseMember(member, profile) { if (recentlyQueued.get(profile.uuid + member.uuid)) return; else recentlyQueued.set(profile.uuid + member.uuid, true); - exports.leaderboardUpdateMemberQueue.enqueue(async () => await updateDatabaseMember(member, profile)); + leaderboardUpdateMemberQueue.enqueue(async () => await updateDatabaseMember(member, profile)); } -exports.queueUpdateDatabaseMember = queueUpdateDatabaseMember; /** Queue an update for the profile's leaderboard data on the server if applicable */ -function queueUpdateDatabaseProfile(profile) { +export function queueUpdateDatabaseProfile(profile) { if (recentlyQueued.get(profile.uuid + 'profile')) return; else recentlyQueued.set(profile.uuid + 'profile', true); - exports.leaderboardUpdateProfileQueue.enqueue(async () => await updateDatabaseProfile(profile)); + leaderboardUpdateProfileQueue.enqueue(async () => await updateDatabaseProfile(profile)); } -exports.queueUpdateDatabaseProfile = queueUpdateDatabaseProfile; /** * Remove leaderboard attributes for members that wouldn't actually be on the leaderboard. This saves a lot of storage space */ async function removeBadMemberLeaderboardAttributes() { const leaderboards = await fetchAllMemberLeaderboardAttributes(); // shuffle so if the application is restarting many times itll still be useful - for (const leaderboard of util_1.shuffle(leaderboards)) { + for (const leaderboard of shuffle(leaderboards)) { // wait 10 seconds so it doesnt use as much ram - await util_1.sleep(10 * 1000); + await sleep(10 * 1000); const unsetValue = {}; unsetValue[leaderboard] = ''; const filter = {}; @@ -588,19 +548,19 @@ async function removeBadMemberLeaderboardAttributes() { await memberLeaderboardsCollection.deleteMany({ stats: {} }); await profileLeaderboardsCollection.deleteMany({ stats: {} }); } -exports.finishedCachingRawLeaderboards = false; +export let finishedCachingRawLeaderboards = false; /** Fetch all the leaderboards, used for caching. Don't call this often! */ async function fetchAllLeaderboards(fast) { const leaderboards = await fetchAllMemberLeaderboardAttributes(); - if (_1.debug) + if (debug) console.debug('Caching raw leaderboards!'); - for (const leaderboard of util_1.shuffle(leaderboards)) + for (const leaderboard of shuffle(leaderboards)) await fetchMemberLeaderboardRaw(leaderboard); - exports.finishedCachingRawLeaderboards = true; + finishedCachingRawLeaderboards = true; } -async function createSession(refreshToken, userData) { - const sessionId = uuid_1.v4(); - await (sessionsCollection === null || sessionsCollection === void 0 ? void 0 : sessionsCollection.insertOne({ +export async function createSession(refreshToken, userData) { + const sessionId = uuid4(); + await sessionsCollection?.insertOne({ _id: sessionId, refresh_token: refreshToken, discord_user: { @@ -608,29 +568,25 @@ async function createSession(refreshToken, userData) { name: userData.username + '#' + userData.discriminator }, lastUpdated: new Date() - })); + }); return sessionId; } -exports.createSession = createSession; -async function fetchSession(sessionId) { - return await (sessionsCollection === null || sessionsCollection === void 0 ? void 0 : sessionsCollection.findOne({ _id: sessionId })); +export async function fetchSession(sessionId) { + return await sessionsCollection?.findOne({ _id: sessionId }); } -exports.fetchSession = fetchSession; -async function fetchAccount(minecraftUuid) { - return await (accountsCollection === null || accountsCollection === void 0 ? void 0 : accountsCollection.findOne({ minecraftUuid })); +export async function fetchAccount(minecraftUuid) { + return await accountsCollection?.findOne({ minecraftUuid }); } -exports.fetchAccount = fetchAccount; -async function fetchAccountFromDiscord(discordId) { - return await (accountsCollection === null || accountsCollection === void 0 ? void 0 : accountsCollection.findOne({ discordId })); +export async function fetchAccountFromDiscord(discordId) { + return await accountsCollection?.findOne({ discordId }); } -exports.fetchAccountFromDiscord = fetchAccountFromDiscord; -async function updateAccount(discordId, schema) { - await (accountsCollection === null || accountsCollection === void 0 ? void 0 : accountsCollection.updateOne({ +export async function updateAccount(discordId, schema) { + await accountsCollection?.updateOne({ discordId - }, { $set: schema }, { upsert: true })); + }, { $set: schema }, { upsert: true }); } -exports.updateAccount = updateAccount; // make sure it's not in a test +console.log('global.isTest', globalThis.isTest); if (!globalThis.isTest) { connect().then(() => { // when it connects, cache the leaderboards and remove bad members diff --git a/build/discord.js b/build/discord.js index ba9f3eb..ca910b2 100644 --- a/build/discord.js +++ b/build/discord.js @@ -1,16 +1,10 @@ -"use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.getUser = exports.exchangeCode = void 0; -const node_fetch_1 = __importDefault(require("node-fetch")); -const https_1 = require("https"); +import fetch from 'node-fetch'; +import { Agent } from 'https'; const DISCORD_CLIENT_ID = '656634948148527107'; -const httpsAgent = new https_1.Agent({ +const httpsAgent = new Agent({ keepAlive: true }); -async function exchangeCode(redirectUri, code) { +export async function exchangeCode(redirectUri, code) { const API_ENDPOINT = 'https://discord.com/api/v6'; const CLIENT_SECRET = process.env.discord_client_secret; if (!CLIENT_SECRET) { @@ -25,7 +19,7 @@ async function exchangeCode(redirectUri, code) { 'redirect_uri': redirectUri, 'scope': 'identify' }; - const fetchResponse = await node_fetch_1.default(API_ENDPOINT + '/oauth2/token', { + const fetchResponse = await fetch(API_ENDPOINT + '/oauth2/token', { method: 'POST', agent: () => httpsAgent, headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, @@ -33,13 +27,11 @@ async function exchangeCode(redirectUri, code) { }); return await fetchResponse.json(); } -exports.exchangeCode = exchangeCode; -async function getUser(accessToken) { +export async function getUser(accessToken) { const API_ENDPOINT = 'https://discord.com/api/v6'; - const response = await node_fetch_1.default(API_ENDPOINT + '/users/@me', { + const response = await fetch(API_ENDPOINT + '/users/@me', { headers: { 'Authorization': 'Bearer ' + accessToken }, agent: () => httpsAgent, }); - return response.json(); + return await response.json(); } -exports.getUser = getUser; diff --git a/build/hypixel.js b/build/hypixel.js index 414139e..6a1a916 100644 --- a/build/hypixel.js +++ b/build/hypixel.js @@ -1,58 +1,35 @@ -"use strict"; /** * Fetch the clean Hypixel API */ -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.fetchMemberProfilesUncached = exports.fetchBasicProfileFromUuidUncached = exports.fetchMemberProfileUncached = exports.fetchMemberProfile = exports.fetchUser = exports.sendCleanApiRequest = exports.maxMinion = exports.saveInterval = void 0; -const profile_1 = require("./cleaners/skyblock/profile"); -const database_1 = require("./database"); -const hypixelApi_1 = require("./hypixelApi"); -const profiles_1 = require("./cleaners/skyblock/profiles"); -const player_1 = require("./cleaners/player"); -const cached = __importStar(require("./hypixelCached")); -const _1 = require("."); +import { cleanSkyblockProfileResponse } from './cleaners/skyblock/profile.js'; +import { fetchAccount, queueUpdateDatabaseMember, queueUpdateDatabaseProfile } from './database.js'; +import { chooseApiKey, sendApiRequest } from './hypixelApi.js'; +import { cleanSkyblockProfilesResponse } from './cleaners/skyblock/profiles.js'; +import { cleanPlayerResponse } from './cleaners/player.js'; +import * as cached from './hypixelCached.js'; +import { debug } from './index.js'; // the interval at which the "last_save" parameter updates in the hypixel api, this is 3 minutes -exports.saveInterval = 60 * 3 * 1000; +export const saveInterval = 60 * 3 * 1000; // the highest level a minion can be -exports.maxMinion = 11; +export const maxMinion = 11; /** Sends an API request to Hypixel and cleans it up. */ -async function sendCleanApiRequest({ path, args }, included, options) { - const key = await hypixelApi_1.chooseApiKey(); - const rawResponse = await hypixelApi_1.sendApiRequest({ path, key, args }); +export async function sendCleanApiRequest({ path, args }, included, options) { + const key = await chooseApiKey(); + const rawResponse = await sendApiRequest({ path, key, args }); if (rawResponse.throttled) { // if it's throttled, wait a second and try again await new Promise(resolve => setTimeout(resolve, 1000)); return await sendCleanApiRequest({ path, args }, included, options); } // clean the response - return await cleanResponse({ path, data: rawResponse }, options !== null && options !== void 0 ? options : {}); + return await cleanResponse({ path, data: rawResponse }, options ?? {}); } -exports.sendCleanApiRequest = sendCleanApiRequest; async function cleanResponse({ path, data }, options) { // Cleans up an api response switch (path) { - case 'player': return await player_1.cleanPlayerResponse(data.player); - case 'skyblock/profile': return await profile_1.cleanSkyblockProfileResponse(data.profile, options); - case 'skyblock/profiles': return await profiles_1.cleanSkyblockProfilesResponse(data.profiles); + case 'player': return await cleanPlayerResponse(data.player); + case 'skyblock/profile': return await cleanSkyblockProfileResponse(data.profile, options); + case 'skyblock/profiles': return await cleanSkyblockProfilesResponse(data.profiles); } } /** @@ -61,21 +38,20 @@ async function cleanResponse({ path, data }, options) { * @param included lets you choose what is returned, so there's less processing required on the backend * used inclusions: player, profiles */ -async function fetchUser({ user, uuid, username }, included = ['player'], customization) { - var _a, _b; +export async function fetchUser({ user, uuid, username }, included = ['player'], customization) { if (!uuid) { // If the uuid isn't provided, get it if (!username && !user) return null; - uuid = await cached.uuidFromUser((user !== null && user !== void 0 ? user : username)); + uuid = await cached.uuidFromUser((user ?? username)); } if (!uuid) { // the user doesn't exist. - if (_1.debug) + if (debug) console.debug('error:', user, 'doesnt exist'); return null; } - const websiteAccountPromise = customization ? database_1.fetchAccount(uuid) : null; + const websiteAccountPromise = customization ? fetchAccount(uuid) : null; const includePlayers = included.includes('player'); const includeProfiles = included.includes('profiles'); let profilesData; @@ -85,7 +61,7 @@ async function fetchUser({ user, uuid, username }, included = ['player'], custom playerData = await cached.fetchPlayer(uuid); // if not including profiles, include lightweight profiles just in case if (!includeProfiles) - basicProfilesData = playerData === null || playerData === void 0 ? void 0 : playerData.profiles; + basicProfilesData = playerData?.profiles; if (playerData) delete playerData.profiles; } @@ -95,7 +71,7 @@ async function fetchUser({ user, uuid, username }, included = ['player'], custom let lastOnline = 0; if (includeProfiles) { for (const profile of profilesData) { - const member = (_a = profile.members) === null || _a === void 0 ? void 0 : _a.find(member => member.uuid === uuid); + const member = profile.members?.find(member => member.uuid === uuid); if (member && member.last_save > lastOnline) { lastOnline = member.last_save; activeProfile = profile; @@ -107,13 +83,12 @@ async function fetchUser({ user, uuid, username }, included = ['player'], custom websiteAccount = await websiteAccountPromise; return { player: playerData, - profiles: profilesData !== null && profilesData !== void 0 ? profilesData : basicProfilesData, - activeProfile: includeProfiles ? (_b = activeProfile) === null || _b === void 0 ? void 0 : _b.uuid : undefined, - online: includeProfiles ? lastOnline > (Date.now() - exports.saveInterval) : undefined, - customization: websiteAccount === null || websiteAccount === void 0 ? void 0 : websiteAccount.customization + profiles: profilesData ?? basicProfilesData, + activeProfile: includeProfiles ? activeProfile?.uuid : undefined, + online: includeProfiles ? lastOnline > (Date.now() - saveInterval) : undefined, + customization: websiteAccount?.customization }; } -exports.fetchUser = fetchUser; /** * Fetch a CleanMemberProfile from a user and string * This is safe to use many times as the results are cached! @@ -121,12 +96,12 @@ exports.fetchUser = fetchUser; * @param profile A profile name or profile uuid * @param customization Whether stuff like the user's custom background will be returned */ -async function fetchMemberProfile(user, profile, customization) { +export async function fetchMemberProfile(user, profile, customization) { const playerUuid = await cached.uuidFromUser(user); if (!playerUuid) return null; // we don't await the promise immediately so it can load while we do other stuff - const websiteAccountPromise = customization ? database_1.fetchAccount(playerUuid) : null; + const websiteAccountPromise = customization ? fetchAccount(playerUuid) : null; const profileUuid = await cached.fetchProfileUuid(user, profile); // if the profile or player doesn't have an id, just return if (!profileUuid) @@ -164,41 +139,38 @@ async function fetchMemberProfile(user, profile, customization) { ...player }, profile: cleanProfile, - customization: websiteAccount === null || websiteAccount === void 0 ? void 0 : websiteAccount.customization + customization: websiteAccount?.customization }; } -exports.fetchMemberProfile = fetchMemberProfile; /** * Fetches the Hypixel API to get a CleanFullProfile. This doesn't do any caching and you should use hypixelCached.fetchProfile instead * @param playerUuid The UUID of the Minecraft player * @param profileUuid The UUID of the Hypixel SkyBlock profile */ -async function fetchMemberProfileUncached(playerUuid, profileUuid) { +export async function fetchMemberProfileUncached(playerUuid, profileUuid) { const profile = await sendCleanApiRequest({ path: 'skyblock/profile', args: { profile: profileUuid } }, undefined, { mainMemberUuid: playerUuid }); // queue updating the leaderboard positions for the member, eventually for (const member of profile.members) - database_1.queueUpdateDatabaseMember(member, profile); - database_1.queueUpdateDatabaseProfile(profile); + queueUpdateDatabaseMember(member, profile); + queueUpdateDatabaseProfile(profile); return profile; } -exports.fetchMemberProfileUncached = fetchMemberProfileUncached; /** * Fetches the Hypixel API to get a CleanProfile from its id. This doesn't do any caching and you should use hypixelCached.fetchBasicProfileFromUuid instead * @param playerUuid The UUID of the Minecraft player * @param profileUuid The UUID of the Hypixel SkyBlock profile */ -async function fetchBasicProfileFromUuidUncached(profileUuid) { +export async function fetchBasicProfileFromUuidUncached(profileUuid) { const profile = await sendCleanApiRequest({ path: 'skyblock/profile', args: { profile: profileUuid } }, undefined, { basic: true }); return profile; } -exports.fetchBasicProfileFromUuidUncached = fetchBasicProfileFromUuidUncached; -async function fetchMemberProfilesUncached(playerUuid) { +export async function fetchMemberProfilesUncached(playerUuid) { const profiles = await sendCleanApiRequest({ path: 'skyblock/profiles', args: { @@ -210,10 +182,9 @@ async function fetchMemberProfilesUncached(playerUuid) { }); for (const profile of profiles) { for (const member of profile.members) { - database_1.queueUpdateDatabaseMember(member, profile); + queueUpdateDatabaseMember(member, profile); } - database_1.queueUpdateDatabaseProfile(profile); + queueUpdateDatabaseProfile(profile); } return profiles; } -exports.fetchMemberProfilesUncached = fetchMemberProfilesUncached; diff --git a/build/hypixelApi.js b/build/hypixelApi.js index a35dd64..da1be16 100644 --- a/build/hypixelApi.js +++ b/build/hypixelApi.js @@ -1,33 +1,26 @@ -"use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -var _a, _b, _c; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.sendApiRequest = exports.getKeyUsage = exports.chooseApiKey = void 0; /** * Fetch the raw Hypixel API */ -const node_fetch_1 = __importDefault(require("node-fetch")); -const util_1 = require("./util"); -const https_1 = require("https"); +import fetch from 'node-fetch'; +import { jsonToQuery, shuffle } from './util.js'; +import { Agent } from 'https'; if (!process.env.hypixel_keys) // if there's no hypixel keys in env, run dotenv - require('dotenv').config(); + (await import('dotenv')).config(); // We need to create an agent to prevent memory leaks and to only do dns lookups once -const httpsAgent = new https_1.Agent({ +const httpsAgent = new Agent({ keepAlive: true }); /** This array should only ever contain one item because using multiple hypixel api keys isn't allowed :) */ -const apiKeys = (_c = (_b = (_a = process.env) === null || _a === void 0 ? void 0 : _a.hypixel_keys) === null || _b === void 0 ? void 0 : _b.split(' ')) !== null && _c !== void 0 ? _c : []; +const apiKeys = process.env?.hypixel_keys?.split(' ') ?? []; const apiKeyUsage = {}; const baseHypixelAPI = 'https://api.hypixel.net'; /** Choose the best current API key */ -function chooseApiKey() { +export function chooseApiKey() { // find the api key with the lowest amount of uses let bestKeyUsage = null; let bestKey = null; - for (let key of util_1.shuffle(apiKeys.slice())) { + for (let key of shuffle(apiKeys.slice())) { const keyUsage = apiKeyUsage[key]; // if the key has never been used before, use it if (!keyUsage) @@ -43,8 +36,7 @@ function chooseApiKey() { } return bestKey; } -exports.chooseApiKey = chooseApiKey; -function getKeyUsage() { +export function getKeyUsage() { let keyLimit = 0; let keyUsage = 0; for (let key of Object.values(apiKeyUsage)) { @@ -56,20 +48,18 @@ function getKeyUsage() { usage: keyUsage }; } -exports.getKeyUsage = getKeyUsage; /** Send an HTTP request to the Hypixel API */ -async function sendApiRequest({ path, key, args }) { +export let sendApiRequest = async function sendApiRequest({ path, key, args }) { // Send a raw http request to api.hypixel.net, and return the parsed json - var _a, _b, _c; if (key) // If there's an api key, add it to the arguments args.key = key; // Construct a url from the base api url, path, and arguments - const fetchUrl = baseHypixelAPI + '/' + path + '?' + util_1.jsonToQuery(args); + const fetchUrl = baseHypixelAPI + '/' + path + '?' + jsonToQuery(args); let fetchResponse; let fetchJsonParsed; try { - fetchResponse = await node_fetch_1.default(fetchUrl, { agent: () => httpsAgent }); + fetchResponse = await fetch(fetchUrl, { agent: () => httpsAgent }); fetchJsonParsed = await fetchResponse.json(); } catch { @@ -85,9 +75,9 @@ async function sendApiRequest({ path, key, args }) { if (fetchResponse.headers.get('ratelimit-limit')) // remember how many uses it has apiKeyUsage[key] = { - remaining: parseInt((_a = fetchResponse.headers.get('ratelimit-remaining')) !== null && _a !== void 0 ? _a : '0'), - limit: parseInt((_b = fetchResponse.headers.get('ratelimit-limit')) !== null && _b !== void 0 ? _b : '0'), - reset: Date.now() + parseInt((_c = fetchResponse.headers.get('ratelimit-reset')) !== null && _c !== void 0 ? _c : '0') * 1000 + remaining: parseInt(fetchResponse.headers.get('ratelimit-remaining') ?? '0'), + limit: parseInt(fetchResponse.headers.get('ratelimit-limit') ?? '0'), + reset: Date.now() + parseInt(fetchResponse.headers.get('ratelimit-reset') ?? '0') * 1000 }; if (fetchJsonParsed.throttle) { if (apiKeyUsage[key]) @@ -97,5 +87,6 @@ async function sendApiRequest({ path, key, args }) { return await sendApiRequest({ path, key, args }); } return fetchJsonParsed; -} -exports.sendApiRequest = sendApiRequest; +}; +// this is necessary for mocking in the tests because es6 +export function mockSendApiRequest($value) { sendApiRequest = $value; } diff --git a/build/hypixelCached.js b/build/hypixelCached.js index b03361f..69bcc62 100644 --- a/build/hypixelCached.js +++ b/build/hypixelCached.js @@ -1,72 +1,47 @@ -"use strict"; /** * Fetch the clean and cached Hypixel API */ -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.fetchProfileName = exports.fetchBasicProfileFromUuid = exports.fetchProfile = exports.fetchProfileUuid = exports.fetchSkyblockProfiles = exports.fetchBasicPlayer = exports.fetchPlayer = exports.usernameFromUser = exports.uuidFromUser = exports.profileNameCache = exports.profilesCache = exports.profileCache = exports.basicPlayerCache = exports.playerCache = exports.basicProfilesCache = exports.usernameCache = void 0; -const node_cache_1 = __importDefault(require("node-cache")); -const lru_cache_1 = __importDefault(require("lru-cache")); -const mojang = __importStar(require("./mojang")); -const hypixel = __importStar(require("./hypixel")); -const util_1 = require("./util"); -const _1 = require("."); +import { isUuid, undashUuid } from './util.js'; +import * as hypixel from './hypixel.js'; +import * as mojang from './mojang.js'; +import NodeCache from 'node-cache'; +import { debug } from './index.js'; +import LRUCache from 'lru-cache'; // cache usernames for 30 minutes /** uuid: username */ -exports.usernameCache = new node_cache_1.default({ +export const usernameCache = new NodeCache({ // stdTTL: 60 * 60 * 4, stdTTL: 60 * 30, checkperiod: 60, useClones: false, }); -exports.usernameCache.setMaxListeners(50); -exports.basicProfilesCache = new node_cache_1.default({ +usernameCache.setMaxListeners(50); +export const basicProfilesCache = new NodeCache({ stdTTL: 60 * 10, checkperiod: 60, useClones: true, }); -exports.playerCache = new node_cache_1.default({ +export const playerCache = new NodeCache({ stdTTL: 60, checkperiod: 10, useClones: true, }); // cache "basic players" (players without profiles) for 20 minutes -exports.basicPlayerCache = new lru_cache_1.default({ +export const basicPlayerCache = new LRUCache({ max: 10000, maxAge: 60 * 20 * 1000, }); -exports.profileCache = new node_cache_1.default({ +export const profileCache = new NodeCache({ stdTTL: 30, checkperiod: 10, useClones: true, }); -exports.profilesCache = new node_cache_1.default({ +export const profilesCache = new NodeCache({ stdTTL: 60 * 3, checkperiod: 10, useClones: false, }); -exports.profileNameCache = new node_cache_1.default({ +export const profileNameCache = new NodeCache({ stdTTL: 60 * 60, checkperiod: 60, useClones: false, @@ -86,77 +61,74 @@ function waitForCacheSet(cache, key, value) { * Fetch the uuid from a user * @param user A user can be either a uuid or a username */ -async function uuidFromUser(user) { +export async function uuidFromUser(user) { // if the user is 32 characters long, it has to be a uuid - if (util_1.isUuid(user)) - return util_1.undashUuid(user); - if (exports.usernameCache.has(util_1.undashUuid(user))) { + if (isUuid(user)) + return undashUuid(user); + if (usernameCache.has(undashUuid(user))) { // check if the uuid is a key - const username = exports.usernameCache.get(util_1.undashUuid(user)); + const username = usernameCache.get(undashUuid(user)); // sometimes the username will be null, return that if (username === null) return undefined; // if it has .then, then that means its a waitForCacheSet promise. This is done to prevent requests made while it is already requesting if (username.then) { const { key: uuid, value: _username } = await username; - exports.usernameCache.set(uuid, _username); + usernameCache.set(uuid, _username); return uuid; } else - return util_1.undashUuid(user); + return undashUuid(user); } // check if the username is a value - const uuidToUsername = exports.usernameCache.mget(exports.usernameCache.keys()); + const uuidToUsername = usernameCache.mget(usernameCache.keys()); for (const [uuid, username] of Object.entries(uuidToUsername)) { if (username && username.toLowerCase && user.toLowerCase() === username.toLowerCase()) return uuid; } - if (_1.debug) + if (debug) console.debug('Cache miss: uuidFromUser', user); - const undashedUser = util_1.undashUuid(user); + const undashedUser = undashUuid(user); // set it as waitForCacheSet (a promise) in case uuidFromUser gets called while its fetching mojang - exports.usernameCache.set(undashedUser, waitForCacheSet(exports.usernameCache, user, user)); + usernameCache.set(undashedUser, waitForCacheSet(usernameCache, user, user)); // not cached, actually fetch mojang api now let { uuid, username } = await mojang.profileFromUser(user); if (!uuid) { - exports.usernameCache.set(user, null); + usernameCache.set(user, null); return; } // remove dashes from the uuid so its more normal - uuid = util_1.undashUuid(uuid); - exports.usernameCache.del(undashedUser); - exports.usernameCache.set(uuid, username); + uuid = undashUuid(uuid); + usernameCache.del(undashedUser); + usernameCache.set(uuid, username); return uuid; } -exports.uuidFromUser = uuidFromUser; /** * Fetch the username from a user * @param user A user can be either a uuid or a username */ -async function usernameFromUser(user) { - var _a; - if (exports.usernameCache.has(util_1.undashUuid(user))) { - if (_1.debug) +export async function usernameFromUser(user) { + if (usernameCache.has(undashUuid(user))) { + if (debug) console.debug('Cache hit! usernameFromUser', user); - return (_a = exports.usernameCache.get(util_1.undashUuid(user))) !== null && _a !== void 0 ? _a : null; + return usernameCache.get(undashUuid(user)) ?? null; } - if (_1.debug) + if (debug) console.debug('Cache miss: usernameFromUser', user); let { uuid, username } = await mojang.profileFromUser(user); if (!uuid) return null; - uuid = util_1.undashUuid(uuid); - exports.usernameCache.set(uuid, username); + uuid = undashUuid(uuid); + usernameCache.set(uuid, username); return username; } -exports.usernameFromUser = usernameFromUser; let fetchingPlayers = new Set(); -async function fetchPlayer(user) { +export async function fetchPlayer(user) { const playerUuid = await uuidFromUser(user); if (!playerUuid) return null; - if (exports.playerCache.has(playerUuid)) - return exports.playerCache.get(playerUuid); + if (playerCache.has(playerUuid)) + return playerCache.get(playerUuid); // if it's already in the process of fetching, check every 100ms until it's not fetching the player anymore and fetch it again, since it'll be cached now if (fetchingPlayers.has(playerUuid)) { while (fetchingPlayers.has(playerUuid)) { @@ -173,21 +145,20 @@ async function fetchPlayer(user) { if (!cleanPlayer) return null; // clone in case it gets modified somehow later - exports.playerCache.set(playerUuid, cleanPlayer); - exports.usernameCache.set(playerUuid, cleanPlayer.username); + playerCache.set(playerUuid, cleanPlayer); + usernameCache.set(playerUuid, cleanPlayer.username); const cleanBasicPlayer = Object.assign({}, cleanPlayer); delete cleanBasicPlayer.profiles; - exports.basicPlayerCache.set(playerUuid, cleanBasicPlayer); + basicPlayerCache.set(playerUuid, cleanBasicPlayer); return cleanPlayer; } -exports.fetchPlayer = fetchPlayer; /** Fetch a player without their profiles. This is heavily cached. */ -async function fetchBasicPlayer(user) { +export async function fetchBasicPlayer(user) { const playerUuid = await uuidFromUser(user); if (!playerUuid) return null; - if (exports.basicPlayerCache.has(playerUuid)) - return exports.basicPlayerCache.get(playerUuid); + if (basicPlayerCache.has(playerUuid)) + return basicPlayerCache.get(playerUuid); const player = await fetchPlayer(playerUuid); if (!player) { console.debug('no player? this should never happen, perhaps the uuid is invalid or the player hasn\'t played hypixel', playerUuid); @@ -196,15 +167,13 @@ async function fetchBasicPlayer(user) { delete player.profiles; return player; } -exports.fetchBasicPlayer = fetchBasicPlayer; -async function fetchSkyblockProfiles(playerUuid) { - var _a; - if (exports.profilesCache.has(playerUuid)) { - if (_1.debug) +export async function fetchSkyblockProfiles(playerUuid) { + if (profilesCache.has(playerUuid)) { + if (debug) console.debug('Cache hit! fetchSkyblockProfiles', playerUuid); - return exports.profilesCache.get(playerUuid); + return profilesCache.get(playerUuid); } - if (_1.debug) + if (debug) console.debug('Cache miss: fetchSkyblockProfiles', playerUuid); const profiles = await hypixel.fetchMemberProfilesUncached(playerUuid); const basicProfiles = []; @@ -213,7 +182,7 @@ async function fetchSkyblockProfiles(playerUuid) { const basicProfile = { name: profile.name, uuid: profile.uuid, - members: (_a = profile.members) === null || _a === void 0 ? void 0 : _a.map(m => { + members: profile.members?.map(m => { return { uuid: m.uuid, username: m.username, @@ -226,21 +195,20 @@ async function fetchSkyblockProfiles(playerUuid) { basicProfiles.push(basicProfile); } // cache the profiles - exports.profilesCache.set(playerUuid, basicProfiles); + profilesCache.set(playerUuid, basicProfiles); return basicProfiles; } -exports.fetchSkyblockProfiles = fetchSkyblockProfiles; /** Fetch an array of `BasicProfile`s */ async function fetchBasicProfiles(user) { const playerUuid = await uuidFromUser(user); if (!playerUuid) return null; // invalid player, just return - if (exports.basicProfilesCache.has(playerUuid)) { - if (_1.debug) + if (basicProfilesCache.has(playerUuid)) { + if (debug) console.debug('Cache hit! fetchBasicProfiles', playerUuid); - return exports.basicProfilesCache.get(playerUuid); + return basicProfilesCache.get(playerUuid); } - if (_1.debug) + if (debug) console.debug('Cache miss: fetchBasicProfiles', user); const player = await fetchPlayer(playerUuid); if (!player) { @@ -248,12 +216,12 @@ async function fetchBasicProfiles(user) { return []; } const profiles = player.profiles; - exports.basicProfilesCache.set(playerUuid, profiles); + basicProfilesCache.set(playerUuid, profiles); if (!profiles) return null; // cache the profile names and uuids to profileNameCache because we can for (const profile of profiles) - exports.profileNameCache.set(`${playerUuid}.${profile.uuid}`, profile.name); + profileNameCache.set(`${playerUuid}.${profile.uuid}`, profile.name); return profiles; } /** @@ -261,48 +229,46 @@ async function fetchBasicProfiles(user) { * @param user A username or uuid * @param profile A profile name or profile uuid */ -async function fetchProfileUuid(user, profile) { - var _a; +export async function fetchProfileUuid(user, profile) { // if a profile wasn't provided, return if (!profile) { - if (_1.debug) + if (debug) console.debug('no profile provided?', user, profile); return null; } - if (_1.debug) + if (debug) console.debug('Cache miss: fetchProfileUuid', user, profile); const profiles = await fetchBasicProfiles(user); if (!profiles) return null; // user probably doesnt exist - const profileUuid = util_1.undashUuid(profile); + const profileUuid = undashUuid(profile); for (const p of profiles) { - if (((_a = p.name) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === profileUuid.toLowerCase()) - return util_1.undashUuid(p.uuid); - else if (util_1.undashUuid(p.uuid) === util_1.undashUuid(profileUuid)) - return util_1.undashUuid(p.uuid); + if (p.name?.toLowerCase() === profileUuid.toLowerCase()) + return undashUuid(p.uuid); + else if (undashUuid(p.uuid) === undashUuid(profileUuid)) + return undashUuid(p.uuid); } return null; } -exports.fetchProfileUuid = fetchProfileUuid; /** * Fetch an entire profile from the user and profile data * @param user A username or uuid * @param profile A profile name or profile uuid */ -async function fetchProfile(user, profile) { +export async function fetchProfile(user, profile) { const playerUuid = await uuidFromUser(user); if (!playerUuid) return null; const profileUuid = await fetchProfileUuid(playerUuid, profile); if (!profileUuid) return null; - if (exports.profileCache.has(profileUuid)) { + if (profileCache.has(profileUuid)) { // we have the profile cached, return it :) - if (_1.debug) + if (debug) console.debug('Cache hit! fetchProfile', profileUuid); - return exports.profileCache.get(profileUuid); + return profileCache.get(profileUuid); } - if (_1.debug) + if (debug) console.debug('Cache miss: fetchProfile', user, profile); const profileName = await fetchProfileName(user, profile); if (!profileName) @@ -310,20 +276,19 @@ async function fetchProfile(user, profile) { const cleanProfile = await hypixel.fetchMemberProfileUncached(playerUuid, profileUuid); // we know the name from fetchProfileName, so set it here cleanProfile.name = profileName; - exports.profileCache.set(profileUuid, cleanProfile); + profileCache.set(profileUuid, cleanProfile); return cleanProfile; } -exports.fetchProfile = fetchProfile; /** * Fetch a CleanProfile from the uuid * @param profileUuid A profile name or profile uuid */ -async function fetchBasicProfileFromUuid(profileUuid) { - if (exports.profileCache.has(profileUuid)) { +export async function fetchBasicProfileFromUuid(profileUuid) { + if (profileCache.has(profileUuid)) { // we have the profile cached, return it :) - if (_1.debug) + if (debug) console.debug('Cache hit! fetchBasicProfileFromUuid', profileUuid); - const profile = exports.profileCache.get(profileUuid); + const profile = profileCache.get(profileUuid); if (!profile) return undefined; return { @@ -341,14 +306,12 @@ async function fetchBasicProfileFromUuid(profileUuid) { // TODO: cache this return await hypixel.fetchBasicProfileFromUuidUncached(profileUuid); } -exports.fetchBasicProfileFromUuid = fetchBasicProfileFromUuid; /** * Fetch the name of a profile from the user and profile uuid * @param user A player uuid or username * @param profile A profile uuid or name */ -async function fetchProfileName(user, profile) { - var _a, _b; +export async function fetchProfileName(user, profile) { // we're fetching the profile and player uuid again in case we were given a name, but it's cached so it's not much of a problem const profileUuid = await fetchProfileUuid(user, profile); if (!profileUuid) @@ -356,13 +319,13 @@ async function fetchProfileName(user, profile) { const playerUuid = await uuidFromUser(user); if (!playerUuid) return null; - if (exports.profileNameCache.has(`${playerUuid}.${profileUuid}`)) { + if (profileNameCache.has(`${playerUuid}.${profileUuid}`)) { // Return the profile name if it's cached - if (_1.debug) + if (debug) console.debug('Cache hit! fetchProfileName', profileUuid); - return (_a = exports.profileNameCache.get(`${playerUuid}.${profileUuid}`)) !== null && _a !== void 0 ? _a : null; + return profileNameCache.get(`${playerUuid}.${profileUuid}`) ?? null; } - if (_1.debug) + if (debug) console.debug('Cache miss: fetchProfileName', user, profile); const basicProfiles = await fetchBasicProfiles(playerUuid); if (!basicProfiles) @@ -370,8 +333,7 @@ async function fetchProfileName(user, profile) { let profileName = null; for (const basicProfile of basicProfiles) if (basicProfile.uuid === playerUuid) - profileName = (_b = basicProfile.name) !== null && _b !== void 0 ? _b : null; - exports.profileNameCache.set(`${playerUuid}.${profileUuid}`, profileName); + profileName = basicProfile.name ?? null; + profileNameCache.set(`${playerUuid}.${profileUuid}`, profileName); return profileName; } -exports.fetchProfileName = fetchProfileName; diff --git a/build/index.js b/build/index.js index 8bb2040..8521a1c 100644 --- a/build/index.js +++ b/build/index.js @@ -1,51 +1,25 @@ -"use strict"; -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { - Object.defineProperty(o, "default", { enumerable: true, value: v }); -}) : function(o, v) { - o["default"] = v; -}); -var __importStar = (this && this.__importStar) || function (mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - __setModuleDefault(result, mod); - return result; -}; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.debug = void 0; -const database_1 = require("./database"); -const hypixel_1 = require("./hypixel"); -const express_rate_limit_1 = __importDefault(require("express-rate-limit")); -const constants = __importStar(require("./constants")); -const discord = __importStar(require("./discord")); -const express_1 = __importDefault(require("express")); -const app = express_1.default(); -exports.debug = false; +import { createSession, fetchAccountFromDiscord, fetchAllLeaderboardsCategorized, fetchLeaderboard, fetchMemberLeaderboardSpots, fetchSession, finishedCachingRawLeaderboards, leaderboardUpdateMemberQueue, leaderboardUpdateProfileQueue, updateAccount } from './database.js'; +import { fetchMemberProfile, fetchUser } from './hypixel.js'; +import rateLimit from 'express-rate-limit'; +import * as constants from './constants.js'; +import * as discord from './discord.js'; +import express from 'express'; +const app = express(); +export const debug = false; const mainSiteUrl = 'https://skyblock.matdoes.dev'; // 200 requests over 5 minutes -const limiter = express_rate_limit_1.default({ +const limiter = rateLimit({ windowMs: 60 * 1000 * 5, max: 200, skip: (req) => { return req.headers.key === process.env.key; }, keyGenerator: (req) => { - var _a; - return ((_a = req.headers['cf-connecting-ip']) !== null && _a !== void 0 ? _a : req.ip).toString(); + return (req.headers['cf-connecting-ip'] ?? req.ip).toString(); } }); app.use(limiter); -app.use(express_1.default.json()); +app.use(express.json()); app.use((req, res, next) => { res.setHeader('Access-Control-Allow-Origin', '*'); next(); @@ -56,15 +30,15 @@ app.get('/', async (req, res) => { res.json({ ok: true, uptimeHours: (currentTime - startTime) / 1000 / 60 / 60, - finishedCachingRawLeaderboards: database_1.finishedCachingRawLeaderboards, - leaderboardUpdateMemberQueueSize: database_1.leaderboardUpdateMemberQueue.size, - leaderboardUpdateProfileQueueSize: database_1.leaderboardUpdateProfileQueue.size, + finishedCachingRawLeaderboards, + leaderboardUpdateMemberQueueSize: leaderboardUpdateMemberQueue.size, + leaderboardUpdateProfileQueueSize: leaderboardUpdateProfileQueue.size, // key: getKeyUsage() }); }); app.get('/player/:user', async (req, res) => { try { - const user = await hypixel_1.fetchUser({ user: req.params.user }, [req.query.basic === 'true' ? undefined : 'profiles', 'player'], req.query.customization === 'true'); + const user = await fetchUser({ user: req.params.user }, [req.query.basic === 'true' ? undefined : 'profiles', 'player'], req.query.customization === 'true'); if (user) res.json(user); else @@ -77,7 +51,7 @@ app.get('/player/:user', async (req, res) => { }); app.get('/discord/:id', async (req, res) => { try { - res.json(await database_1.fetchAccountFromDiscord(req.params.id)); + res.json(await fetchAccountFromDiscord(req.params.id)); } catch (err) { console.error(err); @@ -86,7 +60,7 @@ app.get('/discord/:id', async (req, res) => { }); app.get('/player/:user/:profile', async (req, res) => { try { - const profile = await hypixel_1.fetchMemberProfile(req.params.user, req.params.profile, req.query.customization === 'true'); + const profile = await fetchMemberProfile(req.params.user, req.params.profile, req.query.customization === 'true'); if (profile) res.json(profile); else @@ -99,7 +73,7 @@ app.get('/player/:user/:profile', async (req, res) => { }); app.get('/player/:user/:profile/leaderboards', async (req, res) => { try { - res.json(await database_1.fetchMemberLeaderboardSpots(req.params.user, req.params.profile)); + res.json(await fetchMemberLeaderboardSpots(req.params.user, req.params.profile)); } catch (err) { console.error(err); @@ -108,7 +82,7 @@ app.get('/player/:user/:profile/leaderboards', async (req, res) => { }); app.get('/leaderboard/:name', async (req, res) => { try { - res.json(await database_1.fetchLeaderboard(req.params.name)); + res.json(await fetchLeaderboard(req.params.name)); } catch (err) { console.error(err); @@ -117,7 +91,7 @@ app.get('/leaderboard/:name', async (req, res) => { }); app.get('/leaderboards', async (req, res) => { try { - res.json(await database_1.fetchAllLeaderboardsCategorized()); + res.json(await fetchAllLeaderboardsCategorized()); } catch (err) { console.error(err); @@ -146,7 +120,7 @@ app.post('/accounts/createsession', async (req, res) => { // access token is invalid :( return res.json({ ok: false }); const userData = await discord.getUser(accessToken); - const sessionId = await database_1.createSession(refreshToken, userData); + const sessionId = await createSession(refreshToken, userData); res.json({ ok: true, session_id: sessionId }); } catch (err) { @@ -156,10 +130,10 @@ app.post('/accounts/createsession', async (req, res) => { app.post('/accounts/session', async (req, res) => { try { const { uuid } = req.body; - const session = await database_1.fetchSession(uuid); + const session = await fetchSession(uuid); if (!session) return res.json({ ok: false }); - const account = await database_1.fetchAccountFromDiscord(session.discord_user.id); + const account = await fetchAccountFromDiscord(session.discord_user.id); res.json({ session, account }); } catch (err) { @@ -172,7 +146,7 @@ app.post('/accounts/update', async (req, res) => { if (req.headers.key !== process.env.key) return console.log('bad key!'); try { - await database_1.updateAccount(req.body.discordId, req.body); + await updateAccount(req.body.discordId, req.body); res.json({ ok: true }); } catch (err) { diff --git a/build/mojang.js b/build/mojang.js index 2d2f694..7682839 100644 --- a/build/mojang.js +++ b/build/mojang.js @@ -1,28 +1,22 @@ -"use strict"; /** * Fetch the Mojang username API through api.ashcon.app */ -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.profileFromUser = exports.profileFromUsernameAlternative = exports.profileFromUsername = exports.profileFromUuid = void 0; -const node_fetch_1 = __importDefault(require("node-fetch")); -const https_1 = require("https"); -const util_1 = require("./util"); +import { isUuid, undashUuid } from './util.js'; +import fetch from 'node-fetch'; +import { Agent } from 'https'; // We need to create an agent to prevent memory leaks -const httpsAgent = new https_1.Agent({ +const httpsAgent = new Agent({ keepAlive: true }); /** * Get mojang api data from the session server */ -async function profileFromUuid(uuid) { +export let profileFromUuid = async function profileFromUuid(uuid) { let fetchResponse; try { - fetchResponse = await node_fetch_1.default( + fetchResponse = await fetch( // using mojang directly is faster than ashcon lol, also mojang removed the ratelimits from here - `https://sessionserver.mojang.com/session/minecraft/profile/${util_1.undashUuid(uuid)}`, { agent: () => httpsAgent }); + `https://sessionserver.mojang.com/session/minecraft/profile/${undashUuid(uuid)}`, { agent: () => httpsAgent }); } catch { // if there's an error, wait a second and try again @@ -48,13 +42,12 @@ async function profileFromUuid(uuid) { uuid: data.id, username: data.name }; -} -exports.profileFromUuid = profileFromUuid; -async function profileFromUsername(username) { +}; +export let profileFromUsername = async function profileFromUsername(username) { // since we don't care about anything other than the uuid, we can use /uuid/ instead of /user/ let fetchResponse; try { - fetchResponse = await node_fetch_1.default(`https://api.mojang.com/users/profiles/minecraft/${username}`, { agent: () => httpsAgent }); + fetchResponse = await fetch(`https://api.mojang.com/users/profiles/minecraft/${username}`, { agent: () => httpsAgent }); } catch { // if there's an error, wait a second and try again @@ -67,7 +60,7 @@ async function profileFromUsername(username) { data = JSON.parse(rawData); } catch { } - if (!(data === null || data === void 0 ? void 0 : data.id)) { + if (!data?.id) { // return { uuid: null, username: null } return await profileFromUsernameAlternative(username); } @@ -75,12 +68,11 @@ async function profileFromUsername(username) { uuid: data.id, username: data.name }; -} -exports.profileFromUsername = profileFromUsername; -async function profileFromUsernameAlternative(username) { +}; +export async function profileFromUsernameAlternative(username) { let fetchResponse; try { - fetchResponse = await node_fetch_1.default(`https://api.ashcon.app/mojang/v2/user/${username}`, { agent: () => httpsAgent }); + fetchResponse = await fetch(`https://api.ashcon.app/mojang/v2/user/${username}`, { agent: () => httpsAgent }); } catch { // if there's an error, wait a second and try again @@ -97,16 +89,18 @@ async function profileFromUsernameAlternative(username) { if (!data.uuid) return { uuid: null, username: null }; return { - uuid: util_1.undashUuid(data.uuid), + uuid: undashUuid(data.uuid), username: data.username }; } -exports.profileFromUsernameAlternative = profileFromUsernameAlternative; -async function profileFromUser(user) { - if (util_1.isUuid(user)) { +export let profileFromUser = async function profileFromUser(user) { + if (isUuid(user)) { return await profileFromUuid(user); } else return await profileFromUsername(user); -} -exports.profileFromUser = profileFromUser; +}; +// this is necessary for mocking in the tests because es6 +export function mockProfileFromUuid($value) { profileFromUuid = $value; } +export function mockProfileFromUsername($value) { profileFromUsername = $value; } +export function mockProfileFromUser($value) { profileFromUser = $value; } diff --git a/build/util.js b/build/util.js index c0bbd42..e78e390 100644 --- a/build/util.js +++ b/build/util.js @@ -1,26 +1,20 @@ -"use strict"; /** * Random utility functions that are not related to Hypixel */ -Object.defineProperty(exports, "__esModule", { value: true }); -exports.isUuid = exports.sleep = exports.colorCodeFromName = exports.minecraftColorCodes = exports.shuffle = exports.jsonToQuery = exports.undashUuid = void 0; -function undashUuid(uuid) { +export function undashUuid(uuid) { return uuid.replace(/-/g, '').toLowerCase(); } -exports.undashUuid = undashUuid; -function jsonToQuery(data) { +export function jsonToQuery(data) { return Object.entries(data || {}).map(e => e.join('=')).join('&'); } -exports.jsonToQuery = jsonToQuery; -function shuffle(a) { +export function shuffle(a) { for (let i = a.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [a[i], a[j]] = [a[j], a[i]]; } return a; } -exports.shuffle = shuffle; -exports.minecraftColorCodes = { +export const minecraftColorCodes = { '0': '#000000', '1': '#0000be', '2': '#00be00', @@ -59,21 +53,18 @@ exports.minecraftColorCodes = { * For example: blue -> 9 * @param colorName The name of the color (blue, red, aqua, etc) */ -function colorCodeFromName(colorName) { - const hexColor = exports.minecraftColorCodes[colorName.toLowerCase()]; - for (const key in exports.minecraftColorCodes) { - const value = exports.minecraftColorCodes[key]; +export function colorCodeFromName(colorName) { + const hexColor = minecraftColorCodes[colorName.toLowerCase()]; + for (const key in minecraftColorCodes) { + const value = minecraftColorCodes[key]; if (key.length === 1 && value === hexColor) return key; } } -exports.colorCodeFromName = colorCodeFromName; -async function sleep(ms) { +export async function sleep(ms) { await new Promise(resolve => setTimeout(resolve, ms)); } -exports.sleep = sleep; /** Returns whether a string is a UUID4 (Minecraft uuid) */ -function isUuid(string) { +export function isUuid(string) { return undashUuid(string).length === 32; } -exports.isUuid = isUuid; |