@assetpay/steam-mobile 1.0.5 → 1.1.0

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/dist/index.mjs CHANGED
@@ -68,6 +68,7 @@ let EConfirmationType = /* @__PURE__ */ function(EConfirmationType) {
68
68
  EConfirmationType[EConfirmationType["FeatureOptOut"] = 4] = "FeatureOptOut";
69
69
  EConfirmationType[EConfirmationType["PhoneNumberChange"] = 5] = "PhoneNumberChange";
70
70
  EConfirmationType[EConfirmationType["AccountRecovery"] = 6] = "AccountRecovery";
71
+ EConfirmationType[EConfirmationType["BuyOrder"] = 12] = "BuyOrder";
71
72
  return EConfirmationType;
72
73
  }({});
73
74
  let EOfferFilter = /* @__PURE__ */ function(EOfferFilter) {
@@ -306,6 +307,13 @@ var RateLimitError = class extends SteamError {
306
307
  this.unlockAt = Date.now() + this.retryAfterMs;
307
308
  }
308
309
  };
310
+ var ThrottledError = class extends SteamError {
311
+ statusCode = 403;
312
+ constructor(message = "Throttled (403)", options) {
313
+ super(message, options);
314
+ this.name = "ThrottledError";
315
+ }
316
+ };
309
317
  var EscrowError = class extends SteamError {
310
318
  escrowDays;
311
319
  constructor(escrowDays, message) {
@@ -362,6 +370,24 @@ var PrivateInventoryError = class extends SteamError {
362
370
  this.name = "PrivateInventoryError";
363
371
  }
364
372
  };
373
+ var MarketConfirmationLimitError = class extends SteamError {
374
+ constructor(message = "Too many listings pending confirmation", options) {
375
+ super(message, options);
376
+ this.name = "MarketConfirmationLimitError";
377
+ }
378
+ };
379
+ var WalletBalanceLimitError = class extends SteamError {
380
+ constructor(message = "Listing would exceed the maximum wallet balance", options) {
381
+ super(message, options);
382
+ this.name = "WalletBalanceLimitError";
383
+ }
384
+ };
385
+ var MarketBlockedError = class extends SteamError {
386
+ constructor(message = "This account is currently unable to use the Community Market", options) {
387
+ super(message, options);
388
+ this.name = "MarketBlockedError";
389
+ }
390
+ };
365
391
  var LoginError = class extends SteamError {
366
392
  extendedErrorMessage;
367
393
  isTransient;
@@ -1292,7 +1318,7 @@ function queryParams(url) {
1292
1318
  for (const [k, v] of new URL(url).searchParams) out[k] = v;
1293
1319
  return out;
1294
1320
  }
1295
- function decodeEntities(s) {
1321
+ function decodeEntities$1(s) {
1296
1322
  return s.replace(/&quot;/g, "\"").replace(/&#0?39;/g, "'").replace(/&apos;/g, "'").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&amp;/g, "&");
1297
1323
  }
1298
1324
  function parseOpenidForm(html) {
@@ -1303,14 +1329,14 @@ function parseOpenidForm(html) {
1303
1329
  for (const tag of (form[2] ?? "").match(/<input\b[^>]*>/gi) ?? []) {
1304
1330
  const name = tag.match(/\bname=["']([^"']*)["']/i)?.[1];
1305
1331
  if (!name) continue;
1306
- const value = decodeEntities(tag.match(/\bvalue=["']([^"']*)["']/i)?.[1] ?? "");
1332
+ const value = decodeEntities$1(tag.match(/\bvalue=["']([^"']*)["']/i)?.[1] ?? "");
1307
1333
  fields.push({
1308
1334
  name,
1309
1335
  value
1310
1336
  });
1311
1337
  }
1312
1338
  return {
1313
- action: new URL(decodeEntities(action), STEAM_OPENID_URL).toString(),
1339
+ action: new URL(decodeEntities$1(action), STEAM_OPENID_URL).toString(),
1314
1340
  fields
1315
1341
  };
1316
1342
  }
@@ -1472,6 +1498,16 @@ var CommunityNamespace = class {
1472
1498
  input: { steamid: id }
1473
1499
  })).response?.player_level ?? 0;
1474
1500
  }
1501
+ async getTwoFactorStatus() {
1502
+ const body = await this.api.call({
1503
+ httpMethod: "POST",
1504
+ iface: "ITwoFactorService",
1505
+ method: "QueryStatus",
1506
+ input: { steamid: this.session.steamID.getSteamID64() }
1507
+ });
1508
+ if (!body.response) throw new SteamError("Malformed two-factor status response", { body });
1509
+ return body.response;
1510
+ }
1475
1511
  async ensureApiKey(domain = "assetpay.gg") {
1476
1512
  await this.session.getAccessToken();
1477
1513
  const res = await this.http.get(`${URLS.community}/dev/apikey?l=english`, { responseType: "text" });
@@ -1623,6 +1659,9 @@ var ConfirmationManager = class {
1623
1659
  }));
1624
1660
  }
