tf2-rtp-calculator
Version:
An RTP calculator for Team Fortress 2 crate unbox sessions
135 lines (122 loc) • 4.95 kB
text/typescript
// backpack-tf.ts
// Minimal client for the public backpack.tf WebAPI (OAS3 “WebAPI …” sections)
import { EItemQuality } from "../shared/enums/itemQuality";
import { ITF2ItemPriceData } from "./interfaces/itemPriceData";
import { ETF2UnusualEffects } from "./enums/unusualEffects";
interface CurrencyData {
"name": string;
"quality": EItemQuality;
"priceindex": string;
"single": string;
"plural": string;
"round": number; // how much decimal to round to
"blanket": number; // no idea what this is
"craftable": "Craftable" | "Uncraftable";
"tradable": "Tradable" | "Untradable";
"defindex": number;
"price": {
"value": number;
"currency": "metal" | "keys" | "buds" | "usd";
"difference": number;
"last_update": number;
"value_high": number;
}
}
export interface CurrenciesResponse {
"response": {
"success": number;
"currencies": {
"metal": CurrencyData;
"keys": CurrencyData;
"buds": CurrencyData;
"usd": CurrencyData;
}
"name": "Team Fortress 2";
"url": "https://backpack.tf";
};
}
export interface PriceHistoryResponse { /* … */ }
export interface PricesResponse {
response: {
"success": 1;
"current_time": number; // in seconds
"raw_usd_value": number;
"usd_currency": "metal";
"usd_currency_index": 5002;
"items": Record<string, {
"defindex": Array<number>;
"prices": Record<EItemQuality, {
"Tradable": {
"Non-Craftable": Array<ITF2ItemPriceData>;
"Craftable": Array<ITF2ItemPriceData> | Record<Partial<ETF2UnusualEffects>, ITF2ItemPriceData>;
}
}>;
}>;
}
}
export interface SpecialItemsResponse { /* … */ }
export interface UsersResponse {
"response": {
"success": number;
"players": Record<string, {
"steamid": string;
"success": number;
"backpack_value": Record<string, number>;
"backpack_update": Record<string, number>;
"name": string;
"backpack_tf_reputation": number;
"backpack_tf_trust": {for: number; against: number};
}>;
}
}
export interface ImpersonatedUsersResponse { /* … */ }
export interface UserTradesResponse { /* … */ }
type Query = Record<string, string | number | boolean | undefined>;
export class BackpackTF {
private readonly base = 'https://backpack.tf/api'; // default server :contentReference[oaicite:0]{index=0}
constructor(private readonly apiKey: string) {}
/** GET /IGetCurrencies/v1 – internal currency list */
getCurrencies(params: { raw?: number } = {}): Promise<CurrenciesResponse> {
return this.request('/IGetCurrencies/v1', params); // :contentReference[oaicite:1]{index=1}
}
/** GET /IGetPriceHistory/v1 – price history for one SKU */
getPriceHistory(params: {
appid: string; item: string; quality?: string;
tradable?: string; craftable?: string; priceindex?: string | number;
}): Promise<PriceHistoryResponse> {
return this.request('/IGetPriceHistory/v1', params); // :contentReference[oaicite:2]{index=2}
}
/** GET /IGetPrices/v4 – full price schema (TF2 only) */
getPrices(params: { raw?: number; since?: number } = {}): Promise<PricesResponse> {
return this.request('/IGetPrices/v4', params); // :contentReference[oaicite:3]{index=3}
}
/** GET /IGetSpecialItems/v1 – list of items with special behaviour */
getSpecialItems(): Promise<SpecialItemsResponse> {
return this.request('/IGetSpecialItems/v1'); // :contentReference[oaicite:4]{index=4}
}
/** GET /IGetUsers/v3 – metadata for one or more users */
getUsers(steamids: string[]): Promise<UsersResponse> {
return this.request('/IGetUsers/v3', { steamids: steamids.join(',') }); // :contentReference[oaicite:5]{index=5}
}
/** GET /IGetUsers/GetImpersonatedUsers – flagged impersonators */
getImpersonatedUsers(params: { limit?: number; skip?: number } = {}): Promise<ImpersonatedUsersResponse> {
return this.request('/IGetUsers/GetImpersonatedUsers', params); // :contentReference[oaicite:6]{index=6}
}
/** GET /IGetUserTrades/v1 – public trades for a user */
getUserTrades(): Promise<UserTradesResponse> {
return this.request('/IGetUserTrades/v1'); // :contentReference[oaicite:7]{index=7}
}
// --------------- internals ---------------
private async request<T = unknown>(path: string, query: Query = {}): Promise<T> {
const search = new URLSearchParams(
// @ts-ignore
Object.entries({ ...query, key: this.apiKey })
.filter(([, v]) => v !== undefined)
.map(([k, v]) => [k, String(v)])
);
const url = `${this.base}${path}?${search.toString()}`;
const res = await fetch(url, { method: 'GET' });
if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
return res.json() as Promise<T>;
}
}