Migrating
From 2.x to 3.0
The PokéAPI reworked its evolution data and grew its sprite tree, and 3.0 follows both. The fields 2.x declared for the old shapes no longer arrive, so code reading them was already getting undefined.
EvolutionDetail
base_formis nowrequired_pokemon_form, andevolved_formis nowevolved_pokemon_form.- New:
allowed_natures(Toxtricity's forms) andcondition_expression(Wurmple, Maushold) — see hidden values.
Evolution triggers
- Trigger 10 is
in-battle-level-upupstream, no longerother.EVOLUTION_TRIGGERS.OTHERis nowEVOLUTION_TRIGGERS.IN_BATTLE_LEVEL_UP, andEvolutionTriggerNamedrops'other'. - New:
meltan-candies(17) andunclassified(18).
Requirements
requirementsOfemits{ kind: 'required-form' }where it emitted{ kind: 'base-form' }. Aphrasesoverride keyed'base-form'must be renamed.- New kinds
allowed-naturesandcondition. Aswitchoverkindthat is checked for exhaustiveness needs cases for both.
Evolution variables
New endpoint: EvolutionClient gains getEvolutionVariableById, getEvolutionVariableByName and listEvolutionVariables, with ENDPOINTS.EVOLUTION_VARIABLE and EVOLUTION_VARIABLES. Variables carry a source: pokemon (encryption-constant, personality-value) or player-input (spin-direction, spin-duration). An expression over player input has percentage_chance: null.
Sprites
BrilliantDiamondShiningPearldropsfront_female, which upstream no longer publishes.PokemonFormSpritesnow carries the whole tree, likePokemonSprites:otheris new, andversionsis aVersionSprites.PokemonFormVersionSpritesandPokemonFormGenerationVIIISpritesare removed — useVersionSpritesandGenerationVIIISprites.- New sprite sets, all additions: official artwork
versions,red-green-japan,lets-go-pikachu-lets-go-eeveeandchampions; gray, Game Boy Color and transparent variants in generations I and II;animatedsets for Emerald and generation IV; back sprites for generations VI and VII;iconsfor generations III, IV and VI.
From 1.x to 2.0
Version 2.0 replaces Axios with the platform's native fetch. pokenode-ts now ships with no runtime dependencies and runs anywhere fetch exists — Node 22+, Deno, Bun, browsers, and edge runtimes.
Every client method keeps the same name, arguments, and return type. Installation, client options, and error handling change.
Installation
Axios and its cache interceptor are no longer peer dependencies. Uninstall them if nothing else in your project uses them:
npm uninstall axios axios-cache-interceptor
npm install pokenode-tsCache options
cacheOptions is replaced by a single cache slot: omit it for the default in-memory store, pass false to disable caching, or supply your own. Anything shaped for the old interceptor — storage, generateKey, interpretHeader, methods — no longer type-checks.
// 1.x
new BerryClient({ cacheOptions: { ttl: 1000 * 60 * 5, methods: ['get'] } });
// 2.0
new BerryClient({ cache: new MemoryCache({ ttl: 300000, maxEntries: 500 }) });If you supplied a custom storage to axios-cache-interceptor, the replacement is a CacheStore implementation — see Bring your own store.
See the Cache guide for the full behavior.
Logging
logs: true is replaced by a logger slot, so requests can be reported somewhere other than the console. Pass the bundled consoleLogger for the 1.x behavior:
// 1.x
new BerryClient({ logs: true });
// 2.0
new BerryClient({ logger: consoleLogger });See the Logging guide for the Logger interface.
Renamed and removed exports
ClientArgsis nowClientOptions. The fields are unchanged apart fromlogs.ENDPOINTS.POKEMON_LOCATION_AREAis gone. It held the template/pokemon/:id/encountersrather than an endpoint, and never worked without a string replacement. UsePokemonClient#getPokemonLocationAreaById, which was always the supported route.LANGUAGES.ROOMAJIis nowLANGUAGES.JA_ROMA, following the PokéAPI's own rename of language 2 fromroomajitoja-roma. The id is unchanged, so only the key needs updating.ItemClient#listItemFilingEffectsis nowlistItemFlingEffects. The old name was a typo — the endpoint isitem-fling-effect, named after the move Fling. Behavior is unchanged.
MainClient
MainClient no longer extends BaseClient, so mainClient instanceof BaseClient is now false. Its sub-clients are unchanged, and they now share one cache rather than holding one each.
Errors
Failed requests used to reject with an AxiosError. A non-2xx response now rejects with a PokenodeError, which carries the response details directly:
import { PokenodeError, BerryClient } from 'pokenode-ts';
try {
await new BerryClient().getBerryByName('not-a-berry');
} catch (error) {
if (PokenodeError.isPokenodeError(error)) {
console.log(error.status); // 404
console.log(error.statusText); // 'Not Found'
console.log(error.url); // the request URL
console.log(error.body); // parsed JSON body, when the response had one
}
}TIP
Prefer the isPokenodeError guard over instanceof. A dependency tree that loads both the ESM and the CJS build of pokenode-ts ends up with two distinct classes, and instanceof against the wrong one is silently false. The guard matches on a brand instead, so it holds either way.
Transport failures — offline, DNS — are not wrapped. They reject with the native TypeError that fetch produced. See the Errors guide for the full breakdown.
Timeouts and cancellation
Neither 1.x nor 2.0 imposes a timeout of its own. In 2.0, derive a scoped client with with() rather than reaching for the constructor:
const api = new BerryClient();
await api.with({ timeout: 5000 }).getBerryByName('cheri');with() takes a signal too, and MainClient#with scopes all twelve sections at once. See Cancellation.
An abort rejects with the runtime's own DOMException, not with a pokenode error.