purge some dead code

This commit is contained in:
tresabhi committed 2026-06-30 14:03:34 -05:00
1 parent 878ada0d10
commit 2ee72b40ab
65 files changed
+30 -4376

No files matched your search

-89
View File
@@ -1,89 +0,0 @@
import { assertSecret, EventManager } from "../blitzkit";
import { patientFetch } from "../blitzkit/patientFetch";
import type { Region } from "./regions";
const RETRY_ERRORS = ["REQUEST_LIMIT_EXCEEDED", "SOURCE_NOT_AVAILABLE"];
export const retryAbleBlitzFetchEvent = new EventManager();
export const blitzFetchQueueAvailableEvent = new EventManager();
type BlitzResponse<Data extends object> =
| {
status: "error";
error: { field: string; message: string; code: 402; value: null };
}
| {
status: "ok";
data: Data;
};
const MAX_CALLS_PER_SECOND = 10;
const queue: { url: string; resolve: (data: object) => void }[] = [];
let inProgress = 0;
function decrement() {
inProgress--;
blitzFetchQueueAvailableEvent.emit(undefined);
manageQueue();
}
async function manageQueue() {
if (queue.length > 0 && inProgress < MAX_CALLS_PER_SECOND) {
inProgress++;
const timeout = setTimeout(decrement, 1000);
const request = queue.shift()!;
const data = (await patientFetch(request.url)
.then((response) => response.json())
.catch((error) => ({ status: "error", error }))) as BlitzResponse<
typeof request.resolve
>;
if (data.status === "ok") {
request.resolve(data.data);
} else {
if (RETRY_ERRORS.includes(data.error.message)) {
retryAbleBlitzFetchEvent.emit(undefined);
clearTimeout(timeout);
setTimeout(() => {
queue.push(request);
decrement();
}, 1000 / MAX_CALLS_PER_SECOND);
} else {
clearTimeout(timeout);
decrement();
throw new Error(`Wargaming response error status: "${data.status}"`, {
cause: `Message: "${data.error.message}"\nURL: "${request.url}"`,
});
}
}
}
}
export type FetchBlitzParams = Record<string, string | number | undefined>;
export function fetchBlitz<Data extends object>(
region: Region,
path: string,
params: FetchBlitzParams = {}
) {
return new Promise<Data>((resolve) => {
queue.push({
url: `https://api.wotblitz.${region}/wotb/${path}/?${Object.entries({
application_id: assertSecret(
import.meta.env.PUBLIC_WARGAMING_APPLICATION_ID
),
...params,
})
.filter(([_, value]) => value !== undefined)
.map(([key, value]) => `${key}=${encodeURIComponent(value!)}`)
.join("&")}`,
resolve(data) {
resolve(data as Data);
},
});
manageQueue();
});
}
-11
View File
@@ -1,11 +0,0 @@
import { assertSecret } from "../blitzkit";
import type { BlitzGlossary } from "../types";
export async function fetchGlossary(locale: string) {
const response = await fetch(
`${assertSecret(
import.meta.env.WOTB_GLOSSARY_DOMAIN
)}/${locale}${assertSecret(import.meta.env.WOTB_GLOSSARY_PATH)}`
);
return (await response.json()) as BlitzGlossary;
}
@@ -1,35 +0,0 @@
import { fetchBlitz } from "./fetchBlitz";
import { normalizeIds } from "./normalizeIds";
import type { Region } from "./regions";
interface IndividualAccountAchievements {
achievements: {
[achievement: string]: number;
};
max_series: {
[achievement: string]: number;
};
}
export interface AccountAchievements {
[id: number]: IndividualAccountAchievements;
}
export async function getAccountAchievements<
Ids extends number | number[],
ReturnType = Ids extends number
? IndividualAccountAchievements
: IndividualAccountAchievements[],
>(region: Region, ids: Ids) {
const object = await fetchBlitz<AccountAchievements>(
region,
"account/achievements",
{ account_id: normalizeIds(ids) }
);
if (typeof ids === "number") {
return object[ids as number] as ReturnType;
} else {
return ids.map((id) => object[id]) as ReturnType;
}
}
-96
View File
@@ -1,96 +0,0 @@
import { BlitzStats } from "../statistics";
import { FetchBlitzParams, fetchBlitz } from "./fetchBlitz";
import { normalizeIds } from "./normalizeIds";
import { Region } from "./regions";
export interface SupplementaryStats {
WN8?: number;
tier?: number;
}
export interface ClanStats {
spotted: number;
max_frags_tank_id: number;
hits: number;
frags: number;
max_xp: number;
max_xp_tank_id: number;
wins: number;
losses: number;
capture_points: number;
battles: number;
damage_dealt: number;
damage_received: number;
max_frags: number;
shots: number;
frags8p: number;
xp: number;
win_and_survived: number;
survived_battles: number;
dropped_capture_points: number;
}
export interface RatingStats {
spotted: number;
calibration_battles_left: number;
hits: number;
frags: number;
recalibration_start_time: number;
mm_rating: number;
wins: number;
losses: number;
is_recalibration: boolean;
capture_points: number;
battles: number;
damage_dealt: number;
damage_received: number;
shots: number;
frags8p: number;
xp: number;
win_and_survived: number;
survived_battles: number;
dropped_capture_points: number;
}
export interface IndividualAccountInfo {
account_id: number;
created_at: number;
updated_at: number;
private: null;
last_battle_time: number;
nickname: string;
statistics: {
all: BlitzStats;
clan: ClanStats;
rating?: RatingStats;
frags: null | number;
};
}
export interface AccountInfo {
[accountId: number]: IndividualAccountInfo;
}
export async function getAccountInfo<
Ids extends number | number[],
ReturnType = Ids extends number
? IndividualAccountInfo
: IndividualAccountInfo[],
>(
region: Region,
ids: Ids,
extra: string[] = [],
params: FetchBlitzParams = {}
) {
const object = await fetchBlitz<AccountInfo>(region, "account/info", {
account_id: normalizeIds(ids),
extra: extra.length === 0 ? undefined : extra.join(","),
...params,
});
if (typeof ids === "number") {
return object[ids as number] as ReturnType;
} else {
return ids.map((id) => object[id]) as ReturnType;
}
}
@@ -1,46 +0,0 @@
import { fetchBlitz } from "./fetchBlitz";
import { normalizeIds } from "./normalizeIds";
import type { Region } from "./regions";
type IndividualClanAccountInfo = {
account_id: number;
joined_at: number;
clan_id: number;
role: string;
account_name: string;
clan?: {
members_count: number;
name: string;
created_at: number;
tag: string;
clan_id: number;
emblem_set_id: number;
};
} | null;
interface ClanAccountInfo {
[accountId: number]: IndividualClanAccountInfo;
}
export async function getClanAccountInfo<
Ids extends number | number[],
ReturnType = Ids extends number
? IndividualClanAccountInfo
: IndividualClanAccountInfo[],
>(region: Region, ids: Ids, extra: string[] = []) {
const object = await fetchBlitz<ClanAccountInfo>(
region,
"clans/accountinfo",
{
account_id: normalizeIds(ids),
extra: extra.length === 0 ? undefined : extra.join(","),
}
);
if (typeof ids === "number") {
return object[ids as number] as ReturnType;
} else {
return ids.map((id) => object[id]) as ReturnType;
}
}
-51
View File
@@ -1,51 +0,0 @@
import { fetchBlitz } from "./fetchBlitz";
import { normalizeIds } from "./normalizeIds";
import type { Region } from "./regions";
interface IndividualClanInfo {
recruiting_options: {
vehicles_level: number;
wins_ratio: number;
average_battles_per_day: number;
battles: number;
average_damage: number;
};
members_count: number;
name: string;
creator_name: string;
clan_id: number;
created_at: number;
updated_at: number;
leader_name: string;
members_ids: number[];
recruiting_policy: string;
tag: string;
is_clan_disbanded: boolean;
old_name: string;
emblem_set_id: number;
creator_id: number;
motto: string;
renamed_at: number;
old_tag: null;
leader_id: number;
description: string;
}
interface ClanInfo {
[clanId: number]: IndividualClanInfo;
}
export async function getClanInfo<
Ids extends number | number[],
ReturnType = Ids extends number ? IndividualClanInfo : IndividualClanInfo[],
>(region: Region, ids: Ids) {
const object = await fetchBlitz<ClanInfo>(region, "clans/info", {
clan_id: normalizeIds(ids),
});
if (typeof ids === "number") {
return object[ids as number] as ReturnType;
} else {
return ids.map((id) => object[id]) as ReturnType;
}
}
-16
View File
@@ -1,16 +0,0 @@
import type { TanksStats } from "../types";
import { type FetchBlitzParams, fetchBlitz } from "./fetchBlitz";
import type { Region } from "./regions";
export async function getTankStats(
region: Region,
id: number,
params?: FetchBlitzParams
) {
const tankStats = await fetchBlitz<TanksStats>(region, "tanks/stats", {
account_id: id,
...params,
});
return tankStats[id];
}
-10
View File
@@ -3,21 +3,13 @@ export * from "./clans";
export * from "./classes";
export * from "./constants";
export * from "./equipmentPrice";
export * from "./fetchBlitz";
export * from "./fetchGlossary";
export * from "./generateStats";
export * from "./getAccountAchievements";
export * from "./getAccountInfo";
export * from "./getClanAccountInfo";
export * from "./getClanInfo";
export * from "./getLeagueFromScore";
export * from "./getRatingInfo";
export * from "./getRatingLeague";
export * from "./getRatingNeighbors";
export * from "./getTankStats";
export * from "./idToRegion";
export * from "./isOnGoingRatingSeason";
export * from "./isValidBlitzId";
export * from "./nations";
export * from "./normalizeExtra";
export * from "./normalizeIds";
@@ -27,7 +19,5 @@ export * from "./readDVPL";
export * from "./regions";
export * from "./regionSubdomainToRegion";
export * from "./regionToRegionSubdomain";
export * from "./searchClansAcrossRegions";
export * from "./searchCurrentRatingPlayers";
export * from "./searchPlayersAcrossRegions";
export * from "./toUniqueId";
-32
View File
@@ -1,32 +0,0 @@
import { assertSecret } from "../blitzkit";
import { idToRegion } from "./idToRegion";
import { Region } from "./regions";
export async function isValidBlitzId(id: number, token?: string) {
let region: Region;
try {
region = idToRegion(id);
} catch (error) {
return false;
}
const json = await fetch(
`https://api.wotblitz.${region}/wotb/account/info/?account_id=${id}&application_id=${assertSecret(
import.meta.env.PUBLIC_WARGAMING_APPLICATION_ID
)}${
token === undefined ? "" : `&access_token=${token}`
}&fields=account_id%2C-account_id`
).then(
(response) =>
response.json() as Promise<
| {
status: "ok";
data: Record<number, {} | null>;
}
| { status: "error" }
>
);
return json.status === "ok" && json.data[id] !== null;
}
@@ -1,51 +0,0 @@
import type { ClanList } from "./clans";
import { fetchBlitz } from "./fetchBlitz";
import type { Region } from "./regions";
export async function searchClansAcrossRegions(search: string, limit = 25) {
const trimmed = search.trim();
if (trimmed.length < 3 && trimmed.length > 100) return [];
const normalizedLimit = Math.floor(limit / 3);
// TODO: remove splice once wargaming fixes the functionality of the limit felid
return (
await Promise.all([
fetchBlitz<ClanList>("com", "clans/list", {
search,
limit: normalizedLimit,
}).then((value) =>
value
.map((account) => ({
...account,
region: "com" as Region,
}))
.splice(0, normalizedLimit)
),
fetchBlitz<ClanList>("eu", "clans/list", {
search,
limit: normalizedLimit,
}).then((value) =>
value
.map((account) => ({
...account,
region: "eu" as Region,
}))
.splice(0, normalizedLimit)
),
fetchBlitz<ClanList>("asia", "clans/list", {
search,
limit: normalizedLimit,
}).then((value) =>
value
.map((account) => ({
...account,
region: "asia" as Region,
}))
.splice(0, normalizedLimit)
),
])
)
.filter(Boolean)
.flat();
}
@@ -1,2 +0,0 @@
export const usernamePattern = /^[a-zA-Z0-9_]{3,24}$/;
export const usernamePatternWithoutPosition = /[a-zA-Z0-9_]{3,24}/;
@@ -1,64 +0,0 @@
import { fetchBlitz } from "../fetchBlitz";
import type { Region } from "../regions";
import { usernamePattern } from "./constants";
export interface AccountListItem {
nickname: string;
account_id: number;
}
export type AccountList = AccountListItem[];
export type AccountListWithServer = (AccountListItem & {
region: Region;
})[];
export async function searchPlayersAcrossRegions(search: string, limit = 25) {
const trimmed = search.trim();
if (trimmed.length < 3 && trimmed.length > 100) return [];
const normalizedLimit = Math.floor(limit / 3);
if (usernamePattern.test(trimmed)) {
return (
await Promise.all([
fetchBlitz<AccountList>("com", "account/list", {
search,
limit: normalizedLimit,
}).then(
(value) =>
value &&
value.map((account) => ({
...account,
region: "com" as Region,
}))
),
fetchBlitz<AccountList>("eu", "account/list", {
search,
limit: normalizedLimit,
}).then(
(value) =>
value &&
value.map((account) => ({
...account,
region: "eu" as Region,
}))
),
fetchBlitz<AccountList>("asia", "account/list", {
search,
limit: normalizedLimit,
}).then(
(value) =>
value &&
value.map((account) => ({
...account,
region: "asia" as Region,
}))
),
])
)
.filter(Boolean)
.flat() as AccountListWithServer;
} else {
return [] as AccountListWithServer;
}
}
export * from "./constants";
-5
View File
@@ -1,5 +0,0 @@
import { assertSecret } from "./assertSecret";
export function asset(path: string) {
return `${assertSecret(import.meta.env.PUBLIC_ASSET_BASE)}/${path}`;
}
@@ -1,22 +0,0 @@
import { emptyAllStats } from '../../blitz/constants';
import { Samples } from '../../protos';
import type { BlitzkitStats } from '../../statistics';
export const emptyAverageDefinitionsAllStats: BlitzkitStats = {
...emptyAllStats,
battle_life_time: 0,
};
export const averageDefinitionsAllStatsKeys = Object.keys(
emptyAverageDefinitionsAllStats,
) as (keyof BlitzkitStats)[];
export const emptySamples: Samples = {
d_1: 0,
d_7: 0,
d_30: 0,
d_60: 0,
d_90: 0,
d_120: 0,
total: 0,
};
@@ -1,23 +0,0 @@
import { fetchPB } from '../../protobuf';
import { AverageDefinitions } from '../../protos';
import { asset } from '../asset';
export interface AverageDefinitionsManifest {
version: 1;
/**
* epoch in days
*/
latest: number;
}
export async function fetchAverageDefinitions() {
const manifestResponse = await fetch(asset('averages/manifest.json'));
const manifestJson =
(await manifestResponse.json()) as AverageDefinitionsManifest;
return await fetchPB(
asset(`averages/${manifestJson.latest}.pb`),
AverageDefinitions,
);
}
export * from './constants';
@@ -1,7 +0,0 @@
import { fetchPB } from '../protobuf';
import { CamouflageDefinitions } from '../protos';
import { asset } from './asset';
export function fetchCamouflageDefinitions() {
return fetchPB(asset('definitions/camouflages.pb'), CamouflageDefinitions);
}
@@ -1,7 +0,0 @@
import { fetchPB } from '../protobuf';
import { ConsumableDefinitions } from '../protos';
import { asset } from './asset';
export function fetchConsumableDefinitions() {
return fetchPB(asset('definitions/consumables.pb'), ConsumableDefinitions);
}
@@ -1,12 +0,0 @@
import { asset } from './asset';
export interface DiscoveredIdsDefinitions {
time: number;
chunks: number;
count: number;
}
export async function fetchDiscoveredIdsDefinitions() {
const response = await fetch(asset('ids/manifest.json'));
return response.json() as Promise<DiscoveredIdsDefinitions>;
}
@@ -1,7 +0,0 @@
import { fetchPB } from '../protobuf';
import { EquipmentDefinitions } from '../protos';
import { asset } from './asset';
export function fetchEquipmentDefinitions() {
return fetchPB(asset('definitions/equipment.pb'), EquipmentDefinitions);
}
-7
View File
@@ -1,7 +0,0 @@
import { fetchPB } from '../protobuf';
import { Gallery } from '../protos';
import { asset } from './asset';
export function fetchGallery() {
return fetchPB(asset('definitions/gallery.pb'), Gallery);
}
@@ -1,7 +0,0 @@
import { fetchPB } from '../protobuf';
import { GameDefinitions } from '../protos';
import { asset } from './asset';
export function fetchGameDefinitions() {
return fetchPB(asset('definitions/game.pb'), GameDefinitions);
}
@@ -1,49 +0,0 @@
import { getRatingInfo } from "../blitz/getRatingInfo";
import { assertSecret } from "./assertSecret";
interface GitHubTrees {
tree: { path: string; url: string }[];
}
let cachedLatestArchivedSeasonNumber: number | null = null;
export async function getArchivedLatestSeasonNumber() {
if (cachedLatestArchivedSeasonNumber !== null) {
return cachedLatestArchivedSeasonNumber;
}
const ratingInfo = await getRatingInfo("com");
if (ratingInfo.detail) {
const regionsURL = (
(await fetch(
`https://api.github.com/repos/${assertSecret(
import.meta.env.PUBLIC_ASSET_REPO
)}/git/trees/main`
).then((response) => response.json())) as GitHubTrees
).tree.find(({ path }) => path === "regions")!.url;
const comURL = (
(await fetch(regionsURL).then((response) =>
response.json()
)) as GitHubTrees
).tree.find(({ path }) => path === "com")!.url;
const ratingURL = (
(await fetch(comURL).then((response) => response.json())) as {
tree: [{ url: string }];
}
).tree[0].url;
const latestSeason = Math.max(
...(
(await fetch(ratingURL).then((response) => response.json())) as {
tree: { path: string }[];
}
).tree.map(({ path }) => Number(path))
);
cachedLatestArchivedSeasonNumber = latestSeason;
} else {
cachedLatestArchivedSeasonNumber = ratingInfo.current_season - 1;
}
return cachedLatestArchivedSeasonNumber;
}
@@ -1,23 +0,0 @@
import type { Region } from "../blitz/regions";
import { RatingLeaderboard } from "../protos";
import { asset } from "./asset";
const cache: Record<Region, Record<number, RatingLeaderboard>> = {
asia: {},
eu: {},
com: {},
};
export async function getArchivedRatingLeaderboard(
region: Region,
season: number
) {
if (!cache[region][season]) {
const info = await fetch(asset(`regions/${region}/rating/${season}.pb`))
.then((response) => response.arrayBuffer())
.then((buffer) => RatingLeaderboard.decode(new Uint8Array(buffer)));
cache[region][season] = info;
}
return cache[region][season];
}
-28
View File
@@ -1,50 +1,22 @@
export * from "./assertSecret";
export * from "./asset";
export * from "./availableProvisions";
export * from "./averageDefinitions";
// export * from './camouflageDefinitions';
// export * from './checkConsumableProvisionInclusivity';
export * from "./coefficient";
export * from "./consumableDefinitions";
// export * from './context';
export * from "./createDefaultSkills";
export * from "./degressiveStat";
export * from "./discoveredIdDefinitions";
export * from "./emblemURL";
export * from "./equipmentDefinitions";
export * from "./eventManager";
export * from "./gameDefinitions";
export * from "./getArchivedLatestSeasonNumber";
// export * from './getArchivedRatingInfo';
export * from "./getArchivedRatingLeaderboard";
// export * from './getArchivedRatingMidnightLeaderboard';
export * from "./getTimeDaysAgo";
export * from "./isExplosive";
export * from "./mapDefinitions";
export * from "./modelDefinitions";
export * from "./normalizeBoundingBox";
// export * from './parseBkni';
// export * from './patientFetch';
export * from "./patientFetchJSON";
export * from "./progressiveStat";
export * from "./provisionDefinitions";
export * from "./resolveDpm";
export * from "./resolvePenetrationCoefficient";
export * from "./reviews";
export * from "./skillDefinitions";
export * from "./sum";
export * from "./tankDefinitions";
export * from "./tankIcon";
export * from "./tankNames";
export * from "./unionBoundingBox";
export * from "./uniqueGuns";
export * from "./unwrapBlitzkitResponse";
export * from "./votes";
// export * from './withCORSProxy';
export * from "./createDefaultProvisions";
export * from "./gallery";
export * from "./metaSortTank";
export * from "./popularTanks";
export * from "./romanize";
export * from "./sluggify.ts";
export * from "./youtubers";
@@ -1,7 +0,0 @@
import { fetchPB } from '../protobuf';
import { MapDefinitions } from '../protos';
import { asset } from './asset';
export function fetchMapDefinitions() {
return fetchPB(asset('definitions/maps.pb'), MapDefinitions);
}
@@ -1,7 +0,0 @@
import { fetchPB } from '../protobuf';
import { ModelDefinitions } from '../protos';
import { asset } from './asset';
export function fetchModelDefinitions() {
return fetchPB(asset('definitions/models.pb'), ModelDefinitions);
}
@@ -1,7 +0,0 @@
import { fetchPB } from '../protobuf';
import { PopularTanks } from '../protos';
import { asset } from './asset';
export function fetchPopularTanks() {
return fetchPB(asset('definitions/popular-tanks.pb'), PopularTanks);
}
@@ -1,7 +0,0 @@
import { fetchPB } from '../protobuf';
import { ProvisionDefinitions } from '../protos';
import { asset } from './asset';
export function fetchProvisionDefinitions() {
return fetchPB(asset('definitions/provisions.pb'), ProvisionDefinitions);
}
-7
View File
@@ -1,7 +0,0 @@
import { fetchPB } from '../protobuf';
import { Reviews } from '../protos';
import { asset } from './asset';
export function fetchReviews() {
return fetchPB(asset('definitions/reviews.pb'), Reviews);
}
@@ -1,7 +0,0 @@
import { fetchPB } from '../protobuf';
import { SkillDefinitions } from '../protos';
import { asset } from './asset';
export function fetchSkillDefinitions() {
return fetchPB(asset('definitions/skills.pb'), SkillDefinitions);
}
@@ -1,74 +0,0 @@
import { times } from "lodash-es";
import { CrewType, ShellType, TankClass, TankType } from "../../protos";
export const SHELL_NAMES: Record<ShellType, string> = {
[ShellType.SHELL_TYPE_AP]: "AP",
[ShellType.SHELL_TYPE_APCR]: "APCR",
[ShellType.SHELL_TYPE_HEAT]: "HEAT",
[ShellType.SHELL_TYPE_HE]: "HE",
};
export const CREW_MEMBER_NAMES = {
[CrewType.CREW_TYPE_COMMANDER]: "commander",
[CrewType.CREW_TYPE_DRIVER]: "driver",
[CrewType.CREW_TYPE_GUNNER]: "gunner",
[CrewType.CREW_TYPE_LOADER]: "loader",
[CrewType.CREW_TYPE_RADIOMAN]: "radioman",
} as const;
/**
* @deprecated use svg
*/
export const TANK_ICONS: Record<TankClass, string> = {
[TankClass.TANK_CLASS_TANK_DESTROYER]: "https://i.imgur.com/BIHSEH0.png",
[TankClass.TANK_CLASS_LIGHT]: "https://i.imgur.com/CSNha5V.png",
[TankClass.TANK_CLASS_MEDIUM]: "https://i.imgur.com/wvf3ltm.png",
[TankClass.TANK_CLASS_HEAVY]: "https://i.imgur.com/ECeqlZa.png",
};
/**
* @deprecated use svg
*/
export const TANK_ICONS_PREMIUM: Record<TankClass, string> = {
[TankClass.TANK_CLASS_TANK_DESTROYER]: "https://i.imgur.com/TCu3EdR.png",
[TankClass.TANK_CLASS_LIGHT]: "https://i.imgur.com/zdkpTRb.png",
[TankClass.TANK_CLASS_MEDIUM]: "https://i.imgur.com/3z7eHX6.png",
[TankClass.TANK_CLASS_HEAVY]: "https://i.imgur.com/P3vbmyA.png",
};
/**
* @deprecated use svg
*/
export const TANK_ICONS_COLLECTOR: Record<TankClass, string> = {
[TankClass.TANK_CLASS_TANK_DESTROYER]: "https://i.imgur.com/WTjeirB.png",
[TankClass.TANK_CLASS_LIGHT]: "https://i.imgur.com/EwhtKkU.png",
[TankClass.TANK_CLASS_MEDIUM]: "https://i.imgur.com/u8YDMBh.png",
[TankClass.TANK_CLASS_HEAVY]: "https://i.imgur.com/8xRf3nc.png",
};
export const TIERS = times(10, (index) => index + 1);
export const TIER_ROMAN_NUMERALS: Record<number, string> = {
1: "I",
2: "II",
3: "III",
4: "IV",
5: "V",
6: "VI",
7: "VII",
8: "VIII",
9: "IX",
10: "X",
};
export const flags: Record<string, string> = {
ussr: "<:ussr:1218421042033197197>",
germany: "🇩🇪",
usa: "🇺🇸",
china: "🇨🇳",
uk: "🇬🇧",
france: "🇫🇷",
japan: "🇯🇵",
european: "🇪🇺",
other: "<:other:1218421572243558482>",
};
export const TREE_TYPE_ICONS: Record<TankType, Record<TankClass, string>> = {
[TankType.TANK_TYPE_RESEARCHABLE]: TANK_ICONS,
[TankType.TANK_TYPE_PREMIUM]: TANK_ICONS_PREMIUM,
[TankType.TANK_TYPE_COLLECTOR]: TANK_ICONS_COLLECTOR,
};
@@ -1,9 +0,0 @@
import { fetchPB } from '../../protobuf';
import { TankDefinitions } from '../../protos';
import { asset } from '../asset';
export function fetchTankDefinitions() {
return fetchPB(asset('definitions/tanks.pb'), TankDefinitions);
}
export * from './constants';
-7
View File
@@ -1,7 +0,0 @@
import { asset } from "./asset";
export const BLITZKIT_TANK_ICON_SIZE = { width: 40 * 16, height: 30 * 16 };
export function tankIcon(id: number, size: "big" | "small" = "big") {
return asset(`icons/tanks/${size}/${id}.webp`);
}
-52
View File
@@ -1,52 +0,0 @@
import locales from "@blitzkit/i18n/locales.json";
import { deburr } from "lodash-es";
import { I18nString } from "../protos";
import { fetchCamouflageDefinitions } from "./camouflageDefinitions";
import { fetchTankDefinitions } from "./tankDefinitions";
export async function fetchTankNames() {
const [tankDefinitions, camouflageDefinitions] = await Promise.all([
fetchTankDefinitions(),
fetchCamouflageDefinitions(),
]);
const tankDefinitionsArray = Object.values(tankDefinitions.tanks);
return await Promise.all(
tankDefinitionsArray.map(async (tank) => {
const searchableNameDeburr: I18nString = { locales: {} };
Object.entries(tank.name!).forEach(([key, value]) => {
searchableNameDeburr.locales[key] = deburr(value);
});
return {
id: tank.id,
name: tank.name,
searchableName: tank.name,
searchableNameDeburr,
camouflages: tank.camouflages
?.map((id) =>
locales.supported.map(
({ locale }) =>
camouflageDefinitions.camouflages[id]?.name!.locales[locale],
),
)
.flat()
.filter(Boolean)
.map(deburr)
.join(" "),
treeType: tank.type,
};
}),
);
}
export const SEARCH_KEYS = [
...locales.supported
.map(({ locale }) => [
`searchableName.locales.${locale}`,
`searchableNameDeburr.locales.${locale}`,
])
.flat(),
"camouflages",
];
+5 -5
View File
@@ -1,11 +1,11 @@
import { assertSecret } from '../blitzkit/assertSecret';
import { secret } from "../secrets";
export function patreonLoginUrl() {
const params = new URLSearchParams({
response_type: 'code',
client_id: assertSecret(import.meta.env.PUBLIC_PATREON_CLIENT_ID),
redirect_uri: assertSecret(import.meta.env.PUBLIC_PATREON_REDIRECT_URI),
scope: 'identity',
response_type: "code",
client_id: secret("PUBLIC_PATREON_CLIENT_ID"),
redirect_uri: secret("PUBLIC_PATREON_REDIRECT_URI"),
scope: "identity",
});
return `https://www.patreon.com/oauth2/authorize?${params}`;
+3 -6
View File
@@ -6,7 +6,7 @@ export enum SecretType {
Number,
}
export type PassableSecretName = WellKnownSecret | (string & {});
export type PassableSecretName = WellKnownSecret;
export function secret(
name: PassableSecretName,
@@ -18,10 +18,7 @@ export function secret(
type: SecretType.Number,
): number;
export function secret(
name: WellKnownSecret | (string & {}),
type = SecretType.String,
) {
export function secret(name: PassableSecretName, type = SecretType.String) {
if (!hasSecret(name)) {
throw new Error(`Secret "${name}" not defined`);
}
@@ -30,7 +27,7 @@ export function secret(
switch (type) {
case SecretType.String:
return value;
return String(value);
case SecretType.Number:
return Number(value);
+9 -2
View File
@@ -1,10 +1,17 @@
export type WellKnownSecret =
// development set-up
| "TEMP"
// website
| "BUILD_CHUNK"
| "TEXTURE_CHUNKS"
| "TEMP"
// wotb
| "WOTB_SERVER"
| "WOTB_VERSION"
| "PUBLIC_WOTB_CLIENT"
| "WOTB_USMAP"
// google
| "GOOGLE_APPLICATION_CREDENTIALS"
| "PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID";
| "PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID"
// patreon
| "PUBLIC_PATREON_CLIENT_ID"
| "PUBLIC_PATREON_REDIRECT_URI";
@@ -1,22 +0,0 @@
import { fetchTankDefinitions } from '../blitzkit';
import type { BlitzStats } from './compositeStats/constants';
export async function getTierWeights(
stats: Record<number, BlitzStats>,
order: number[] = Object.keys(stats).map(parseInt),
) {
const tankDefinitions = await fetchTankDefinitions();
const tierWeights: TierWeightsRecord = {};
order.forEach((id) => {
const entry = tankDefinitions.tanks[id];
if (!entry) return;
if (!tierWeights[entry.tier]) tierWeights[entry.tier] = 0;
tierWeights[entry.tier]! += stats[id].battles;
});
return tierWeights;
}
export type TierWeightsRecord = Partial<Record<number, number>>;
+8 -9
View File
@@ -1,9 +1,8 @@
export * from './calculateWN8';
export * from './compositeStats';
export * from './deltaBkrlBlitzStats';
export * from './deltaTankStats';
export * from './getBkniPercentile';
export * from './getTierWeights';
export * from './getWN8Percentile';
export * from './percentiles';
export * from './sumAllStats';
export * from "./calculateWN8";
export * from "./compositeStats";
export * from "./deltaBkrlBlitzStats";
export * from "./deltaTankStats";
export * from "./getBkniPercentile";
export * from "./getWN8Percentile";
export * from "./percentiles";
export * from "./sumAllStats";