Shatari Data Backend

WoW auction-house price tracker — data engine. Раздаёт только данные (gzip-бинарь .bin + JSON-метаданные) по HTTP; CORS — по белому списку origin'ов фронтов. API-слоя нет: фронт фетчит файлы по фиксированным URL и парсит сам. Эталон логики парсинга — проект shatari-front (src/ts/).

проверяю…

Единицы и форматы

• Цена в файлах — серебро (uint32): gold = silver / 100, copper = silver × 100.
• Время — unix-секунды (uint32): ms = sec × 1000. Все числа little-endian.
• .bin лежат gzip-сжатыми, отдаются с Content-Encoding: gzip → браузер инфлейтит сам (await res.arrayBuffer(), без ручного gunzip). Первый байт = версия формата.
• itemKey = id | id-level | id-level-suffix (хвостовые нули отброшены).
• connectedId ≠ realmId — данные лежат по connectedId (поле в realm-list). Commodity-реалмы: 32512 (us), 32513 (eu), 32514 (tw), 32515 (kr).
• Локали: enus dede eses esmx frfr itit kokr ptbr ruru zhtw   Регионы: us eu tw kr.

JSON-метаданные (статика, парсится как обычный JSON)

ПутьЧто внутри
/json/realms/realm-list.json{realmId: {id, connectedId, region, slug, population}} — список реалмов
/json/realms/realm-names.{locale}.jsonимена реалмов по локали
/json/items.unbound.json{itemId: {class, subclass, icon, quality, itemLevel, stack, …}}
/json/names.unbound.{locale}.json{itemId: "имя предмета"}
/json/categories.{locale}.jsonиерархия категорий аукциона
/json/name-suffixes.{locale}.json{suffixId: {name}}
/json/battlepets.json + .{locale}.jsonметаданные/имена боевых питомцев
/json/vendor.jsonтаблицы цен NPC (vendor-flip)
/json/bonusToStats.json{bonusId: [statId]} — бонус → тертиарные статы
/json/items.bound.json, /json/names.bound.{locale}.jsonзаглушка 200 {} — bound-метаданные не генерируются; фронт мержит пустой объект

JSON сжимается gzip на лету (по Accept-Encoding); Cache-Control: max-age=3600 на статике, max-age=300 на /json/realms/* и /data/**.json.

Бинарные данные (.bin, gzip, парсить через DataView)

ПутьЧто / версия
/data/global/state.binснапшоты по всем реалмам (timeline). GlobalState v2 (байт 0x02)
/data/global/region-{region}.binрегиональные медианы + арбитраж. RegionState v2
/data/global/deals-{region}.binвыгодные сделки (median vs dealPrice). DealState v1
/data/global/token-{region}.binцена WoW Token + история. TokenState v1
/data/{connectedId}/state.binсводка реалма: все предметы + текущая цена/кол-во. RealmState v4 (байт 0x04)
/data/{connectedId}/{itemId&255}/{itemKey}.binистория цены предмета: текущая + hourly (14д) + daily + лоты. ItemState v5 (байт 0x05)
/data/{connectedId}/pet/{species&255}/{itemKey}.binто же для пет-клеток (itemId 82800)

404 на конкретном item-.bin — норма: по этому предмету ещё нет данных (особенно первые часы).

WoW Classic (префикс /classic/, если сбор включён)

ПутьЧто
/classic/json/realms/realm-list.jsonсписок classic-реалмов (та же форма, что retail; + realm-names.{locale}.json)
/classic/data/…те же форматы и раскладка, что /data/…, но для Classic (Cata/MoP): global/state, region/deals/token-{region}.bin, {connectedId}/state.bin, item-.bin
/classic/data/{connectedId}/pet/{species&255}/{itemKey}.binпет-клетки (itemId 82800) — в classic ЕСТЬ с фазы MoP, формат как в retail
/classic/data/global/region-{region}-stats.jsonregion-wide {itemKey: {current, mean, quantity, realms}} — единственный регионный источник для стакаемых (в classic region-*.bin/deals-*.bin содержат только stack==1)

Отличия от retail: НЕТ commodity-псевдореалмов (/classic/data/32512…32515 → 404), у item-ключей suffix=0 (кроме петов). Статические метаданные /json/* общие с retail и без префикса (/classic/json/<не realms/> → 404); /classic-era/** зарезервирован и пуст. Подробно: railway/FRONTEND_CONTRACT_CLASSIC.md.

Как построить путь к предмету (JS)

function itemBinPath(connectedId, itemId, level, suffix) {
  const key = itemId + (level ? '-' + level + (suffix ? '-' + suffix : '') : '');
  if (itemId === 82800) return `data/${connectedId}/pet/${level & 0xFF}/${key}.bin`;
  return `data/${connectedId}/${itemId & 0xFF}/${key}.bin`;
}
// fetch -> res.arrayBuffer() -> new DataView(buf); первый байт = версия (0x05 = ItemState v5)

Эндпоинты-утилиты

/healthzhealthcheck → ok
/api-index.jsonэтот же список в машиночитаемом JSON

Подключение фронта

Фронт хостится отдельно. В shatari-front/vite.config.js поменяй прокси /data (и /json) на этот домен — и собранный фронт (npm run build) работает на наших данных. Полный контракт — в railway/DATA_ACCESS.md. Логику парсинга копируй из shatari-front/src/ts/ (Detail.ts, Auctions.ts, Realms.ts, Items.ts).