1625
1661
  async respondToConfirmation(confID, confKey, time, key, accept) {
1662
+ const ids = Array.isArray(confID) ? confID : [confID];
1663
+ const keys = Array.isArray(confKey) ? confKey : [confKey];
1664
+ if (ids.length !== keys.length) throw new ConfirmationError("confID and confKey must have the same length");
1626
1665
  const { tag, k } = splitKey(key, accept ? "allow" : "cancel");
1627
1666
  const op = accept ? "allow" : "cancel";
1628
1667
  const res = await this.http.post(`${URLS.community}/mobileconf/multiajaxop`, {
@@ -1631,13 +1670,13 @@ var ConfirmationManager = class {
1631
1670
  ...this.confParams(k, time, tag),
1632
1671
  op
1633
1672
  },
1634
- multipart: [{
1673
+ multipart: ids.flatMap((id, i) => [{
1635
1674
  name: "cid[]",
1636
- value: confID
1675
+ value: id
1637
1676
  }, {
1638
1677
  name: "ck[]",
1639
- value: confKey
1640
- }]
1678
+ value: keys[i]
1679
+ }])
1641
1680
  });
1642
1681
  if (res.statusCode !== 200) throw httpError(res);
1643
1682
  if (res.body?.success) return;
@@ -1653,10 +1692,22 @@ var ConfirmationManager = class {
1653
1692
  });
1654
1693
  }
1655
1694
  acceptConfirmation(confID, nonce) {
1656
- return this.actOnConfirmation(confID, nonce, true);
1695
+ return this.actOnConfirmations([{
1696
+ id: confID,
1697
+ key: nonce
1698
+ }], true);
1657
1699
  }
1658
1700
  rejectConfirmation(confID, nonce) {
1659
- return this.actOnConfirmation(confID, nonce, false);
1701
+ return this.actOnConfirmations([{
1702
+ id: confID,
1703
+ key: nonce
1704
+ }], false);
1705
+ }
1706
+ acceptConfirmations(confs) {
1707
+ return this.actOnConfirmations(confs, true);
1708
+ }
1709
+ rejectConfirmations(confs) {
1710
+ return this.actOnConfirmations(confs, false);
1660
1711
  }
