steamutils 1.5.37 → 1.5.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.idea/prettier.xml +0 -1
- package/_steamproto.js +51 -51
- package/index.js +286 -172
- package/package.json +1 -1
- package/steamproto.js +52 -52
- package/utils.js +1282 -1282
- package/.idea/gbrowser_project.xml +0 -11
- package/.idea/git_toolbox_blame.xml +0 -6
- package/.idea/git_toolbox_prj.xml +0 -15
- package/.idea/inspectionProfiles/Project_Default.xml +0 -6
- package/.idea/jsLinters/eslint.xml +0 -6
- package/full_steamproto.js +0 -53
- package/race.js +0 -2241
package/index.js
CHANGED
@@ -4,8 +4,6 @@ import _ from "lodash";
|
|
4
4
|
import moment from "moment";
|
5
5
|
import { hex2b64, Key as RSA } from "node-bignumber";
|
6
6
|
import SteamID from "steamid";
|
7
|
-
import URL from "url";
|
8
|
-
import Url from "url-parse";
|
9
7
|
import qs from "qs";
|
10
8
|
import { console_log, convertLongsToNumbers, downloadImage, formatMarketHistoryDate, getCleanObject, getImageSize, JSON_parse, JSON_stringify, removeSpaceKeys, secretAsBuffer, sleep } from "./utils.js";
|
11
9
|
import { Header, request } from "./axios.js";
|
@@ -1057,91 +1055,20 @@ export default class SteamUser {
|
|
1057
1055
|
throw new Error(`[${this._sessionId}] You have not set cookie yet`);
|
1058
1056
|
}
|
1059
1057
|
|
1060
|
-
|
1061
|
-
params = { url: params };
|
1062
|
-
}
|
1063
|
-
const isRedirect = typeof params.isRedirect === "boolean" ? params.isRedirect : true;
|
1064
|
-
delete params.isRedirect;
|
1065
|
-
if (!params.url.startsWith("http")) {
|
1066
|
-
params.url = _.trimEnd(SteamcommunityURL, "/") + "/" + _.trimStart(params.url, "/");
|
1067
|
-
}
|
1068
|
-
const originalURL = params.url;
|
1069
|
-
|
1070
|
-
//format URL
|
1071
|
-
const urlObject = URL.parse(params.url);
|
1072
|
-
const queryList = (urlObject.query || "")
|
1073
|
-
.split("&")
|
1074
|
-
.map((query) => query.trim())
|
1075
|
-
.filter(Boolean);
|
1076
|
-
if (!queryList.some((q) => q.toLowerCase().startsWith("sessionid".toLowerCase()))) {
|
1077
|
-
queryList.push(`sessionid=${this.getSessionid()}`);
|
1078
|
-
}
|
1079
|
-
if (!queryList.some((q) => q.toLowerCase().startsWith("l".toLowerCase()))) {
|
1080
|
-
queryList.push(`l=english`);
|
1081
|
-
}
|
1082
|
-
const protocol = urlObject.protocol ? `${urlObject.protocol}//${urlObject.host}` : "";
|
1083
|
-
params.url = `${protocol}${urlObject.pathname}?${queryList.join("&")}`;
|
1084
|
-
|
1085
|
-
if (!(params.headers instanceof Header)) {
|
1086
|
-
params.headers = new Header(params.headers);
|
1087
|
-
}
|
1088
|
-
|
1089
|
-
params.headers.set({
|
1090
|
-
accept: "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
|
1091
|
-
"accept-language": "en-US,en;q=0.9",
|
1092
|
-
"cache-control": "no-cache",
|
1093
|
-
pragma: "no-cache",
|
1094
|
-
"sec-ch-ua": '"Not A(Brand";v="99", "Google Chrome";v="121", "Chromium";v="121"',
|
1095
|
-
"sec-ch-ua-mobile": "?0",
|
1096
|
-
"sec-ch-ua-platform": '"Windows"',
|
1097
|
-
"sec-fetch-dest": "document",
|
1098
|
-
"sec-fetch-mode": "navigate",
|
1099
|
-
"sec-fetch-site": "none",
|
1100
|
-
"sec-fetch-user": "?1",
|
1101
|
-
"upgrade-insecure-requests": "1",
|
1102
|
-
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36",
|
1103
|
-
});
|
1104
|
-
|
1105
|
-
if (params.ajax) {
|
1106
|
-
params.headers.set({
|
1107
|
-
"X-KL-Ajax-Request": "Ajax_Request",
|
1108
|
-
"X-Prototype-Version": "1.7",
|
1109
|
-
"X-Requested-With": "XMLHttpRequest",
|
1110
|
-
});
|
1111
|
-
}
|
1112
|
-
delete params.ajax;
|
1113
|
-
|
1114
|
-
let referer = params.headers.get("referer");
|
1115
|
-
if (!referer) {
|
1116
|
-
const urlObject = URL.parse(params.url);
|
1117
|
-
if (urlObject.protocol && urlObject.host) {
|
1118
|
-
referer = urlObject.protocol + "//" + urlObject.host;
|
1119
|
-
} else {
|
1120
|
-
referer = SteamcommunityURL;
|
1121
|
-
}
|
1122
|
-
params.headers.set("referer", referer);
|
1123
|
-
}
|
1124
|
-
|
1125
|
-
if (!params.method) {
|
1126
|
-
params.method = "GET";
|
1127
|
-
}
|
1128
|
-
|
1129
|
-
params.method = params.method.toUpperCase();
|
1130
|
-
if (!params.timeout) {
|
1131
|
-
params.timeout = 2 * 60000;
|
1132
|
-
}
|
1058
|
+
const normalizedParams = normalizeParams(params, this.getSessionid());
|
1133
1059
|
|
1134
1060
|
let response = null;
|
1135
1061
|
const maxRedirect = 10;
|
1136
1062
|
let redirectCount = 0;
|
1137
1063
|
|
1138
|
-
async function
|
1064
|
+
async function requestOnce(_params, cookie) {
|
1139
1065
|
let data = params.data ? params.data : {};
|
1140
1066
|
const _sessionId = cookie.getCookie("sessionid");
|
1141
1067
|
if (!_sessionId) return;
|
1142
1068
|
|
1143
1069
|
if (params.method === "POST") {
|
1144
|
-
|
1070
|
+
const contentType = params.headers.get("content-type")?.toLowerCase();
|
1071
|
+
if (contentType === "multipart/form-data") {
|
1145
1072
|
if (data && !(data instanceof FormData) && typeof data === "object") {
|
1146
1073
|
const form = new FormData();
|
1147
1074
|
for (const name in data) {
|
@@ -1202,6 +1129,9 @@ export default class SteamUser {
|
|
1202
1129
|
data,
|
1203
1130
|
};
|
1204
1131
|
|
1132
|
+
delete config.originalURL;
|
1133
|
+
delete config.isRedirect;
|
1134
|
+
|
1205
1135
|
let _response = null;
|
1206
1136
|
try {
|
1207
1137
|
if (SteamUser.LOG_REQUEST) {
|
@@ -1233,7 +1163,7 @@ export default class SteamUser {
|
|
1233
1163
|
}
|
1234
1164
|
|
1235
1165
|
if (_response?.status === 302 && !redirectURL?.startsWith("https://steamcommunity.com/login/") && redirectCount++ < maxRedirect) {
|
1236
|
-
return await
|
1166
|
+
return await requestOnce(
|
1237
1167
|
{
|
1238
1168
|
...config,
|
1239
1169
|
headers: {
|
@@ -1249,14 +1179,14 @@ export default class SteamUser {
|
|
1249
1179
|
return _response;
|
1250
1180
|
}
|
1251
1181
|
|
1252
|
-
async function
|
1182
|
+
async function tryRequestWithCookies(cookies, params) {
|
1253
1183
|
if (!Array.isArray(cookies)) {
|
1254
1184
|
cookies = [cookies];
|
1255
1185
|
}
|
1256
1186
|
|
1257
1187
|
for (const cookie of cookies) {
|
1258
1188
|
redirectCount = 0;
|
1259
|
-
response = await
|
1189
|
+
response = await requestOnce(
|
1260
1190
|
{
|
1261
1191
|
baseURL: SteamcommunityURL,
|
1262
1192
|
...params,
|
@@ -1266,32 +1196,13 @@ export default class SteamUser {
|
|
1266
1196
|
);
|
1267
1197
|
|
1268
1198
|
if (response) {
|
1269
|
-
|
1270
|
-
|
1271
|
-
|
1272
|
-
const title = $("head > title").text().trim();
|
1273
|
-
const errorMsg = $("#error_msg").text().trim();
|
1274
|
-
const headline = $("#headline").text().trim();
|
1275
|
-
|
1276
|
-
if (title && SteamErrorTitle.includes(title)) {
|
1277
|
-
return new ResponseError({
|
1278
|
-
message: errorMsg || "Steam Community :: Error",
|
1279
|
-
steamId: self._steamIdUser,
|
1280
|
-
originalURL,
|
1281
|
-
});
|
1282
|
-
} else if (title === "Error" && headline === "Something Went Wrong") {
|
1283
|
-
return new ResponseError({
|
1284
|
-
message: headline,
|
1285
|
-
detail: $("#message").text().trim(),
|
1286
|
-
steamId: self._steamIdUser,
|
1287
|
-
originalURL,
|
1288
|
-
});
|
1289
|
-
}
|
1290
|
-
}
|
1199
|
+
// Try to parse steam "HTML" errors
|
1200
|
+
const htmlError = parseSteamHtmlError(response?.data, params.originalURL, self._steamIdUser);
|
1201
|
+
if (htmlError) return htmlError;
|
1291
1202
|
|
1292
1203
|
switch (response.status) {
|
1293
1204
|
case 302: {
|
1294
|
-
if (isRedirect) {
|
1205
|
+
if (params.isRedirect) {
|
1295
1206
|
const redirectURL = response.headers.location;
|
1296
1207
|
|
1297
1208
|
if (redirectURL?.startsWith("https://steamcommunity.com/id/")) {
|
@@ -1300,7 +1211,7 @@ export default class SteamUser {
|
|
1300
1211
|
self._customURL = customURL;
|
1301
1212
|
}
|
1302
1213
|
} else if (redirectURL?.startsWith("https://steamcommunity.com/login/")) {
|
1303
|
-
console.error("Login first", originalURL, self._steamIdUser);
|
1214
|
+
console.error("Login first", params.originalURL, self._steamIdUser);
|
1304
1215
|
if (self._steamIdUser) {
|
1305
1216
|
eventEmitter.emit("login_first", {
|
1306
1217
|
steamId: self._steamIdUser,
|
@@ -1311,7 +1222,7 @@ export default class SteamUser {
|
|
1311
1222
|
response = new ResponseError({
|
1312
1223
|
loginFirst: true,
|
1313
1224
|
steamId: self._steamIdUser,
|
1314
|
-
originalURL,
|
1225
|
+
originalURL: params.originalURL,
|
1315
1226
|
});
|
1316
1227
|
continue;
|
1317
1228
|
}
|
@@ -1392,13 +1303,13 @@ export default class SteamUser {
|
|
1392
1303
|
}
|
1393
1304
|
}
|
1394
1305
|
|
1395
|
-
await
|
1306
|
+
await tryRequestWithCookies(this._cookies, normalizedParams);
|
1396
1307
|
|
1397
1308
|
if (response instanceof ResponseError && response.loginFirst && typeof self._refreshCookie === "function") {
|
1398
1309
|
//refresh cookie
|
1399
1310
|
const newCookie = await self._refreshCookie();
|
1400
1311
|
if (newCookie) {
|
1401
|
-
await
|
1312
|
+
await tryRequestWithCookies(newCookie, normalizedParams);
|
1402
1313
|
|
1403
1314
|
if (!(response instanceof ResponseError)) {
|
1404
1315
|
if (typeof self._onRefreshCookie === "function") {
|
@@ -1407,7 +1318,6 @@ export default class SteamUser {
|
|
1407
1318
|
self._cookies.unshift(new CookieManager(newCookie));
|
1408
1319
|
}
|
1409
1320
|
}
|
1410
|
-
console.log("");
|
1411
1321
|
}
|
1412
1322
|
|
1413
1323
|
// while (--retry) {
|
@@ -1668,38 +1578,42 @@ export default class SteamUser {
|
|
1668
1578
|
|
1669
1579
|
static _formatGroupLink({ link, gid, groupURL, page, content_only, searchKey, pathname = "" }) {
|
1670
1580
|
searchKey = searchKey?.trim?.();
|
1581
|
+
|
1582
|
+
// Build the path if no link provided
|
1671
1583
|
if (!link) {
|
1672
1584
|
link = gid ? `gid/${gid}/?p=${page}` : `groups/${groupURL}/?p=${page}`;
|
1673
1585
|
}
|
1674
|
-
link = new Url(link);
|
1675
|
-
link.query =
|
1676
|
-
"?" +
|
1677
|
-
[
|
1678
|
-
...link.query
|
1679
|
-
.removePrefix("?")
|
1680
|
-
.split("&")
|
1681
|
-
.map((q) => q.split("="))
|
1682
|
-
.filter((q) => !["searchKey", "content_only"].includes(q[0]))
|
1683
|
-
.map((q) => q.join("=")),
|
1684
|
-
!!content_only && `content_only=true`,
|
1685
|
-
!!searchKey && `searchKey=${encodeURIComponent(searchKey)}`,
|
1686
|
-
]
|
1687
|
-
.filter(Boolean)
|
1688
|
-
.join("&");
|
1689
1586
|
|
1587
|
+
// Always build an absolute URL
|
1588
|
+
let base = SteamcommunityURL.endsWith("/") ? SteamcommunityURL : SteamcommunityURL + "/";
|
1589
|
+
|
1590
|
+
// Try to guard against double slash, e.g., if link starts with /
|
1591
|
+
let urlStr = link.startsWith("http://") || link.startsWith("https://") ? link : link.startsWith("/") ? base.replace(/\/$/, "") + link : base + link;
|
1592
|
+
|
1593
|
+
const urlObj = new URL(urlStr);
|
1594
|
+
|
1595
|
+
// Remove searchKey and content_only from query
|
1596
|
+
urlObj.searchParams.delete("searchKey");
|
1597
|
+
urlObj.searchParams.delete("content_only");
|
1598
|
+
|
1599
|
+
// Add/overwrite provided query parameters
|
1600
|
+
if (content_only) urlObj.searchParams.set("content_only", "true");
|
1601
|
+
if (searchKey) urlObj.searchParams.set("searchKey", encodeURIComponent(searchKey));
|
1602
|
+
|
1603
|
+
// Pathname adjustment
|
1690
1604
|
if (pathname) {
|
1691
|
-
let _pathname =
|
1605
|
+
let _pathname = urlObj.pathname.replace(/\/$/, "");
|
1692
1606
|
if (!_pathname.endsWith(pathname)) {
|
1693
|
-
|
1607
|
+
urlObj.pathname = _pathname + "/" + pathname.replace(/^\//, "") + "/";
|
1694
1608
|
}
|
1695
1609
|
}
|
1696
1610
|
|
1697
|
-
|
1698
|
-
if (
|
1699
|
-
|
1611
|
+
// Ensure leading "/" for pathname
|
1612
|
+
if (urlObj.pathname && !urlObj.pathname.startsWith("/")) {
|
1613
|
+
urlObj.pathname = "/" + urlObj.pathname;
|
1700
1614
|
}
|
1701
1615
|
|
1702
|
-
return
|
1616
|
+
return urlObj.toString();
|
1703
1617
|
}
|
1704
1618
|
|
1705
1619
|
static _parseGroupInfo(html) {
|
@@ -5966,20 +5880,16 @@ export default class SteamUser {
|
|
5966
5880
|
|
5967
5881
|
static parseTradeURL(tradeURL) {
|
5968
5882
|
try {
|
5969
|
-
const
|
5970
|
-
|
5971
|
-
|
5972
|
-
|
5973
|
-
|
5974
|
-
[currentValue.split("=")[0]]: currentValue.split("=")[1],
|
5975
|
-
}),
|
5976
|
-
{},
|
5977
|
-
);
|
5883
|
+
const urlObj = new URL(tradeURL);
|
5884
|
+
const params = urlObj.searchParams;
|
5885
|
+
|
5886
|
+
const partner = params.get("partner");
|
5887
|
+
const token = params.get("token");
|
5978
5888
|
|
5979
5889
|
return {
|
5980
|
-
accountId:
|
5981
|
-
steamId: SteamID.fromIndividualAccountID(
|
5982
|
-
token:
|
5890
|
+
accountId: partner,
|
5891
|
+
steamId: partner ? SteamID.fromIndividualAccountID(partner).getSteamID64() : undefined,
|
5892
|
+
token: token,
|
5983
5893
|
};
|
5984
5894
|
} catch (e) {}
|
5985
5895
|
}
|
@@ -7215,6 +7125,27 @@ export default class SteamUser {
|
|
7215
7125
|
];
|
7216
7126
|
}
|
7217
7127
|
|
7128
|
+
/**
|
7129
|
+
* @typedef {Object} RedeemPointsResponse
|
7130
|
+
* @property {number[]} bundle_community_item_ids - Array of community item IDs in the bundle. May be empty.
|
7131
|
+
* @property {number} communityitemid - The redeemed community item ID.
|
7132
|
+
*/
|
7133
|
+
|
7134
|
+
/**
|
7135
|
+
* Redeems Steam Points for a specified reward definition.
|
7136
|
+
*
|
7137
|
+
* @async
|
7138
|
+
* @param {string} accessToken - The user's Steam OAuth access token.
|
7139
|
+
* @param {number|string} definitionId - The definition ID for the reward to redeem.
|
7140
|
+
* @returns {Promise<?RedeemPointsResponse>} A promise that resolves to the redemption response object,
|
7141
|
+
* or null/undefined if unsuccessful.
|
7142
|
+
*
|
7143
|
+
* @example
|
7144
|
+
* {
|
7145
|
+
* bundle_community_item_ids: [],
|
7146
|
+
* communityitemid: 34336330688
|
7147
|
+
* }
|
7148
|
+
*/
|
7218
7149
|
async redeemPoints(accessToken, definitionId) {
|
7219
7150
|
if (!definitionId) {
|
7220
7151
|
return;
|
@@ -7516,6 +7447,49 @@ export default class SteamUser {
|
|
7516
7447
|
};
|
7517
7448
|
}
|
7518
7449
|
|
7450
|
+
/**
|
7451
|
+
* Enumerates all refresh tokens associated with the given Steam access token.
|
7452
|
+
*
|
7453
|
+
* Makes a POST request to the Steam API to retrieve all refresh tokens for the provided access token.
|
7454
|
+
*
|
7455
|
+
* @async
|
7456
|
+
* @param {string} accessToken - The Steam access token to enumerate tokens for.
|
7457
|
+
* @returns {Promise<{
|
7458
|
+
* response: {
|
7459
|
+
* refresh_tokens: Array<{
|
7460
|
+
* token_id: string,
|
7461
|
+
* token_description: string,
|
7462
|
+
* time_updated: number,
|
7463
|
+
* platform_type: number,
|
7464
|
+
* logged_in: boolean,
|
7465
|
+
* os_platform: number,
|
7466
|
+
* auth_type: number,
|
7467
|
+
* gaming_device_type?: number,
|
7468
|
+
* first_seen: {
|
7469
|
+
* time: number
|
7470
|
+
* },
|
7471
|
+
* last_seen: {
|
7472
|
+
* time: number,
|
7473
|
+
* ip?: {
|
7474
|
+
* v4?: number
|
7475
|
+
* },
|
7476
|
+
* country?: string,
|
7477
|
+
* state?: string,
|
7478
|
+
* city?: string
|
7479
|
+
* },
|
7480
|
+
* os_type: number,
|
7481
|
+
* authentication_type: number
|
7482
|
+
* }>,
|
7483
|
+
* requesting_token: string
|
7484
|
+
* }
|
7485
|
+
* } | undefined>} Resolves with Steam API token enumeration response on success, or undefined on invalid input or network error.
|
7486
|
+
*
|
7487
|
+
* @example
|
7488
|
+
* const tokens = await enumerateTokens(mySteamAccessToken);
|
7489
|
+
* if (tokens) {
|
7490
|
+
* console.log(tokens.response.refresh_tokens);
|
7491
|
+
* }
|
7492
|
+
*/
|
7519
7493
|
async enumerateTokens(accessToken) {
|
7520
7494
|
if (!accessToken || typeof accessToken !== "string") {
|
7521
7495
|
console.error("revokeAccessToken", "invalid accessToken", accessToken);
|
@@ -7539,37 +7513,6 @@ export default class SteamUser {
|
|
7539
7513
|
}
|
7540
7514
|
|
7541
7515
|
return result?.data;
|
7542
|
-
|
7543
|
-
const data = {
|
7544
|
-
response: {
|
7545
|
-
refresh_tokens: [
|
7546
|
-
{
|
7547
|
-
token_id: "6524101908770518402",
|
7548
|
-
token_description: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36",
|
7549
|
-
time_updated: 1713256963,
|
7550
|
-
platform_type: 2,
|
7551
|
-
logged_in: true,
|
7552
|
-
os_platform: 2,
|
7553
|
-
auth_type: 4,
|
7554
|
-
first_seen: {
|
7555
|
-
time: 1713256963,
|
7556
|
-
},
|
7557
|
-
last_seen: {
|
7558
|
-
time: 1715595247,
|
7559
|
-
ip: {
|
7560
|
-
v4: 250140346,
|
7561
|
-
},
|
7562
|
-
country: "VN",
|
7563
|
-
state: "Ha Noi",
|
7564
|
-
city: "Hanoi",
|
7565
|
-
},
|
7566
|
-
os_type: 0,
|
7567
|
-
authentication_type: 2,
|
7568
|
-
},
|
7569
|
-
],
|
7570
|
-
requesting_token: "6524101908770518402",
|
7571
|
-
},
|
7572
|
-
};
|
7573
7516
|
}
|
7574
7517
|
|
7575
7518
|
async hasToken(accessToken, tokenId) {
|
@@ -7880,6 +7823,87 @@ export default class SteamUser {
|
|
7880
7823
|
return response;
|
7881
7824
|
}
|
7882
7825
|
|
7826
|
+
/**
|
7827
|
+
* @typedef {Object} SteamStoreItemsResponse
|
7828
|
+
* @property {Array<SteamStoreItem>} store_items - Array of store item objects.
|
7829
|
+
*/
|
7830
|
+
|
7831
|
+
/**
|
7832
|
+
* @typedef {Object} SteamStoreItem
|
7833
|
+
* @property {Array} included_types
|
7834
|
+
* @property {Array} included_appids
|
7835
|
+
* @property {Array<number>} content_descriptorids
|
7836
|
+
* @property {Array} tagids
|
7837
|
+
* @property {Array} tags
|
7838
|
+
* @property {Array} purchase_options
|
7839
|
+
* @property {Array} accessories
|
7840
|
+
* @property {Array} supported_languages
|
7841
|
+
* @property {number} item_type
|
7842
|
+
* @property {number} id
|
7843
|
+
* @property {number} success
|
7844
|
+
* @property {boolean} visible
|
7845
|
+
* @property {boolean} unvailable_for_country_restriction
|
7846
|
+
* @property {string} name
|
7847
|
+
* @property {string} store_url_path
|
7848
|
+
* @property {number} appid
|
7849
|
+
* @property {number} type
|
7850
|
+
* @property {boolean} is_free
|
7851
|
+
* @property {boolean} is_early_access
|
7852
|
+
* @property {?null} related_items
|
7853
|
+
* @property {?null} included_items
|
7854
|
+
* @property {SteamStoreItemCategories} categories
|
7855
|
+
* @property {?null} reviews
|
7856
|
+
* @property {?null} basic_info
|
7857
|
+
* @property {SteamStoreItemAssets} assets
|
7858
|
+
* @property {?null} release
|
7859
|
+
* @property {?null} platforms
|
7860
|
+
* @property {?null} game_rating
|
7861
|
+
* @property {?null} best_purchase_option
|
7862
|
+
* @property {?null} self_purchase_option
|
7863
|
+
* @property {?null} screenshots
|
7864
|
+
* @property {?null} trailers
|
7865
|
+
* @property {string} store_url_path_override
|
7866
|
+
* @property {?null} free_weekend
|
7867
|
+
* @property {boolean} unlisted
|
7868
|
+
* @property {number} game_count
|
7869
|
+
* @property {string} internal_name
|
7870
|
+
* @property {string} full_description
|
7871
|
+
* @property {boolean} is_free_temporarily
|
7872
|
+
* @property {?null} assets_without_overrides
|
7873
|
+
* @property {?null} user_filter_failure
|
7874
|
+
*/
|
7875
|
+
|
7876
|
+
/**
|
7877
|
+
* @typedef {Object} SteamStoreItemCategories
|
7878
|
+
* @property {Array<number>} supported_player_categoryids
|
7879
|
+
* @property {Array<number>} feature_categoryids
|
7880
|
+
* @property {Array<number>} controller_categoryids
|
7881
|
+
*/
|
7882
|
+
|
7883
|
+
/**
|
7884
|
+
* @typedef {Object} SteamStoreItemAssets
|
7885
|
+
* @property {string} asset_url_format
|
7886
|
+
* @property {string} main_capsule
|
7887
|
+
* @property {string} small_capsule
|
7888
|
+
* @property {string} header
|
7889
|
+
* @property {string} package_header
|
7890
|
+
* @property {string} page_background
|
7891
|
+
* @property {string} hero_capsule
|
7892
|
+
* @property {string} hero_capsule_2x
|
7893
|
+
* @property {string} library_capsule
|
7894
|
+
* @property {string} library_capsule_2x
|
7895
|
+
* @property {string} library_hero
|
7896
|
+
* @property {string} library_hero_2x
|
7897
|
+
* @property {string} community_icon
|
7898
|
+
* @property {string} clan_avatar
|
7899
|
+
*/
|
7900
|
+
|
7901
|
+
/**
|
7902
|
+
* Retrieves Steam Store items given app IDs. Wraps Steam API call and returns strong-typed results.
|
7903
|
+
*
|
7904
|
+
* @param {number|number[]} appIds A single Steam appid or an array of appids.
|
7905
|
+
* @returns {Promise<SteamStoreItemsResponse|undefined>} Returns the Steam Store API response containing store_items, or undefined if appIds is not provided.
|
7906
|
+
*/
|
7883
7907
|
static async getSteamStoreItems(appIds) {
|
7884
7908
|
if (!appIds) {
|
7885
7909
|
return;
|
@@ -8264,6 +8288,95 @@ export default class SteamUser {
|
|
8264
8288
|
|
8265
8289
|
SteamUser.MAX_RETRY = 10;
|
8266
8290
|
|
8291
|
+
// Helper: Ensure URL has sessionid and language
|
8292
|
+
function ensureSessionIdAndLangInUrl(url, sessionId) {
|
8293
|
+
const urlObj = new URL(url);
|
8294
|
+
if (![...urlObj.searchParams.keys()].some((k) => k.toLowerCase() === "sessionid")) {
|
8295
|
+
urlObj.searchParams.append("sessionid", sessionId);
|
8296
|
+
}
|
8297
|
+
if (![...urlObj.searchParams.keys()].some((k) => k.toLowerCase() === "l")) {
|
8298
|
+
urlObj.searchParams.append("l", "english");
|
8299
|
+
}
|
8300
|
+
return urlObj.toString();
|
8301
|
+
}
|
8302
|
+
|
8303
|
+
// Pure HTML error parser
|
8304
|
+
function parseSteamHtmlError(html, originalURL, steamId) {
|
8305
|
+
if (!html || typeof html !== "string") {
|
8306
|
+
return;
|
8307
|
+
}
|
8308
|
+
const $ = cheerio.load(html.replace(/[\t\n\r]/gi, "").trim());
|
8309
|
+
const title = $("head > title").text().trim();
|
8310
|
+
const errorMsg = $("#error_msg").text().trim();
|
8311
|
+
const headline = $("#headline").text().trim();
|
8312
|
+
if (title && SteamErrorTitle.includes(title)) {
|
8313
|
+
return new ResponseError({ message: errorMsg || "Steam Community :: Error", steamId, originalURL });
|
8314
|
+
} else if (title === "Error" && headline === "Something Went Wrong") {
|
8315
|
+
return new ResponseError({ message: headline, detail: $("#message").text().trim(), steamId, originalURL });
|
8316
|
+
}
|
8317
|
+
}
|
8318
|
+
|
8319
|
+
function normalizeParams(params, sessionId) {
|
8320
|
+
if (typeof params === "string") {
|
8321
|
+
params = { url: params };
|
8322
|
+
}
|
8323
|
+
|
8324
|
+
if (!params.url.startsWith("http")) {
|
8325
|
+
params.url = _.trimEnd(SteamcommunityURL, "/") + "/" + _.trimStart(params.url, "/");
|
8326
|
+
}
|
8327
|
+
params.originalURL = params.url;
|
8328
|
+
params.url = ensureSessionIdAndLangInUrl(params.url, sessionId);
|
8329
|
+
|
8330
|
+
if (!(params.headers instanceof Header)) {
|
8331
|
+
params.headers = new Header(params.headers);
|
8332
|
+
}
|
8333
|
+
|
8334
|
+
params.headers.set(defaultHeaders());
|
8335
|
+
|
8336
|
+
if (params.ajax) {
|
8337
|
+
params.headers.set(ajaxHeaders());
|
8338
|
+
delete params.ajax;
|
8339
|
+
}
|
8340
|
+
|
8341
|
+
if (!params.headers.get("referer")) {
|
8342
|
+
const urlObj = new URL(params.url);
|
8343
|
+
const referer = urlObj.protocol && urlObj.host ? `${urlObj.protocol}//${urlObj.host}` : SteamcommunityURL;
|
8344
|
+
params.headers.set("referer", referer);
|
8345
|
+
}
|
8346
|
+
|
8347
|
+
params.method = (params.method || "GET").toUpperCase();
|
8348
|
+
params.timeout = params.timeout || 2 * 60000;
|
8349
|
+
params.isRedirect = typeof params.isRedirect === "boolean" ? params.isRedirect : true;
|
8350
|
+
|
8351
|
+
return params;
|
8352
|
+
}
|
8353
|
+
|
8354
|
+
function defaultHeaders() {
|
8355
|
+
return {
|
8356
|
+
accept: "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
|
8357
|
+
"accept-language": "en-US,en;q=0.9",
|
8358
|
+
"cache-control": "no-cache",
|
8359
|
+
pragma: "no-cache",
|
8360
|
+
"sec-ch-ua": '"Not A(Brand";v="99", "Google Chrome";v="121", "Chromium";v="121"',
|
8361
|
+
"sec-ch-ua-mobile": "?0",
|
8362
|
+
"sec-ch-ua-platform": '"Windows"',
|
8363
|
+
"sec-fetch-dest": "document",
|
8364
|
+
"sec-fetch-mode": "navigate",
|
8365
|
+
"sec-fetch-site": "none",
|
8366
|
+
"sec-fetch-user": "?1",
|
8367
|
+
"upgrade-insecure-requests": "1",
|
8368
|
+
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36",
|
8369
|
+
};
|
8370
|
+
}
|
8371
|
+
|
8372
|
+
function ajaxHeaders() {
|
8373
|
+
return {
|
8374
|
+
"X-KL-Ajax-Request": "Ajax_Request",
|
8375
|
+
"X-Prototype-Version": "1.7",
|
8376
|
+
"X-Requested-With": "XMLHttpRequest",
|
8377
|
+
};
|
8378
|
+
}
|
8379
|
+
|
8267
8380
|
export class ResponseError {
|
8268
8381
|
constructor({ loginFirst, message, steamId, originalURL }) {
|
8269
8382
|
this.loginFirst = loginFirst;
|
@@ -8280,6 +8393,7 @@ export class ResponseError {
|
|
8280
8393
|
return false;
|
8281
8394
|
}
|
8282
8395
|
}
|
8396
|
+
|
8283
8397
|
export class ResponseSuccess {
|
8284
8398
|
constructor(response) {
|
8285
8399
|
this.response = response;
|