Comparing version 2.5.0 to 3.0.0
22
index.js
@@ -1,1 +0,21 @@ | ||
module.exports = require('./src/SteamAPI'); | ||
import NewsPost from './src/structures/NewsPost.js'; | ||
import Server, { ServerRegion } from './src/structures/Server.js'; | ||
import Game from './src/structures/Game.js'; | ||
import GameInfo from './src/structures/GameInfo.js'; | ||
import GameInfoExtended from './src/structures/GameInfoExtended.js'; | ||
import GameInfoBasic from './src/structures/GameInfoBasic.js'; | ||
import GameServer from './src/structures/GameServer.js'; | ||
import UserAchievement from './src/structures/UserAchievement.js'; | ||
import UserAchievements from './src/structures/UserAchievements.js'; | ||
import UserBadge from './src/structures/UserBadge.js'; | ||
import UserBadges from './src/structures/UserBadges.js'; | ||
import UserPlaytime from './src/structures/UserPlaytime.js'; | ||
import UserBans from './src/structures/UserBans.js'; | ||
import UserFriend from './src/structures/UserFriend.js'; | ||
import UserServer from './src/structures/UserServer.js'; | ||
import UserServers from './src/structures/UserServers.js'; | ||
import UserStats from './src/structures/UserStats.js'; | ||
import UserSummary, { UserPersonaState } from './src/structures/UserSummary.js'; | ||
import SteamAPI from './src/SteamAPI.js'; | ||
export default SteamAPI; | ||
export { ServerRegion, UserPersonaState, NewsPost, Server, Game, GameInfo, GameInfoExtended, GameInfoBasic, GameServer, UserAchievement, UserAchievements, UserBadge, UserBadges, UserPlaytime, UserBans, UserFriend, UserServer, UserServers, UserStats, UserSummary, }; |
{ | ||
"author": "xDimGG <dimggyt@gmail.com> (https://dim.codes)", | ||
"name": "steamapi", | ||
"description": "A nice Steam API wrapper.", | ||
"main": "index.js", | ||
"version": "2.5.0", | ||
"license": "MIT", | ||
"eslintConfig": { | ||
"extends": "eslint-config-dim", | ||
"env": { | ||
"node": true, | ||
"browser": true | ||
}, | ||
"parserOptions": { | ||
"ecmaVersion": "latest" | ||
}, | ||
"rules": { | ||
"eol-last": ["error", "always"], | ||
"no-shadow": "off" | ||
} | ||
}, | ||
"keywords": [ | ||
"steam", | ||
"api", | ||
"wrapper", | ||
"steam-api", | ||
"steampowered" | ||
], | ||
"bugs": { | ||
"web": "https://github.com/xDimGG/node-steamapi/issues" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/xDimGG/node-steamapi" | ||
}, | ||
"homepage": "https://github.com/xDimGG/node-steamapi#readme", | ||
"devDependencies": { | ||
"eslint-config-dim": "github:xDimGG/eslint-config-dim" | ||
}, | ||
"dependencies": { | ||
"node-fetch": "^2.6.11", | ||
"steamid": "^2.0.0" | ||
} | ||
"author": "xDimGG <dimggyt@gmail.com> (https://dim.codes)", | ||
"name": "steamapi", | ||
"description": "A nice Steam API wrapper.", | ||
"main": "index.js", | ||
"types": "index.d.ts", | ||
"version": "3.0.0", | ||
"license": "MIT", | ||
"type": "module", | ||
"scripts": { | ||
"tsdoc": "typedoc --plugin typedoc-plugin-markdown --readme none --out docs index.ts" | ||
}, | ||
"keywords": [ | ||
"steam", | ||
"api", | ||
"wrapper", | ||
"steam-api", | ||
"steampowered" | ||
], | ||
"bugs": { | ||
"web": "https://github.com/xDimGG/node-steamapi/issues" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/xDimGG/node-steamapi" | ||
}, | ||
"homepage": "https://github.com/xDimGG/node-steamapi#readme", | ||
"devDependencies": { | ||
"@types/node": "^20.11.5", | ||
"@types/steamid": "^2.0.3", | ||
"typedoc": "^0.25.7", | ||
"typedoc-plugin-markdown": "^3.17.1", | ||
"typescript": "^5.3.3" | ||
}, | ||
"dependencies": { | ||
"node-fetch": "^3.3.2", | ||
"steamid": "^2.0.0" | ||
} | ||
} |
@@ -1,431 +0,493 @@ | ||
const SteamID = require('steamid'); | ||
const PlayerAchievements = require('./structures/PlayerAchievements'); | ||
const PlayerSummary = require('./structures/PlayerSummary'); | ||
const PlayerServers = require('./structures/PlayerServers'); | ||
const PlayerBadges = require('./structures/PlayerBadges'); | ||
const PlayerStats = require('./structures/PlayerStats'); | ||
const PlayerBans = require('./structures/PlayerBans'); | ||
const OwnedGame = require('./structures/OwnedGame'); | ||
const Friend = require('./structures/Friend'); | ||
const Server = require('./structures/Server'); | ||
const Game = require('./structures/Game'); | ||
const objectify = require('./utils/objectify'); | ||
const fetch = require('./utils/fetch'); | ||
const { version, name } = require('../package.json'); | ||
const allowedRegions = ['us', 'ca', 'cc', 'es', 'de', 'fr', 'ru', 'nz', 'au', 'uk']; | ||
const allowedLanguages = ['arabic', 'bulgarian', 'schinese', 'tchinese', 'czech', 'danish', 'dutch', 'english', 'finnish', 'french', 'german', 'greek', 'hungarian', 'italian', 'japanese', 'koreana', 'norwegian', 'polish', 'brazilian', 'portuguese', 'romanian', 'russian', 'latam', 'spanish', 'swedish', 'thai', 'turkish', 'ukrainian', 'vietnamese']; | ||
const reApp = /^\d{1,7}$/; | ||
const reID = /^\d{17}$/; | ||
const reProfileBase = String.raw`(?:(?:(?:(?:https?)?:\/\/)?(?:www\.)?steamcommunity\.com)?)?\/?`; | ||
const reCommunityID = RegExp(String.raw`^(\d{17})$`, 'i'); | ||
const reSteamID2 = RegExp(String.raw`^(STEAM_\d+:\d+:\d+)$`, 'i'); | ||
const reSteamID3 = RegExp(String.raw`^(\[U:\d+:\d+\])$`, 'i'); | ||
const reProfileURL = RegExp(String.raw`${reProfileBase}profiles\/(\d{17})`, 'i'); | ||
const reProfileID = RegExp(String.raw`${reProfileBase}id\/([a-z0-9_-]{2,32})`, 'i'); | ||
const STATUS_SUCCESS = 1; | ||
class SteamAPI { | ||
/** | ||
* Sets Steam key for future use. | ||
* @param {string} key Steam key | ||
* @param {Object} [options={}] Optional options for caching and warnings `getGameDetails()` | ||
* @param {boolean} [options.enabled=true] Whether caching is enabled | ||
* @param {number} [options.expires=86400000] How long cache should last for in ms (1 day by default) | ||
* @param {boolean} [options.disableWarnings=false] Whether to suppress warnings | ||
*/ | ||
constructor(key, { enabled = true, expires = 86400000, disableWarnings = false } = {}) { | ||
this.key = key; | ||
this.baseAPI = 'https://api.steampowered.com'; | ||
this.baseStore = 'https://store.steampowered.com/api'; | ||
this.headers = { 'User-Agent': `SteamAPI/${version} (https://www.npmjs.com/package/${name})` }; | ||
this.options = { enabled, expires, disableWarnings }; | ||
this.resolveCache = new Map(); | ||
if (enabled) this.cache = new Map(); | ||
if (!key) this._warn('no key provided, some methods won\'t work, go get one from https://goo.gl/DfNy5s'); | ||
} | ||
/** | ||
* Prints a warning | ||
* @param {...any} args Message | ||
* @returns {void} | ||
* @private | ||
*/ | ||
_warn(...args) { | ||
if (this.options.disableWarnings) return; | ||
console.warn('[SteamAPI]', ...args); | ||
} | ||
/** | ||
* Get custom path that isn't in SteamAPI. | ||
* @param {string} path Path to request e.g '/IPlayerService/GetOwnedGames/v1?steamid=76561198378422474' | ||
* @param {string} [base=this.baseAPI] Base URL | ||
* @param {string} [key=this.key] The key to use | ||
* @returns {Promise<Object>} JSON Response | ||
*/ | ||
get(path, base = this.baseAPI, key = this.key) { | ||
return fetch(`${base}${path}${path.includes('?') ? '&' : '?'}key=${key}`, this.headers); | ||
} | ||
/** | ||
* Resolve info based on id, profile, or url. | ||
* Rejects promise if a profile couldn't be resolved. | ||
* @param {string} info Something to resolve e.g 'https://steamcommunity.com/id/xDim' | ||
* @returns {Promise<string>} Profile ID | ||
*/ | ||
resolve(info) { | ||
if (!info) return Promise.reject(new TypeError('Invalid/no app provided')); | ||
// community id match, ex. 76561198378422474 | ||
const communityIDMatch = info.match(reCommunityID); | ||
if (communityIDMatch !== null) | ||
return Promise.resolve(communityIDMatch[1]); | ||
// url, https://steamcommunity.com/profiles/76561198378422474 | ||
const urlMatch = info.match(reProfileURL); | ||
if (urlMatch !== null) | ||
return Promise.resolve(urlMatch[1]); | ||
// Steam 2: STEAM_0:0:209078373 | ||
const steamID2Match = info.match(reSteamID2); | ||
if (steamID2Match !== null) { | ||
const sid = new SteamID(steamID2Match[1]); | ||
return Promise.resolve(sid.getSteamID64()); | ||
} | ||
// Steam 3: [U:1:418156746] | ||
const steamID3Match = info.match(reSteamID3); | ||
if (steamID3Match !== null) { | ||
const sid = new SteamID(steamID3Match[1]); | ||
return Promise.resolve(sid.getSteamID64()); | ||
} | ||
// vanity id, https://steamcommunity.com/id/xDim | ||
const idMatch = info.match(reProfileID); | ||
if (idMatch !== null) { | ||
const id = idMatch[1]; | ||
if (this.resolveCache.has(id)) return Promise.resolve(this.resolveCache.get(id)); | ||
return this | ||
.get(`/ISteamUser/ResolveVanityURL/v1?vanityurl=${id}`) | ||
.then(json => json.response.success === STATUS_SUCCESS | ||
? this.resolveCache.set(id, json.response.steamid).get(id) | ||
: Promise.reject(new TypeError(json.response.message)), | ||
); | ||
} | ||
return Promise.reject(new TypeError('Invalid format')); | ||
} | ||
/** | ||
* @typedef {App} | ||
* @property {number} appid The app's ID | ||
* @property {string} name The app's name | ||
*/ | ||
/** | ||
* Get every single app on steam. | ||
* @returns {Promise<App[]>} Array of apps | ||
*/ | ||
getAppList() { | ||
return this | ||
.get('/ISteamApps/GetAppList/v2') | ||
.then(json => json.applist.apps); | ||
} | ||
/** | ||
* Get featured categories on the steam store. | ||
* @returns {Promise<Object[]>} Featured categories | ||
*/ | ||
getFeaturedCategories() { | ||
return this | ||
.get('/featuredcategories', this.baseStore) | ||
.then(Object.values); | ||
} | ||
/** | ||
* Get featured games on the steam store | ||
* @returns {Promise<Object>} Featured games | ||
*/ | ||
getFeaturedGames() { | ||
return this.get('/featured', this.baseStore); | ||
} | ||
/** | ||
* Get achievements for app id. | ||
* @param {string} app App ID | ||
* @returns {Promise<Object>} App achievements for ID | ||
*/ | ||
getGameAchievements(app) { | ||
if (!reApp.test(app)) return Promise.reject(new TypeError('Invalid/no app provided')); | ||
return this | ||
.get(`/ISteamUserStats/GetGlobalAchievementPercentagesForApp/v2?gameid=${app}`) | ||
.then(json => objectify(json.achievementpercentages.achievements, 'percent')); | ||
} | ||
/** | ||
* Get details for app id. | ||
* <warn>Requests for this endpoint are limited to 200 every 5 minutes</warn> | ||
* <warn>Not every `region` is supported. Only the following are valid: `us, ca, cc, es, de, fr, ru, nz, au, uk`.</warn> | ||
* <warn>Not every `language` is supported. A list of available languages can be found [here](https://www.ibabbleon.com/Steam-Supported-Languages-API-Codes.html).</warn> | ||
* @param {string} app App ID | ||
* @param {boolean} [force=false] Overwrite cache | ||
* @param {string} [region=us] Currency region | ||
* @param {string} [language=english] Description language | ||
* @returns {Promise<Object>} App details for ID | ||
*/ | ||
getGameDetails(app, force = false, region = 'us', language = 'english') { | ||
if (!reApp.test(app)) return Promise.reject(TypeError('Invalid/no app provided')); | ||
if (!allowedRegions.includes(region)) return Promise.reject(TypeError('Invalid region provided')); | ||
if (!allowedLanguages.includes(language)) return Promise.reject(TypeError('Invalid language provided')); | ||
const request = () => this | ||
.get(`/appdetails?appids=${app}&cc=${region}&l=${language}`, this.baseStore) | ||
.then(json => json[app].success | ||
? json[app].data | ||
: Promise.reject(new Error('No app found')), | ||
); | ||
const key = `${app}-${region}-${language}`; | ||
if (!force && this.options.enabled && this.cache.has(key) && this.cache.get(key)[0] > Date.now()) | ||
return Promise.resolve(this.cache.get(key)[1]); | ||
if (this.options.enabled && (!this.cache.has(key) || this.cache.get(key)[0] <= Date.now())) | ||
return request().then(json => this.cache.set(key, [Date.now() + this.options.expires, json]) && json); | ||
return request(); | ||
} | ||
/** | ||
* Get news for app id. | ||
* @param {string} app App ID | ||
* @returns {Promise<Object[]>} App news for ID | ||
*/ | ||
getGameNews(app) { | ||
if (!reApp.test(app)) return Promise.reject(new TypeError('Invalid/no app provided')); | ||
return this | ||
.get(`/ISteamNews/GetNewsForApp/v2?appid=${app}`) | ||
.then(json => json.appnews.count ? json.appnews.newsitems : Promise.reject(new Error('No news found'))); | ||
} | ||
/** | ||
* Get number of current players for app id. | ||
* @param {string} app App ID | ||
* @returns {Promise<number>} Number of players | ||
*/ | ||
getGamePlayers(app) { | ||
if (!reApp.test(app)) return Promise.reject(new TypeError('Invalid/no app provided')); | ||
return this | ||
.get(`/ISteamUserStats/GetNumberOfCurrentPlayers/v1?appid=${app}`) | ||
.then(json => json.response.result === 1 ? json.response.player_count : Promise.reject(new Error('No app found'))); | ||
} | ||
/** | ||
* Get schema for app id. | ||
* @param {string} app App ID | ||
* @returns {Promise<Object>} Schema | ||
*/ | ||
getGameSchema(app) { | ||
if (!reApp.test(app)) return Promise.reject(new TypeError('Invalid/no app provided')); | ||
return this | ||
.get(`/ISteamUserStats/GetSchemaForGame/v2?appid=${app}`) | ||
.then(json => json.game ? json.game : Promise.reject(new Error('No app found'))); | ||
// TODO: Schema Class | ||
} | ||
/** | ||
* Get every server associated with host. | ||
* @param {string} host Host to request | ||
* @returns {Promise<Server[]>} Server info | ||
*/ | ||
getServers(host) { | ||
if (!host) return Promise.reject(new TypeError('No host provided')); | ||
return this | ||
.get(`/ISteamApps/GetServersAtAddress/v1?addr=${host}`) | ||
.then(json => json.response.success | ||
? json.response.servers.map(server => new Server(server)) | ||
: Promise.reject(new Error(json.response.message)), | ||
); | ||
} | ||
/** | ||
* Get users achievements for app id. | ||
* @param {string} id User ID | ||
* @param {string} app App ID | ||
* @returns {Promise<PlayerAchievements>} Achievements | ||
*/ | ||
getUserAchievements(id, app) { | ||
if (!reID.test(id)) return Promise.reject(new TypeError('Invalid/no id provided')); | ||
if (!reApp.test(app)) return Promise.reject(new TypeError('Invalid/no appid provided')); | ||
return this | ||
.get(`/ISteamUserStats/GetPlayerAchievements/v1?steamid=${id}&appid=${app}&l=english`) | ||
.then(json => json.playerstats.success | ||
? new PlayerAchievements(json.playerstats) | ||
: Promise.reject(new Error(json.playerstats.message)), | ||
); | ||
} | ||
/** | ||
* Get users badges. | ||
* @param {string} id User ID | ||
* @returns {Promise<PlayerBadges>} Badges | ||
*/ | ||
getUserBadges(id) { | ||
if (!reID.test(id)) return Promise.reject(new TypeError('Invalid/no id provided')); | ||
return this | ||
.get(`/IPlayerService/GetBadges/v1?steamid=${id}`) | ||
.then(json => new PlayerBadges(json.response)); | ||
} | ||
/** | ||
* Get users bans. If an array of IDs is passed in, this returns an array of PlayerBans | ||
* @param {string|string[]} id User ID(s) | ||
* @returns {Promise<PlayerBans|PlayerBans[]>} Ban info | ||
*/ | ||
getUserBans(id) { | ||
const arr = Array.isArray(id); | ||
if ((arr && id.some(i => !reID.test(i))) || (!arr && !reID.test(id))) return Promise.reject(new TypeError('Invalid/no id provided')); | ||
return this | ||
.get(`/ISteamUser/GetPlayerBans/v1?steamids=${id}`) | ||
.then(json => json.players.length | ||
? arr | ||
? json.players.map(player => new PlayerBans(player)) | ||
: new PlayerBans(json.players[0]) | ||
: Promise.reject(new Error('No players found')), | ||
); | ||
} | ||
/** | ||
* Get users friends. | ||
* @param {string} id User ID | ||
* @returns {Promise<Friend[]>} Friends | ||
*/ | ||
getUserFriends(id) { | ||
if (!reID.test(id)) return Promise.reject(new TypeError('Invalid/no id provided')); | ||
return this | ||
.get(`/ISteamUser/GetFriendList/v1?steamid=${id}`) | ||
.then(json => json.friendslist.friends.map(friend => new Friend(friend))); | ||
} | ||
/** | ||
* Get users groups. | ||
* @param {string} id User ID | ||
* @returns {Promise<string[]>} Groups | ||
*/ | ||
getUserGroups(id) { | ||
if (!reID.test(id)) return Promise.reject(new TypeError('Invalid/no id provided')); | ||
return this | ||
.get(`/ISteamUser/GetUserGroupList/v1?steamid=${id}`) | ||
.then(json => json.response.success | ||
? json.response.groups.map(group => group.gid) | ||
: Promise.reject(new Error(json.response.message)), | ||
); | ||
} | ||
/** | ||
* Get users level. | ||
* @param {string} id User ID | ||
* @returns {Promise<number>} Level | ||
*/ | ||
getUserLevel(id) { | ||
if (!reID.test(id)) return Promise.reject(new TypeError('Invalid/no id provided')); | ||
return this | ||
.get(`/IPlayerService/GetSteamLevel/v1?steamid=${id}`) | ||
.then(json => json.response.player_level); | ||
} | ||
/** | ||
* Get users owned games. | ||
* @param {string} id User ID | ||
* @param {boolean} [includeF2P=true] Whether to include user's free-to-play games or not | ||
* @returns {Promise<OwnedGame[]>} Owned games | ||
*/ | ||
getUserOwnedGames(id, includeF2P = true) { | ||
if (!reID.test(id)) return Promise.reject(new TypeError('Invalid/no id provided')); | ||
return this | ||
.get(`/IPlayerService/GetOwnedGames/v1?steamid=${id}${includeF2P ? '&include_played_free_games=1' : ''}&include_appinfo=1`) | ||
.then(json => json.response.games ? json.response.games.map(game => new OwnedGame(game)) : Promise.reject(new Error('No games found'))); | ||
} | ||
/** | ||
* Get users recent games. | ||
* @param {string} id User ID | ||
* @param {number} [count] Optionally limit the number of games to fetch to some number | ||
* @returns {Promise<Game[]>} Recent games | ||
*/ | ||
getUserRecentGames(id, count) { | ||
if (!reID.test(id)) return Promise.reject(new TypeError('Invalid/no id provided')); | ||
if (count !== undefined && count !== null && (!Number.isInteger(count) || count < 1)) | ||
return Promise.reject(new TypeError('Count must be a positive integer')); | ||
return this | ||
.get(`/IPlayerService/GetRecentlyPlayedGames/v1?steamid=${id}${count ? `&count=${count}` : ''}`) | ||
.then(json => json.response.total_count ? json.response.games.map(game => new Game(game)) : []); | ||
} | ||
/** | ||
* Gets servers on steamcommunity.com/dev/managegameservers using your key or provided key. | ||
* @param {boolean} [hide=false] Hide deleted/expired servers | ||
* @param {string} [key=this.key] Key | ||
* @returns {Promise<PlayerServers>} Servers | ||
*/ | ||
getUserServers(hide = false, key) { | ||
return this | ||
.get('/IGameServersService/GetAccountList/v1', this.baseAPI, key) | ||
.then(json => new PlayerServers(json.response, hide)); | ||
} | ||
/** | ||
* Get users stats for app id. | ||
* @param {string} id User ID | ||
* @param {string} app App ID | ||
* @returns {Promise<PlayerStats>} Stats for app id | ||
*/ | ||
getUserStats(id, app) { | ||
if (!reID.test(id)) return Promise.reject(new TypeError('Invalid/no id provided')); | ||
if (!reApp.test(app)) return Promise.reject(new TypeError('Invalid/no app provided')); | ||
return this | ||
.get(`/ISteamUserStats/GetUserStatsForGame/v2?steamid=${id}&appid=${app}`) | ||
.then(json => json.playerstats ? new PlayerStats(json.playerstats) : Promise.reject(new Error('No player found'))); | ||
} | ||
/** | ||
* Get users summary. If an array of IDs is passed in, this returns an array of PlayerSummary | ||
* @param {string|string[]} id User ID(s) | ||
* @returns {Promise<PlayerSummary|PlayerSummary[]>} Summary | ||
*/ | ||
getUserSummary(id) { | ||
const arr = Array.isArray(id); | ||
if ((arr && id.some(i => !reID.test(i))) || (!arr && !reID.test(id))) return Promise.reject(new TypeError('Invalid/no id provided')); | ||
return this | ||
.get(`/ISteamUser/GetPlayerSummaries/v2?steamids=${id}`) | ||
.then(json => json.response.players.length | ||
? arr | ||
? json.response.players.map(player => new PlayerSummary(player)) | ||
: new PlayerSummary(json.response.players[0]) | ||
: Promise.reject(new Error('No players found')), | ||
); | ||
} | ||
import SteamID from 'steamid'; | ||
import querystring from 'node:querystring'; | ||
import Package from '../package.json' assert { type: 'json' }; | ||
import { MemoryCacheMap } from './Cache.js'; | ||
import { fetch, assertApp, assertID } from './Utils.js'; | ||
import UserStats from './structures/UserStats.js'; | ||
import NewsPost from './structures/NewsPost.js'; | ||
import Server from './structures/Server.js'; | ||
import Game from './structures/Game.js'; | ||
import GameInfo from './structures/GameInfo.js'; | ||
import GameInfoExtended from './structures/GameInfoExtended.js'; | ||
import GameInfoBasic from './structures/GameInfoBasic.js'; | ||
import GameServer from './structures/GameServer.js'; | ||
import UserAchievements from './structures/UserAchievements.js'; | ||
import UserBadges from './structures/UserBadges.js'; | ||
import UserPlaytime from './structures/UserPlaytime.js'; | ||
import UserBans from './structures/UserBans.js'; | ||
import UserFriend from './structures/UserFriend.js'; | ||
import UserServers from './structures/UserServers.js'; | ||
import UserSummary from './structures/UserSummary.js'; | ||
const defaultOptions = { | ||
language: 'english', | ||
currency: 'us', | ||
headers: { 'User-Agent': `SteamAPI/${Package.version} (https://www.npmjs.com/package/${Package.name})` }, | ||
baseAPI: 'https://api.steampowered.com', | ||
baseStore: 'https://store.steampowered.com/api', | ||
baseActions: 'https://steamcommunity.com/actions', | ||
inMemoryCacheEnabled: true, | ||
gameDetailCacheEnabled: true, | ||
gameDetailCacheTTL: 86400000, | ||
userResolveCacheEnabled: true, | ||
userResolveCacheTTL: 86400000, | ||
}; | ||
export default class SteamAPI { | ||
static reProfileBase = String.raw `(?:(?:(?:(?:https?)?:\/\/)?(?:www\.)?steamcommunity\.com)?)?\/?`; | ||
static reCommunityID = RegExp(String.raw `^(\d{17})$`, 'i'); | ||
static reSteamID2 = RegExp(String.raw `^(STEAM_\d+:\d+:\d+)$`, 'i'); | ||
static reSteamID3 = RegExp(String.raw `^(\[U:\d+:\d+\])$`, 'i'); | ||
static reProfileURL = RegExp(String.raw `${this.reProfileBase}profiles\/(\d{17})`, 'i'); | ||
static reProfileID = RegExp(String.raw `${this.reProfileBase}id\/([a-z0-9_-]{2,32})`, 'i'); | ||
static SUCCESS_CODE = 1; | ||
language; | ||
currency; | ||
headers; | ||
baseAPI; | ||
baseStore; | ||
baseActions; | ||
gameDetailCache; | ||
userResolveCache; | ||
key = ''; | ||
/** | ||
* Make a new SteamAPI Client | ||
* @param key Key to use for API calls. Key can be generated at https://steamcommunity.com/dev/apikey. If you want to make requests without a key, pass in false | ||
* @param options Custom options for default language, HTTP parameters, and caching | ||
*/ | ||
constructor(key, options = {}) { | ||
if (key !== false) { | ||
if (key) { | ||
this.key = key; | ||
} | ||
else { | ||
console.warn([ | ||
'no key provided', | ||
'some methods won\'t work', | ||
'get one from https://goo.gl/DfNy5s or initialize SteamAPI as new SteamAPI(false) to suppress this warning' | ||
].join('\n')); | ||
} | ||
} | ||
options = { ...defaultOptions, ...options }; | ||
if (options.inMemoryCacheEnabled) { | ||
if (options.gameDetailCacheEnabled && options.gameDetailCacheTTL) | ||
this.gameDetailCache = new MemoryCacheMap(options.gameDetailCacheTTL); | ||
if (options.userResolveCacheEnabled && options.userResolveCacheTTL) | ||
this.userResolveCache = new MemoryCacheMap(options.userResolveCacheTTL); | ||
} | ||
this.language = options.language; | ||
this.currency = options.currency; | ||
this.headers = options.headers; | ||
this.baseAPI = options.baseAPI; | ||
this.baseStore = options.baseStore; | ||
this.baseActions = options.baseActions; | ||
} | ||
/** | ||
* Used to make any GET request to the Steam API | ||
* @param path Path to request e.g '/IPlayerService/GetOwnedGames/v1?steamid=76561198378422474' | ||
* @param base Base API URL | ||
* @returns Parse JSON | ||
*/ | ||
get(path, params = {}, base = this.baseAPI) { | ||
if (this.key) | ||
params.key = this.key; | ||
return fetch(`${base}${path}?${querystring.stringify(params)}`, this.headers); | ||
} | ||
/** | ||
* Resolve runs through a couple different methods for finding a user's profile ID based on | ||
* either their id, username, profile url, vanity url, steamID2, or steamID3. | ||
* Rejects promise if a profile couldn't be resolved | ||
* @param query Something to resolve like https://steamcommunity.com/id/xDim | ||
* @returns Profile ID | ||
*/ | ||
async resolve(query) { | ||
// community id match, ex. 76561198378422474 | ||
const communityIDMatch = query.match(SteamAPI.reCommunityID); | ||
if (communityIDMatch !== null) | ||
return communityIDMatch[1]; | ||
// url, https://steamcommunity.com/profiles/76561198378422474 | ||
const urlMatch = query.match(SteamAPI.reProfileURL); | ||
if (urlMatch !== null) | ||
return urlMatch[1]; | ||
// Steam 2: STEAM_0:0:209078373 | ||
const steamID2Match = query.match(SteamAPI.reSteamID2); | ||
if (steamID2Match !== null) { | ||
const sid = new SteamID(steamID2Match[1]); | ||
return sid.getSteamID64(); | ||
} | ||
// Steam 3: [U:1:418156746] | ||
const steamID3Match = query.match(SteamAPI.reSteamID3); | ||
if (steamID3Match !== null) { | ||
const sid = new SteamID(steamID3Match[1]); | ||
return sid.getSteamID64(); | ||
} | ||
// vanity id, https://steamcommunity.com/id/xDim | ||
const idMatch = query.match(SteamAPI.reProfileID); | ||
if (idMatch !== null) { | ||
const id = idMatch[1]; | ||
const cachedID = this.userResolveCache?.get(id); | ||
if (cachedID) | ||
return cachedID; | ||
const json = await this.get('/ISteamUser/ResolveVanityURL/v1', { vanityurl: id }); | ||
if (json.response.success !== SteamAPI.SUCCESS_CODE) | ||
throw new Error(json.response.message); | ||
if (this.userResolveCache) | ||
this.userResolveCache.set(id, json.response.steamid); | ||
return json.response.steamid; | ||
} | ||
throw new TypeError('Invalid format'); | ||
} | ||
/** | ||
* Gets featured categories on Steam store | ||
* | ||
* <warn>undocumented endpoint -- may be unstable</warn> | ||
* @param options More options | ||
* @param options.language The language | ||
* @param options.currency The currency | ||
*/ | ||
getFeaturedCategories({ language = this.language, currency = this.currency } = {}) { | ||
// TODO: make class for this | ||
return this.get('/featuredcategories', { l: language, cc: currency }, this.baseStore); | ||
} | ||
/** | ||
* Gets featured games on Steam store | ||
* | ||
* <warn>undocumented endpoint -- may be unstable</warn> | ||
* @param options More options | ||
* @param options.language The language | ||
* @param options.currency The currency | ||
*/ | ||
getFeaturedGames({ language = this.language, currency = this.currency } = {}) { | ||
// TODO: make class for this | ||
return this.get('/featured', { l: language, cc: currency }, this.baseStore); | ||
} | ||
/** | ||
* Get details for app ID. If an array of more than one app ID is passed in, the parameter &filters=price_overview | ||
* will be added to the request since otherwise the server would respond with null | ||
* | ||
* Note: a game will not have a price_overview field if it is F2P | ||
* | ||
* <warn>If the array contains invalid app IDs, they will be filtered out</warn> | ||
* | ||
* <warn>Requests for this endpoint are limited to 200 every 5 minutes</warn> | ||
* | ||
* <warn>Not every `currency` is supported. Only the following are valid: `us, ca, cc, es, de, fr, ru, nz, au, uk`.</warn> | ||
* | ||
* <warn>Not every `language` is supported. A list of available languages can be found [here](https://www.ibabbleon.com/Steam-Supported-Languages-API-Codes.html).</warn> | ||
* @param app App ID or array of App IDs | ||
* @param options More options | ||
* @param options.language The language | ||
* @param options.currency The currency | ||
* @param options.filters Fields to restrict the return results to | ||
* @returns If app is number, returns single object. If app is array, returns a mapping of app IDs to objects | ||
*/ | ||
async getGameDetails(app, { language = this.language, currency = this.currency, filters = [] } = {}) { | ||
assertApp(app); | ||
const isArr = Array.isArray(app); | ||
const key = `${app}-${currency}-${language}`; | ||
// For now we're not touching the cache if an array of apps is passed | ||
// TODO: maybe cache apps individually if an array is passed? | ||
if (!isArr) { | ||
const cached = this.gameDetailCache?.get(key); | ||
if (cached) | ||
return cached; | ||
} | ||
const details = await this | ||
.get('/appdetails', { | ||
appids: isArr ? app.join(',') : app, | ||
cc: currency, | ||
l: language, | ||
filters: isArr && app.length > 1 ? 'price_overview' : filters.join(','), | ||
}, this.baseStore) | ||
.then(json => { | ||
if (json === null) | ||
throw new Error('Failed to find app ID'); | ||
// TODO: make a class | ||
const filtered = {}; | ||
for (const [k, v] of Object.entries(json)) | ||
if (v.success) { | ||
const d = v.data; | ||
// Convert empty arrays to empty objects for consistency | ||
filtered[k] = Array.isArray(d) && d.length === 0 ? {} : d; | ||
} | ||
if (Object.keys(filtered).length === 0) | ||
throw new Error('Failed to find app ID'); | ||
return isArr ? filtered : filtered[app]; | ||
}); | ||
if (!isArr) | ||
this.gameDetailCache?.set(key, details); | ||
return details; | ||
} | ||
/** | ||
* Get every single app on steam | ||
* | ||
* Note: Original JSON names are being preserved instead of converting | ||
* each element to a class here because there are 186311+ games | ||
* that would have to be made into a class. | ||
* @returns Array of very basic app info (ID + name) | ||
*/ | ||
async getAppList() { | ||
// TODO: allow a parameter to be passed in to convert these to a class? | ||
return (await this.get('/ISteamApps/GetAppList/v2')).applist.apps; | ||
} | ||
/** | ||
* Get every server associated with a particular host | ||
* @param host Host to query (IPv4 or IPv4:queryport) | ||
* @returns Info of servers | ||
*/ | ||
async getServers(host) { | ||
const { response } = await this.get('/ISteamApps/GetServersAtAddress/v1', { addr: host }); | ||
if (!response.success) | ||
throw new Error(response.message); | ||
return response.servers.map((server) => new Server(server)); | ||
} | ||
/** | ||
* Get number of current players for app ID | ||
* @param app App ID to get number of current players for | ||
* @returns Number of current players | ||
*/ | ||
async getGamePlayers(app) { | ||
assertApp(app); | ||
const json = await this.get('/ISteamUserStats/GetNumberOfCurrentPlayers/v1', { appid: app }); | ||
if (json.response.result !== SteamAPI.SUCCESS_CODE) | ||
throw new Error('No app found'); | ||
return json.response.player_count; | ||
} | ||
/** | ||
* Get schema for app ID | ||
* @param app App ID to get schema for | ||
* @param language Language to return strings for (note: does not seem to affect stats; only achievements) | ||
* @returns Schema | ||
*/ | ||
async getGameSchema(app, language = this.language) { | ||
assertApp(app); | ||
// TODO: make class for this | ||
return (await this.get('/ISteamUserStats/GetSchemaForGame/v2', { appid: app, l: language })).game; | ||
} | ||
/** | ||
* Get a user's achievements for app ID | ||
* @param id Steam ID of user | ||
* @param app App ID to get achievements for | ||
* @param language Language to return strings for | ||
* @returns Achievements | ||
*/ | ||
async getUserAchievements(id, app, language = this.language) { | ||
assertID(id); | ||
assertApp(app); | ||
const json = await this.get('/ISteamUserStats/GetPlayerAchievements/v1', { steamid: id, appid: app, l: language }); | ||
if (!json.playerstats.success) | ||
throw new Error(json.playerstats.message); | ||
return new UserAchievements(json.playerstats); | ||
} | ||
/** | ||
* Get achievement percentages for app ID | ||
* | ||
* If a game does not hvae any achievements, this will error | ||
* @param app App ID to get achievement progress for | ||
* @returns Array of object with achievement name and percentage for app ID | ||
*/ | ||
async getGameAchievementPercentages(app) { | ||
assertApp(app); | ||
const json = await this.get('/ISteamUserStats/GetGlobalAchievementPercentagesForApp/v2', { gameid: app }); | ||
return json.achievementpercentages.achievements; | ||
} | ||
/** | ||
* Get a user's stats for app ID | ||
* @param id Steam ID of user | ||
* @param app App ID to get user stats for | ||
* @returns Stats for app ID | ||
*/ | ||
async getUserStats(id, app) { | ||
assertID(id); | ||
assertApp(app); | ||
return new UserStats((await this.get('/ISteamUserStats/GetUserStatsForGame/v2', { steamid: id, appid: app })).playerstats); | ||
} | ||
/** | ||
* Get news for app ID | ||
* @param app App ID | ||
* @param options Additional options for filtering posts | ||
* @returns App news for ID | ||
*/ | ||
async getGameNews(app, options = {}) { | ||
assertApp(app); | ||
const params = { | ||
appid: app, | ||
maxlength: options.maxContentLength, | ||
enddate: options.endDate?.getTime(), | ||
count: options.count, | ||
feeds: options.feeds?.join(','), | ||
tags: options.tags?.join(','), | ||
}; | ||
// Filter out options that weren't supplied | ||
for (const [k, v] of Object.entries(params)) | ||
if (v === undefined) | ||
delete params[k]; | ||
return (await this.get('/ISteamNews/GetNewsForApp/v2', params)).appnews.newsitems.map((item) => new NewsPost(item)); | ||
} | ||
/** | ||
* Get a user's badges | ||
* @param id User ID | ||
* @returns User level info and badges | ||
*/ | ||
async getUserBadges(id) { | ||
assertID(id); | ||
return new UserBadges((await this.get('/IPlayerService/GetBadges/v1', { steamid: id })).response); | ||
} | ||
/** | ||
* Get a user's level | ||
* @param id User ID | ||
* @returns The user's Steam level | ||
*/ | ||
async getUserLevel(id) { | ||
assertID(id); | ||
return (await this.get('/IPlayerService/GetSteamLevel/v1', { steamid: id })).response.player_level; | ||
} | ||
/** | ||
* Get users owned games. | ||
* @param id User ID | ||
* @param opts Additional options for filtering | ||
* @returns Owned games | ||
*/ | ||
async getUserOwnedGames(id, opts = {}) { | ||
assertID(id); | ||
// Same behavior as v3 | ||
if (opts.includeFreeGames === undefined) | ||
opts.includeFreeGames = true; | ||
if (opts.language === undefined) | ||
opts.language = this.language; | ||
if (opts.includeExtendedAppInfo) | ||
opts.includeAppInfo = true; | ||
const params = { | ||
steamid: id, | ||
include_appinfo: opts.includeAppInfo, | ||
include_played_free_games: opts.includeFreeGames, | ||
include_free_sub: opts.includeFreeSubGames, | ||
skip_unvetted_apps: opts.includeUnvettedApps === undefined ? undefined : !opts.includeUnvettedApps, | ||
include_extended_appinfo: opts.includeExtendedAppInfo, | ||
appids_filter: opts.filterApps, | ||
language: opts.language, | ||
}; | ||
// Filter out options that weren't supplied | ||
for (const [k, v] of Object.entries(params)) | ||
if (v === undefined) | ||
delete params[k]; | ||
const json = await this.get('/IPlayerService/GetOwnedGames/v1', params); | ||
return json.response.games.map((data) => { | ||
let game; | ||
if (opts.includeExtendedAppInfo) | ||
game = new GameInfoExtended(data); | ||
else if (opts.includeAppInfo) | ||
game = new GameInfo(data); | ||
else | ||
game = new Game(data); | ||
return new UserPlaytime(data, game); | ||
}); | ||
} | ||
/** | ||
* Get a user's recently played games. Note: <UserPlaytime>.game is GameInfo not just Game | ||
* | ||
* Like getUserOwnedGames() but only returns games played in the last 2 weeks | ||
* @param id User ID | ||
* @param count Number of results to limit the request to (0 means no limit) | ||
* @returns Recently played games and their play times | ||
*/ | ||
async getUserRecentGames(id, count = 0) { | ||
assertID(id); | ||
const json = await this.get('/IPlayerService/GetRecentlyPlayedGames/v1', { steamid: id, count }); | ||
return json.response.games.map((data) => new UserPlaytime(data, new GameInfoBasic(data))); | ||
} | ||
/** | ||
* Get a user's or multipler users' bans. If an array of IDs is passed in, this returns an array of UserBans | ||
* @param id User ID(s) | ||
* @returns Ban info | ||
*/ | ||
async getUserBans(id) { | ||
assertID(id); | ||
const arr = Array.isArray(id); | ||
const json = await this.get('/ISteamUser/GetPlayerBans/v1', { | ||
steamids: arr ? id.join(',') : id, | ||
}); | ||
const bans = json.players.map((player) => new UserBans(player)); | ||
return arr ? bans : bans[0]; | ||
} | ||
/** | ||
* Get a user's friends | ||
* @param id User ID | ||
* @returns The provided user's friends | ||
*/ | ||
async getUserFriends(id) { | ||
assertID(id); | ||
const json = await this.get('/ISteamUser/GetFriendList/v1', { steamid: id }); | ||
return json.friendslist.friends.map((friend) => new UserFriend(friend)); | ||
} | ||
/** | ||
* Get the groups the user is a member of | ||
* @param id User ID | ||
* @returns Group IDs | ||
*/ | ||
async getUserGroups(id) { | ||
assertID(id); | ||
const json = await this.get('/ISteamUser/GetUserGroupList/v1', { steamid: id }); | ||
if (!json.response.success) | ||
throw new Error(json.response.message); | ||
return json.response.groups.map((group) => group.gid); | ||
} | ||
/** | ||
* Gets servers on steamcommunity.com/dev/managegameservers using your key | ||
* @returns Your server | ||
*/ | ||
async getUserServers() { | ||
return new UserServers((await this.get('/IGameServersService/GetAccountList/v1')).response); | ||
} | ||
/** | ||
* Get users summary. If an array of IDs is passed in, this returns an array of UserSummary | ||
* @param id User ID(s) | ||
* @returns Summary | ||
*/ | ||
async getUserSummary(id) { | ||
assertID(id); | ||
const arr = Array.isArray(id); | ||
const json = await this.get('/ISteamUser/GetPlayerSummaries/v2', { steamids: arr ? id.join(',') : id }); | ||
if (!json.response.players.length) | ||
throw new Error('No players found'); | ||
const summaries = json.response.players.map((player) => new UserSummary(player)); | ||
return arr ? summaries : summaries[0]; | ||
} | ||
/** | ||
* Gets the Steam server's time | ||
* @returns Date object from the server | ||
*/ | ||
async getServerTime() { | ||
const json = await this.get('/ISteamWebAPIUtil/GetServerInfo/v1'); | ||
return new Date(json.servertime * 1000); | ||
} | ||
/** | ||
* Gets all the countries | ||
* @returns Array of country objects with fields countrycode, hasstates, and countryname | ||
*/ | ||
async getCountries() { | ||
return (await this.get('/QueryLocations', {}, this.baseActions)); | ||
} | ||
/** | ||
* Gets all the states for a particular country | ||
* @returns Array of state objects with fields countrycode, statecode, and statename | ||
*/ | ||
async getStates(countryCode) { | ||
return (await this.get(`/QueryLocations/${countryCode}`, {}, this.baseActions)); | ||
} | ||
/** | ||
* Gets all the cities for a particular state | ||
* @returns Array of city objects with fields countrycode, statecode, cityname and cityid | ||
*/ | ||
async getCities(countryCode, stateCode) { | ||
return (await this.get(`/QueryLocations/${countryCode}/${stateCode}`, {}, this.baseActions)); | ||
} | ||
/** | ||
* Gets servers using Master Server Query Protocol filtering | ||
* @param filter Filter as defined by the [Master Server Query Protocol](https://developer.valvesoftware.com/wiki/Master_Server_Query_Protocol#Filter). | ||
* Although a filter is not stricly required, you probably want to at least use something like \appid\[appid] to filter by app | ||
* @param count Number of results to return. 100 by default | ||
*/ | ||
async getServerList(filter = '', count = 100) { | ||
const json = await this.get('/IGameServersService/GetServerList/v1', { filter, count }); | ||
return json.response.servers.map((server) => new GameServer(server)); | ||
} | ||
} | ||
module.exports = SteamAPI; |
@@ -1,19 +0,16 @@ | ||
class Achievement { | ||
constructor(achievement) { | ||
this.api = achievement.apiname; | ||
this.name = achievement.name; | ||
this.description = achievement.description; | ||
this.achieved = Boolean(achievement.achieved); | ||
this.unlockTime = achievement.unlocktime; | ||
} | ||
/** | ||
* @type {Date} Date when this achievement was unlocked at. | ||
* @readonly | ||
*/ | ||
get unlockedAt() { | ||
return new Date(this.unlockTime * 1000); | ||
} | ||
} | ||
module.exports = Achievement; | ||
// class Achievement { | ||
// constructor(data) { | ||
// this.api = data.apiname; | ||
// this.name = data.name; | ||
// this.description = data.description; | ||
// this.achieved = Boolean(data.achieved); | ||
// this.unlockTime = data.unlocktime; | ||
// } | ||
export {}; | ||
// /** | ||
// * Date when this achievement was unlocked at. | ||
// */ | ||
// get unlockedAt() { | ||
// return new Date(this.unlockTime * 1000); | ||
// } | ||
// } |
const appBase = 'https://steamcdn-a.akamaihd.net/steam/apps'; | ||
const communityBase = 'https://steamcdn-a.akamaihd.net/steamcommunity/public/images/apps'; | ||
const cfBase = 'https://cdn.cloudflare.steamstatic.com/steam/apps'; | ||
class Game { | ||
constructor(game) { | ||
this.name = game.name; | ||
this.appID = game.appid; | ||
this.playTime = game.playtime_forever; | ||
this.playTime2 = game.playtime_2weeks || 0; | ||
// img_logo_url used to be a part of the api, now removed, but still documented | ||
this.logoURL = game.img_logo_url ? `${communityBase}/${this.appID}/${game.img_logo_url}.jpg` : null; | ||
// tiny app icon | ||
this.iconURL = `${communityBase}/${this.appID}/${game.img_icon_url}.jpg`; | ||
// Some of the following URLs aren't guaranteed to exist | ||
// large sized header used on the store page | ||
this.headerURL = `${cfBase}/${this.appID}/header.jpg`; | ||
// medium sized header image | ||
this.headerMediumURL = `${cfBase}/${this.appID}/capsule_231x87.jpg`; | ||
// small header image used on user pages | ||
this.smallHeaderURL = `${cfBase}/${this.appID}/capsule_184x69.jpg`; | ||
// tiny header image used on app bundles | ||
this.tinyHeaderURL = `${cfBase}/${this.appID}/capsule_sm_120.jpg`; | ||
// the following URLs are courtesy of | ||
// https://www.reddit.com/r/steamgrid/comments/d6ha6f/universal_link_for_downloading_games_cover/ | ||
// game page background | ||
this.backgroundURL = `${appBase}/${this.appID}/library_hero.jpg`; | ||
// game cover | ||
this.backgroundURL = `${appBase}/${this.appID}/library_600x900_2x.jpg`; | ||
// large transparent logo that appears in user's library | ||
this.logoURL = `${appBase}/${this.appID}/logo.png`; | ||
} | ||
export default class Game { | ||
/** App ID for this game */ | ||
id; | ||
constructor(data) { | ||
this.id = data.appid; | ||
} | ||
/** (might not exist) large sized header used on the store page */ | ||
get headerURL() { return `${cfBase}/${this.id}/header.jpg`; } | ||
/** (might not exist) medium sized header image */ | ||
get headerMediumURL() { return `${cfBase}/${this.id}/capsule_231x87.jpg`; } | ||
/** (might not exist) small header image used on user pages */ | ||
get smallHeaderURL() { return `${cfBase}/${this.id}/capsule_184x69.jpg`; } | ||
/** (might not exist) tiny header image used on app bundles */ | ||
get tinyHeaderURL() { return `${cfBase}/${this.id}/capsule_sm_120.jpg`; } | ||
// the following URLs are courtesy of | ||
// https://www.reddit.com/r/steamgrid/comments/d6ha6f/universal_link_for_downloading_games_cover/ | ||
/** (might not exist) game page background */ | ||
get backgroundURL() { return `${appBase}/${this.id}/library_hero.jpg`; } | ||
/** (might not exist) game cover */ | ||
get coverURL() { return `${appBase}/${this.id}/library_600x900_2x.jpg`; } | ||
/** (might not exist) transparent game logo*/ | ||
get logoURL() { return `${appBase}/${this.id}/logo.png`; } | ||
} | ||
module.exports = Game; |
@@ -1,29 +0,56 @@ | ||
class GameServer { | ||
constructor(server) { | ||
this.appID = server.appid; | ||
this.actor = server.actor; | ||
this.memo = server.memo; | ||
this.token = server.login_token; | ||
this.deleted = server.is_deleted; | ||
this.expired = server.is_expired; | ||
this.lastLoginTime = server.rt_last_logon; | ||
} | ||
/** | ||
* @type {boolean} Whether or not this token is usable. | ||
* @readonly | ||
*/ | ||
get usable() { | ||
return !this.deleted && !this.expired; | ||
} | ||
/** | ||
* @type {Date} Date the last time this token was used. | ||
* @readonly | ||
*/ | ||
get lastLoginAt() { | ||
return new Date(this.lastLoginTime * 1000); | ||
} | ||
/** Game server as returned by getServerList */ | ||
export default class GameServer { | ||
/** Server address of the form IPv4:PORT */ | ||
address; | ||
/** The port this server is running on */ | ||
port; | ||
/** The SteamID of this game server */ | ||
id; | ||
/** Public name of the server */ | ||
name; | ||
/** App ID this server is hosting */ | ||
appID; | ||
/** The directory the game is from */ | ||
gameDir; | ||
/** What version the server is running */ | ||
version; | ||
/** Product string. Not sure what this means. Is often the same as gameDir */ | ||
product; | ||
/** Server region */ | ||
region; | ||
/** Number of players in the server */ | ||
players; | ||
/** Max number of players that can join the server */ | ||
maxPlayers; | ||
/** Number of bots in the server */ | ||
bots; | ||
/** What map the game server is on */ | ||
map; | ||
/** Is this server VAC secured */ | ||
secure; | ||
/** Is the server running dedicated */ | ||
dedicated; | ||
/** What OS the server is running. Typically 'l' or 'w' */ | ||
os; | ||
/** Game specific sv_tags e.g. hidden,reserved,empty,secure */ | ||
tags; | ||
constructor(data) { | ||
this.address = data.addr; | ||
this.port = data.gameport; | ||
this.id = data.steamid; | ||
this.name = data.name; | ||
this.appID = data.appid; | ||
this.gameDir = data.gamedir; | ||
this.version = data.version; | ||
this.product = data.product; | ||
this.region = data.region; | ||
this.players = data.players; | ||
this.maxPlayers = data.max_players; | ||
this.bots = data.bots; | ||
this.map = data.map; | ||
this.secure = data.secure; | ||
this.dedicated = data.dedicated; | ||
this.os = data.os; | ||
this.tags = data.gametype.split(','); | ||
} | ||
} | ||
module.exports = GameServer; |
@@ -1,15 +0,51 @@ | ||
class Server { | ||
constructor(server) { | ||
this.address = server.addr; | ||
this.appID = server.appid; | ||
this.game = server.gamedir; | ||
this.gmsindex = server.gmsindex; | ||
this.lan = server.lan; | ||
this.port = server.gameport; | ||
this.region = server.region; | ||
this.secure = server.secure; | ||
this.specPort = server.specport; | ||
} | ||
/** Server regions as indicated by https://developer.valvesoftware.com/wiki/Sv_region */ | ||
export var ServerRegion; | ||
(function (ServerRegion) { | ||
ServerRegion[ServerRegion["USEast"] = 0] = "USEast"; | ||
ServerRegion[ServerRegion["USWest"] = 1] = "USWest"; | ||
ServerRegion[ServerRegion["SouthAmerica"] = 2] = "SouthAmerica"; | ||
ServerRegion[ServerRegion["Europe"] = 3] = "Europe"; | ||
ServerRegion[ServerRegion["Asia"] = 4] = "Asia"; | ||
ServerRegion[ServerRegion["Australia"] = 5] = "Australia"; | ||
ServerRegion[ServerRegion["MiddleEast"] = 6] = "MiddleEast"; | ||
ServerRegion[ServerRegion["Africa"] = 7] = "Africa"; | ||
ServerRegion[ServerRegion["World"] = 255] = "World"; | ||
})(ServerRegion || (ServerRegion = {})); | ||
/** Game server as returned by getServers */ | ||
export default class Server { | ||
/** The SteamID of this game server */ | ||
id; | ||
/** Server address of the form IPv4:PORT */ | ||
address; | ||
/** App ID this server is hosting */ | ||
appID; | ||
/** The directory the game is from */ | ||
gameDir; | ||
/** GMS Index. Not sure what this means */ | ||
gmsIndex; | ||
/** Is this server LAN only */ | ||
lan; | ||
/** The port this server is running on */ | ||
port; | ||
/** Server region */ | ||
region; | ||
/** Is this server VAC secured */ | ||
secure; | ||
/** Server specPort. Not sure what this means */ | ||
specPort; | ||
/** Requirements for clients to join server */ | ||
reject; | ||
constructor(data) { | ||
this.id = data.steamid; | ||
this.address = data.addr; | ||
this.appID = data.appid; | ||
this.gameDir = data.gamedir; | ||
this.gmsIndex = data.gmsindex; | ||
this.lan = data.lan; | ||
this.port = data.gameport; | ||
this.region = data.region; | ||
this.secure = data.secure; | ||
this.specPort = data.specport; | ||
this.reject = data.reject; | ||
} | ||
} | ||
module.exports = Server; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
No README
QualityPackage does not have a README. This may indicate a failed publish or a low quality package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No bug tracker
MaintenancePackage does not have a linked bug tracker in package.json.
Found 1 instance in 1 package
77268
59
1989
Yes
5
2
0
+ Addeddata-uri-to-buffer@4.0.1(transitive)
+ Addedfetch-blob@3.2.0(transitive)
+ Addedformdata-polyfill@4.0.10(transitive)
+ Addednode-domexception@1.0.0(transitive)
+ Addednode-fetch@3.3.2(transitive)
+ Addedweb-streams-polyfill@3.3.3(transitive)
- Removednode-fetch@2.7.0(transitive)
- Removedtr46@0.0.3(transitive)
- Removedwebidl-conversions@3.0.1(transitive)
- Removedwhatwg-url@5.0.0(transitive)
Updatednode-fetch@^3.3.2