1661
1712
  async acceptAll() {
1662
1713
  const pending = await this.getPending();
@@ -1668,13 +1719,14 @@ var ConfirmationManager = class {
1668
1719
  if (!conf) throw new ConfirmationError(`Could not find confirmation for object ${objectID}`);
1669
1720
  await this.acceptConfirmation(conf.id, conf.key);
1670
1721
  }
1671
- async actOnConfirmation(confID, nonce, accept) {
1722
+ async actOnConfirmations(confs, accept) {
1723
+ if (confs.length === 0) return;
1672
1724
  const secret = this.requireSecret();
1673
1725
  const offset = await this.getTimeOffset();
1674
1726
  const time = this.nextConfTime(offset);
1675
1727
  const tag = accept ? "accept" : "cancel";
1676
1728
  const key = getConfirmationKey(secret, time, tag);
1677
- await this.respondToConfirmation(confID, nonce, time, {
1729
+ await this.respondToConfirmation(confs.map((c) => c.id), confs.map((c) => c.key), time, {
1678
1730
  tag,
1679
1731
  key
1680
1732
  }, accept);
@@ -1877,6 +1929,445 @@ var SteamWebApi = class {
1877
1929
  return response;
1878
1930
  }
1879
1931
  };
1932
+ //#endregion
1933
+ //#region src/market/prices.ts
1934
+ function getPriceValueAsInt(strAmount) {
1935
+ if (!strAmount) return 0;
1936
+ let amount = String(strAmount);
1937
+ amount = amount.replace(/,/g, ".");
1938
+ amount = amount.replace(".--", ".00");
1939
+ amount = amount.replace(/[^\d.]/g, "");
1940
+ if (amount.indexOf(".") !== -1) {
1941
+ const segments = amount.split(".");
1942
+ const last = segments[segments.length - 1] ?? "";
1943
+ if (!Number.isNaN(Number(last)) && last.length === 3 && segments[segments.length - 2] !== "0") amount = segments.join("");
1944
+ else amount = `${segments.slice(0, -1).join("")}.${last}`;
1945
+ }
1946
+ const cents = Number.parseFloat(amount) * 100;
1947
+ return Math.max(Math.floor(Number.isNaN(cents) ? 0 : cents + 1e-6), 0);
1948
+ }
1949
+ //#endregion
1950
+ //#region src/market/history.ts
1951
+ function parseMarketHistory(body) {
1952
+ const history = {
1953
+ events: [],
1954
+ sales: [],
1955
+ purchases: [],
1956
+ listingEvents: [],
1957
+ totalCount: body.total_count
1958
+ };
1959
+ if (!body.results_html) return history;
1960
+ const hovers = body.hovers ?? "";
1961
+ const assets = body.assets ?? {};
1962
+ const html = body.results_html.replace(/<!--[\s\S]*?-->/g, "");
1963
+ for (const row of findByClass(html, "market_listing_row", "market_recent_listing_row")) {
1964
+ const dates = findByClass(row.inner, "market_listing_listed_date");
1965
+ const itemName = textOf(row.inner, "market_listing_item_name");
1966
+ const gameName = textOf(row.inner, "market_listing_game_name");
1967
+ const actedOn = dates[0] ? elementText(dates[0]).trim() : "";
1968
+ const listedOn = dates[1] ? elementText(dates[1]).trim() : "";
1969
+ const displayPrice = textOf(row.inner, "market_listing_price").trim();
1970
+ const rowId = attrValue(row.attrs, "id") ?? "";
1971
+ const priceInCents = getPriceValueAsInt(displayPrice);
1972
+ if (priceInCents === 0 && displayPrice) throw new SteamError(`Market history price parsed to 0 cents for "${displayPrice}" in row ${rowId || "?"}`);
1973
+ const gainOrLoss = textOf(row.inner, "market_listing_gainorloss").trim();
1974
+ const type = gainOrLoss === "-" ? "sale" : gainOrLoss === "+" ? "purchase" : "listing_event";
1975
+ const idMatch = rowId.match(/^history_row_(\d+)_(\d+)$/);
1976
+ if (!idMatch) continue;
1977
+ const event = {
1978
+ historyId: rowId,
1979
+ listingid: idMatch[1],
1980
+ eventid: idMatch[2],
1981
+ itemName,
1982
+ gameName,
1983
+ listedOn,
1984
+ actedOn,
1985
+ displayPrice,
1986
+ priceInCents,
1987
+ type,
1988
+ marketName: null,
1989
+ appID: null,
1990
+ contextID: null,
1991
+ assetID: null,
1992
+ classID: null,
1993
+ instanceID: null,
1994
+ unOwnedContextID: null,
1995
+ unOwnedID: null
1996
+ };
1997
+ if (type !== "listing_event") attachAsset(event, rowId, hovers, assets);
1998
+ if (type === "sale") {
1999
+ const sale = {
2000
+ ...event,
2001
+ type,
2002
+ receivedAmount: priceInCents
2003
+ };
2004
+ history.sales.push(sale);
2005
+ history.events.push(sale);
2006
+ } else if (type === "purchase") {
2007
+ const purchase = {
2008
+ ...event,
2009
+ type,
2010
+ paidAmount: priceInCents
2011
+ };
2012
+ history.purchases.push(purchase);
2013
+ history.events.push(purchase);
2014
+ } else {
2015
+ const listingEvent = {
2016
+ ...event,
2017
+ type
2018
+ };
2019
+ history.listingEvents.push(listingEvent);
2020
+ history.events.push(listingEvent);
2021
+ }
2022
+ }
2023
+ return history;
2024
+ }
2025
+ function attachAsset(event, rowId, hovers, assets) {
2026
+ try {
2027
+ const args = hovers.split(`${rowId}_name`)[1].split(")")[0].split(",");
2028
+ event.appID = Number.parseInt(args[1], 10);
2029
+ event.contextID = args[2].split("'")[1] ?? null;
2030
+ event.assetID = args[3].split("'")[1] ?? null;
2031
+ if (event.contextID === null || event.assetID === null) return;
2032
+ const asset = assets[String(event.appID)]?.[event.contextID]?.[event.assetID];
2033
+ if (asset) {
2034
+ event.classID = asset.classid ?? null;
2035
+ event.instanceID = asset.instanceid ?? null;
2036
+ event.unOwnedContextID = asset.unowned_contextid ?? null;
2037
+ event.unOwnedID = asset.unowned_id ?? null;
2038
+ event.marketName = asset.market_hash_name ?? null;
2039
+ }
2040
+ } catch {}
2041
+ }
2042
+ const TAG = /<([a-zA-Z][\w:-]*)((?:"[^"]*"|'[^']*'|[^'">])*)>/g;
2043
+ const VOID_TAGS = /* @__PURE__ */ new Set([
2044
+ "area",
2045
+ "base",
2046
+ "br",
2047
+ "col",
2048
+ "embed",
2049
+ "hr",
2050
+ "img",
2051
+ "input",
2052
+ "link",
2053
+ "meta",
2054
+ "source",
2055
+ "track",
2056
+ "wbr"
2057
+ ]);
2058
+ function findByClass(html, ...classes) {
2059
+ const found = [];
2060
+ for (const m of html.matchAll(TAG)) {
2061
+ const attrs = m[2] ?? "";
2062
+ const tokens = (attrValue(attrs, "class") ?? "").split(/\s+/);
2063
+ if (!classes.every((c) => tokens.includes(c))) continue;
2064
+ const tag = m[1].toLowerCase();
2065
+ const start = m.index + m[0].length;
2066
+ const empty = VOID_TAGS.has(tag) || attrs.trimEnd().endsWith("/");
2067
+ found.push({
2068
+ attrs,
2069
+ inner: empty ? "" : html.slice(start, closeIndex(html, tag, start))
2070
+ });
2071
+ }
2072
+ return found;
2073
+ }
2074
+ function closeIndex(html, tag, from) {
2075
+ const re = new RegExp(`<(/?)${tag}\\b((?:"[^"]*"|'[^']*'|[^'">])*)>`, "gi");
2076
+ re.lastIndex = from;
2077
+ let depth = 1;
2078
+ for (let m = re.exec(html); m; m = re.exec(html)) if (m[1]) {
2079
+ if (--depth === 0) return m.index;
2080
+ } else if (!(m[2] ?? "").trimEnd().endsWith("/")) depth++;
2081
+ return html.length;
2082
+ }
2083
+ const ATTR = /([^\s"'>/=]+)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'=<>`]+)))?/g;
2084
+ function attrValue(attrs, name) {
2085
+ for (const m of attrs.matchAll(ATTR)) if (m[1].toLowerCase() === name) return decodeEntities(m[2] ?? m[3] ?? m[4] ?? "");
2086
+ }
2087
+ function textOf(html, className) {
2088
+ return findByClass(html, className).map(elementText).join("");
2089
+ }
2090
+ function elementText(el) {
2091
+ return decodeEntities(el.inner.replace(/<(?:"[^"]*"|'[^']*'|[^'">])*>/g, ""));
2092
+ }
2093
+ const NAMED_ENTITIES = {
2094
+ amp: "&",
2095
+ lt: "<",
2096
+ gt: ">",
2097
+ quot: "\"",
2098
+ apos: "'",
2099
+ nbsp: "\xA0"
2100
+ };
2101
+ function decodeEntities(s) {
2102
+ return s.replace(/&(#x[0-9a-f]+|#\d+|[a-z]+);/gi, (whole, ref) => {
2103
+ if (ref[0] === "#") {
2104
+ const code = ref[1] === "x" || ref[1] === "X" ? Number.parseInt(ref.slice(2), 16) : Number.parseInt(ref.slice(1), 10);
2105
+ return code <= 1114111 ? String.fromCodePoint(code) : whole;
2106
+ }
2107
+ return NAMED_ENTITIES[ref.toLowerCase()] ?? whole;
2108
+ });
2109
+ }
2110
+ //#endregion
2111
+ //#region src/market/MarketNamespace.ts
2112
+ const LISTINGS_PAGE_SIZE = 100;
2113
+ const MARKET_REFERER = `${URLS.community}/market/`;
2114
+ var MarketNamespace = class {
2115
+ http;
2116
+ session;
2117
+ confirmations;
2118
+ api;
2119
+ walletCurrency;
2120
+ constructor(http, session, confirmations, api) {
2121
+ this.http = http;
2122
+ this.session = session;
2123
+ this.confirmations = confirmations;
2124
+ this.api = api;
2125
+ }
2126
+ async getWalletDetails() {
2127
+ const body = await this.api.call({
2128
+ httpMethod: "POST",
2129
+ iface: "IUserAccountService",
2130
+ method: "GetClientWalletDetails",
2131
+ input: {
2132
+ include_balance_in_usd: 1,
2133
+ include_formatted_balance: 1
2134
+ }
2135
+ });
2136
+ if (!body.response) throw new SteamError("Malformed wallet details response", { body });
2137
+ const currency = body.response.currency_code;
2138
+ if (typeof currency === "number" && currency > 0) this.walletCurrency = currency;
2139
+ return body.response;
2140
+ }
2141
+ async getMyListings(options = {}) {
2142
+ await this.session.getAccessToken();
2143
+ const result = {
2144
+ listings: [],
2145
+ listings_to_confirm: [],
2146
+ buy_orders: [],
2147
+ num_active_listings: 0
2148
+ };
2149
+ let start = 0;
2150
+ for (;;) {
2151
+ const res = await this.http.get(`${URLS.community}/market/mylistings/`, {
2152
+ responseType: "json",
2153
+ searchParams: {
2154
+ norender: 1,
2155
+ currency: options.currency ?? this.walletCurrency,
2156
+ start,
2157
+ count: LISTINGS_PAGE_SIZE
2158
+ }
2159
+ });
2160
+ if (res.statusCode !== 200) throw httpError(res);
2161
+ const body = res.body;
2162
+ if (!body?.success) throw new SteamError("Steam returned success=false for /market/mylistings", { body });
2163
+ if (body.num_active_listings !== void 0) result.num_active_listings = body.num_active_listings;
2164
+ if (start === 0) {
2165
+ if (Array.isArray(body.buy_orders)) result.buy_orders = body.buy_orders;
2166
+ if (Array.isArray(body.listings_to_confirm)) result.listings_to_confirm = body.listings_to_confirm;
2167
+ }
2168
+ const page = body.listings ?? body.results?.listings ?? [];
2169
+ result.listings.push(...page);
2170
+ start += page.length;
2171
+ if (start >= result.num_active_listings || page.length === 0) return result;
2172
+ }
2173
+ }
2174
+ async getMyHistory(options = {}) {
2175
+ await this.session.getAccessToken();
2176
+ const res = await this.http.get(`${URLS.community}/market/myhistory`, {
2177
+ responseType: "json",
2178
+ searchParams: {
2179
+ count: options.count ?? 500,
2180
+ start: options.start
2181
+ }
2182
+ });
2183
+ if (res.statusCode !== 200) throw httpError(res);
2184
+ if (!res.body?.success) throw new SteamError("Steam returned success=false for /market/myhistory", { body: res.body });
2185
+ return parseMarketHistory(res.body);
2186
+ }
2187
+ async getOrderbook(appid, marketHashName, options = {}) {
2188
+ await this.session.getAccessToken();
2189
+ const qp = encodeURIComponent(JSON.stringify([appid, marketHashName]));
2190
+ const res = await this.http.get(`${URLS.community}/market/orderbook?q=Load&qp=${qp}`, { responseType: "json" });
2191
+ if (res.statusCode === 403) throw new ThrottledError(void 0, { body: res.body });
2192
+ if (res.statusCode !== 200) throw httpError(res);
2193
+ const body = res.body;
2194
+ const payload = body && body.success === void 0 && body.data ? body.data : body;
2195
+ if (!payload?.success || !payload.data) throw new SteamError(`Bad orderbook response for ${marketHashName}`, { body });
2196
+ const data = payload.data;
2197
+ const expected = options.expectedCurrency ?? this.walletCurrency;
2198
+ if (expected && data.eCurrency !== expected) throw new SteamError(`Orderbook currency ${data.eCurrency} != expected ${expected} for ${marketHashName}`, { body });
2199
+ return data;
2200
+ }
2201
+ async getPriceHistory(appid, marketHashName) {
2202
+ await this.session.getAccessToken();
2203
+ const res = await this.http.get(`${URLS.community}/market/pricehistory?appid=${appid}&market_hash_name=${encodeURIComponent(marketHashName)}`, { responseType: "json" });
2204
+ if (res.statusCode !== 200) throw httpError(res);
2205
+ if (!res.body?.success) throw new SteamError(`Steam returned success=false for pricehistory of ${marketHashName}`, { body: res.body });
2206
+ return Array.isArray(res.body.prices) ? res.body.prices : [];
2207
+ }
2208
+ async getMarketItemDetails(appid, marketHashName) {
2209
+ await this.session.getAccessToken();
2210
+ const query = encodeURIComponent(`"${marketHashName}"`);
2211
+ const res = await this.http.get(`${URLS.community}/market/search/render/?query=${query}&start=0&count=10&search_descriptions=0&sort_column=quantity&sort_dir=desc&appid=${appid}&norender=1`, { responseType: "json" });
2212
+ if (res.statusCode !== 200) throw httpError(res);
2213
+ const body = res.body;
2214
+ if (!body || typeof body !== "object") throw new SteamError("Malformed market search response", { body });
2215
+ return (Array.isArray(body.results) ? body.results : []).find((r) => r.hash_name === marketHashName) ?? null;
2216
+ }
2217
+ async sellItem(options) {
2218
+ await this.session.getAccessToken();
2219
+ const sessionid = await this.http.getSessionId();
2220
+ const res = await this.http.post(`${URLS.community}/market/sellitem/`, {
2221
+ responseType: "json",
2222
+ form: {
2223
+ sessionid,
2224
+ appid: options.appid,
2225
+ contextid: options.contextid ?? "2",
2226
+ assetid: options.assetid,
2227
+ amount: options.amount ?? 1,
2228
+ price: options.price
2229
+ },
2230
+ headers: { Referer: MARKET_REFERER }
2231
+ });
2232
+ const body = res.body;
2233
+ if (res.statusCode === 200 && (body?.success === true || body?.success === 1)) return body;
2234
+ if (res.statusCode === 429 || res.statusCode === 401) throw httpError(res);
2235
+ if (body?.message) throw sellItemError(body.message, body);
2236
+ if (res.statusCode !== 200) throw httpError(res);
2237
+ throw new SteamError("Unknown error listing item", {
2238
+ ...eresultOf(body),
2239
+ body
2240
+ });
2241
+ }
2242
+ async cancelListing(listingId) {
2243
+ await this.session.getAccessToken();
2244
+ const sessionid = await this.http.getSessionId();
2245
+ const res = await this.http.post(`${URLS.community}/market/removelisting/${listingId}`, {
2246
+ form: { sessionid },
2247
+ headers: { Referer: MARKET_REFERER }
2248
+ });
2249
+ if (res.statusCode === 200 || res.statusCode === 302 && redirectsToMarket(res)) return;
2250
+ throw httpError(res);
2251
+ }
2252
+ async createBuyOrder(options) {
2253
+ const currency = options.currency ?? this.walletCurrency;
2254
+ if (!currency) throw new SteamError("Wallet currency unknown — call getWalletDetails() or pass currency");
2255
+ await this.session.getAccessToken();
2256
+ const sessionid = await this.http.getSessionId();
2257
+ const referer = `${URLS.community}/market/listings/${options.appid}/${encodeURIComponent(options.marketHashName)}`;
2258
+ const form = {
2259
+ sessionid,
2260
+ currency,
2261
+ appid: options.appid,
2262
+ market_hash_name: options.marketHashName,
2263
+ price_total: options.priceTotal,
2264
+ quantity: options.quantity,
2265
+ confirmation: 0
2266
+ };
2267
+ const first = await this.postBuyOrder(form, referer);
2268
+ const direct = buyOrderId(first);
2269
+ if (direct) return direct;
2270
+ const confirmationId = first.body?.confirmation?.confirmation_id;
2271
+ if (!confirmationId) throw buyOrderError(first, `No confirmation_id (HTTP ${first.statusCode})`);
2272
+ await this.confirmations.acceptConfirmationForObject(String(confirmationId));
2273
+ const final = await this.postBuyOrder({
2274
+ ...form,
2275
+ confirmation: String(confirmationId)
2276
+ }, referer);
2277
+ const orderId = buyOrderId(final);
2278
+ if (orderId) return orderId;
2279
+ throw buyOrderError(final, `Finalization failed (HTTP ${final.statusCode})`);
2280
+ }
2281
+ async cancelBuyOrder(buyOrderId) {
2282
+ await this.session.getAccessToken();
2283
+ const sessionid = await this.http.getSessionId();
2284
+ const res = await this.http.post(`${URLS.community}/market/cancelbuyorder/`, {
2285
+ responseType: "json",
2286
+ form: {
2287
+ sessionid,
2288
+ buy_orderid: buyOrderId
2289
+ },
2290
+ headers: { Referer: MARKET_REFERER }
2291
+ });
2292
+ if (res.statusCode !== 200) throw httpError(res);
2293
+ return res.body ?? {};
2294
+ }
2295
+ async confirmListings(expected) {
2296
+ if (Object.values(expected).reduce((sum, n) => sum + n, 0) === 0) return {
2297
+ confirmed: [],
2298
+ skipped: []
2299
+ };
2300
+ await this.session.getAccessToken();
2301
+ const listings = (await this.confirmations.getPending()).filter((c) => c.type === 3).sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
2302
+ const remaining = { ...expected };
2303
+ const confirmed = [];
2304
+ const skipped = [];
2305
+ for (const conf of listings) {
2306
+ const name = (remaining[conf.sending] ?? 0) > 0 ? conf.sending : Object.keys(remaining).find((n) => (remaining[n] ?? 0) > 0 && conf.sending !== "" && n.includes(conf.sending));
2307
+ if (name === void 0) {
2308
+ skipped.push(conf);
2309
+ continue;
2310
+ }
2311
+ confirmed.push(conf);
2312
+ remaining[name] = (remaining[name] ?? 0) - 1;
2313
+ }
2314
+ await this.confirmations.acceptConfirmations(confirmed);
2315
+ return {
2316
+ confirmed,
2317
+ skipped
2318
+ };
2319
+ }
2320
+ async rejectListings(types = [3]) {
2321
+ await this.session.getAccessToken();
2322
+ const matched = (await this.confirmations.getPending()).filter((c) => types.includes(c.type));
2323
+ await this.confirmations.rejectConfirmations(matched);
2324
+ return matched;
2325
+ }
2326
+ async postBuyOrder(form, referer) {
2327
+ const res = await this.http.post(`${URLS.community}/market/createbuyorder/`, {
2328
+ responseType: "json",
2329
+ form,
2330
+ headers: { Referer: referer }
2331
+ });
2332
+ if (res.statusCode === 429 || res.statusCode === 401) throw httpError(res);
2333
+ return res;
2334
+ }
2335
+ };
2336
+ function redirectsToMarket(res) {
2337
+ const location = res.headers.location;
2338
+ if (typeof location !== "string" || !URL.canParse(location, URLS.community)) return false;
2339
+ const { pathname } = new URL(location, URLS.community);
2340
+ return pathname === "/market/" || pathname === "/market";
2341
+ }
2342
+ function eresultOf(body) {
2343
+ const success = body?.success;
2344
+ return typeof success === "number" && success !== 1 ? { eresult: success } : {};
2345
+ }
2346
+ function sellItemError(message, body) {
2347
+ const options = {
2348
+ ...eresultOf(body),
2349
+ body
2350
+ };
2351
+ const lower = message.toLowerCase();
2352
+ if (lower.includes("pending confirmation")) return new MarketConfirmationLimitError(message, options);
2353
+ if (lower.includes("maximum wallet balance")) return new WalletBalanceLimitError(message, options);
2354
+ if (lower.includes("unable to use the community market")) return new MarketBlockedError(message, options);
2355
+ return new SteamError(message, options);
2356
+ }
2357
+ function buyOrderId(res) {
2358
+ const body = res.body;
2359
+ const ok = body?.success === 1 || body?.success === true || body?.wallet_info?.success === 1;
2360
+ return res.statusCode === 200 && ok && body?.buy_orderid ? String(body.buy_orderid) : void 0;
2361
+ }
2362
+ function buyOrderError(res, fallback) {
2363
+ const body = res.body;
2364
+ const eresult = eresultOf(body);
2365
+ if (!body?.message && eresult.eresult === void 0 && ![200, 406].includes(res.statusCode)) return httpError(res);
2366
+ return new SteamError(body?.message || fallback, {
2367
+ ...eresult,
2368
+ body
2369
+ });
2370
+ }
1880
2371
  /**
1881
2372
  * Describes the message CEconItemPreviewDataBlock.
1882
2373
  * Use `create(CEconItemPreviewDataBlockSchema)` to create a new message.
@@ -2961,6 +3452,7 @@ var SteamMobile = class extends EventEmitter {
2961
3452
  confirmations;
2962
3453
  trade;
2963
3454
  community;
3455
+ market;
2964
3456
  identitySecret;
2965
3457
  polling;
2966
3458
  proxy;
@@ -2981,6 +3473,7 @@ var SteamMobile = class extends EventEmitter {
2981
3473
  this.confirmations = new ConfirmationManager(this.http, this.session.steamID, options.identitySecret, profile);
2982
3474
  this.trade = new TradeNamespace(this.api, this.http, this.session, this.confirmations);
2983
3475
  this.community = new CommunityNamespace(this.http, this.session, this.confirmations, this.api);
3476
+ this.market = new MarketNamespace(this.http, this.session, this.confirmations, this.api);
2984
3477
  this.session.on("refreshToken", (token) => this.emit("refreshToken", token));
2985
3478
  this.session.on("sessionExpired", (error) => this.emit("sessionExpired", error));
2986
3479
  this.session.on("debug", (message) => this.emit("debug", message));
@@ -3040,6 +3533,6 @@ var SteamMobile = class extends EventEmitter {
3040
3533
  }
3041
3534
  };
3042
3535
  //#endregion
3043
- export { ANDROID_PROFILE, AccessTokenError, AuthClient, CommunityNamespace, ConfirmationError, ConfirmationManager, CredentialSession, DEFAULT_CONTEXTID, DEFAULT_POLL_FULL_UPDATE_INTERVAL, DEFAULT_POLL_INTERVAL, DEFAULT_POLL_MAX_AGE_MS, DEFAULT_RATE_LIMIT_RETRY_MS, EAuthSessionGuardType, EAuthTokenPlatformType, EAuthTokenRevokeAction, EConfirmationMethod, EConfirmationType, EOfferFilter, EResult, ESessionPersistence, ETokenRenewalType, ETradeOfferState, ETradeStatus, EscrowError, FamilyViewError, HttpClient, HttpStatusError, IOS_PROFILE, ItemServerUnavailableError, LANG, LoginError, NewDeviceError, NoMobileAuthenticatorError, OfferLimitError, OpenIdError, Poller, PrivateInventoryError, ProxyError, RATE_LIMITS, RETRY_AFTER, RateLimitError, SessionManager, SteamError, SteamMobile, SteamSessionExpiredError, SteamWebApi, TERMINAL_AUTH_ERESULTS, TRANSIENT_ERESULTS, TargetCannotTradeError, TradeBanError, TradeNamespace, TradeOffer, URLS, WebApiClient, confirmOpenid, decodeJwt, decodePreviewToken, encodePreviewToken, getTradeHistory, getTradeOffersSummary, getTradeStatus, isTerminalAuthEResult, isTerminalState, isTransientEResult, loginWithCredentials, parseInventory, parseOpenidForm, parsePartnerInventory, resolveMobileProfile, resolveTarget, secondsUntilExpiry, steamOpenidLogin };
3536
+ export { ANDROID_PROFILE, AccessTokenError, AuthClient, CommunityNamespace, ConfirmationError, ConfirmationManager, CredentialSession, DEFAULT_CONTEXTID, DEFAULT_POLL_FULL_UPDATE_INTERVAL, DEFAULT_POLL_INTERVAL, DEFAULT_POLL_MAX_AGE_MS, DEFAULT_RATE_LIMIT_RETRY_MS, EAuthSessionGuardType, EAuthTokenPlatformType, EAuthTokenRevokeAction, EConfirmationMethod, EConfirmationType, EOfferFilter, EResult, ESessionPersistence, ETokenRenewalType, ETradeOfferState, ETradeStatus, EscrowError, FamilyViewError, HttpClient, HttpStatusError, IOS_PROFILE, ItemServerUnavailableError, LANG, LoginError, MarketBlockedError, MarketConfirmationLimitError, MarketNamespace, NewDeviceError, NoMobileAuthenticatorError, OfferLimitError, OpenIdError, Poller, PrivateInventoryError, ProxyError, RATE_LIMITS, RETRY_AFTER, RateLimitError, SessionManager, SteamError, SteamMobile, SteamSessionExpiredError, SteamWebApi, TERMINAL_AUTH_ERESULTS, TRANSIENT_ERESULTS, TargetCannotTradeError, ThrottledError, TradeBanError, TradeNamespace, TradeOffer, URLS, WalletBalanceLimitError, WebApiClient, confirmOpenid, decodeJwt, decodePreviewToken, encodePreviewToken, getPriceValueAsInt, getTradeHistory, getTradeOffersSummary, getTradeStatus, isTerminalAuthEResult, isTerminalState, isTransientEResult, loginWithCredentials, parseInventory, parseMarketHistory, parseOpenidForm, parsePartnerInventory, resolveMobileProfile, resolveTarget, secondsUntilExpiry, steamOpenidLogin };
3044
3537
 
3045
3538
  //# sourceMappingURL=index.mjs.map