Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

steamapi

Package Overview
Dependencies
Maintainers
1
Versions
42
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

steamapi - npm Package Compare versions

Comparing version 2.5.0 to 3.0.0

index.d.ts

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, };

79

package.json
{
"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;
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc