npm.io
2.0.0 • Published yesterday

travian-kingdoms-api

Licence
MIT
Version
2.0.0
Deps
0
Size
80 kB
Vulns
0
Weekly
0
Stars
3

Travian Kingdoms API

npm version License: MIT

Modern, fully-typed JavaScript/TypeScript client for the Travian Kingdoms public API endpoints.

  • TypeScript-first — ships with complete type definitions and rich JSDoc.
  • Promise based — every call works with async/await.
  • Zero runtime dependencies — built on the native fetch API.
  • Dual package — usable from both ESM (import) and CommonJS (require).

What is a public endpoint?

Public endpoints are the external-tools endpoints published by Travian Kingdoms so that third-party tools can read game world data.

Requirements

  • Node.js >= 18 (for the built-in global fetch). On older runtimes you can pass your own fetch implementation via the per-call request.fetch option.

Installation

npm install travian-kingdoms-api

Quick start

import { register, getMapData } from 'travian-kingdoms-api';

// 1. Register your tool to obtain the API keys.
const { response: keys } = await register({
	url: 'https://cz4.kingdoms.com',
	email: 'me@example.com',
	siteName: 'My Tool',
	siteUrl: 'https://tool.example',
	isPublic: true,
});

// 2. Use the private key to fetch data.
const { response: map } = await getMapData({
	url: 'https://cz4.kingdoms.com',
	privateApiKey: keys.privateApiKey,
});

console.log(map.gameworld.name, map.players.length);

CommonJS is fully supported too:

const { register } = require('travian-kingdoms-api');

Migrating from v1

Version 2 is a complete rewrite. The old callback-based API (tka.register(options, (err, response, body) => { ... })) has been replaced by a Promise-based API that you await. The response is the parsed body directly, and failed HTTP requests reject with a TravianApiError instead of surfacing an error argument.

// v1 (removed)
tka.register(options, (err, response, body) => {
	console.log(body);
});

// v2
const body = await register(options);
console.log(body);

API

All functions return a Promise<ApiEnvelope<T>>, where ApiEnvelope is:

interface ApiEnvelope<T> {
	time: number; // server timestamp (ms)
	response: T; // endpoint-specific payload
}

Each function also accepts an optional second argument, RequestOptions, for cancellation and dependency injection:

interface RequestOptions {
	signal?: AbortSignal; // cancel the request (e.g. for a timeout)
	fetch?: typeof fetch; // supply a custom fetch implementation
}
register(options, request?)

Call this first to obtain a privateApiKey / publicSiteKey. The privateApiKey authenticates all other calls.

Option Type Required Meaning
url string yes Game world URL, e.g. https://cz4.kingdoms.com
email string (≤ 255) yes A valid e-mail address
siteName string (≤ 255) yes Name of the tool
siteUrl string (≤ 255) yes A valid, publicly reachable URL of the tool
isPublic boolean yes When true, your tool may be included in the public tool list
const { response } = await register({
	url: 'https://cz4.kingdoms.com',
	email: 'some@email.com',
	siteName: 'someSiteName',
	siteUrl: 'http://www.someSite.url',
	isPublic: true,
});
// response => { privateApiKey: 'xxx', publicSiteKey: 'yyy' }
updateSiteData(options, request?)

Update the metadata of a previously registered tool.

Option Type Required Meaning
url string yes Game world URL
privateApiKey string yes Your private API key (from register)
email string (≤ 255) yes A valid e-mail address
siteName string (≤ 255) yes Name of the tool
siteUrl string (≤ 255) yes A valid, publicly reachable URL of the tool
isPublic boolean yes Public tool list opt-in
const { response } = await updateSiteData({
	url: 'https://cz4.kingdoms.com',
	privateApiKey: 'xxx',
	email: 'some@email.com',
	siteName: 'someSiteName',
	siteUrl: 'http://www.someSite.url',
	isPublic: true,
});
// response => { data: true }
getMapData(options, request?)

Fetch a full public map snapshot (the classic map.sql) for a given day.

Option Type Required Meaning
url string yes Game world URL
privateApiKey string yes Your private API key (from register)
date string no Day in d.m.Y format (e.g. 27.08.2014). Defaults to today when omitted.
const { response } = await getMapData({
	url: 'https://cz4.kingdoms.com',
	privateApiKey: 'xxx',
	date: '20.02.2018', // optional
});

The response payload has the following shape:

{
	gameworld: {
		name: 'cz4',
		startTime: 1518008400,
		speed: 1,
		speedTroops: 1,
		lastUpdateTime: '1519167901',
		date: 1519084800,
		version: '1.0',
	},
	players: [ /* ... */ ],
	kingdoms: [ /* ... */ ],
	map: {
		radius: '60',
		cells: [ /* ... */ ],
		landscapes: [ /* ... */ ],
	},
}
TravianKingdomsClient

A convenience wrapper that binds the game world url (and optionally a privateApiKey) so you don't have to repeat them on every call.

import { TravianKingdomsClient } from 'travian-kingdoms-api';

const client = new TravianKingdomsClient({
	url: 'https://cz4.kingdoms.com',
	privateApiKey: 'xxx',
});

const { response } = await client.getMapData({ date: '20.02.2018' });

Error handling

Non-successful HTTP responses reject with a TravianApiError exposing the status, status text, requested URL (with secrets redacted) and the parsed body.

import { getMapData, TravianApiError } from 'travian-kingdoms-api';

try {
	await getMapData({ url: 'https://cz4.kingdoms.com', privateApiKey: 'xxx' });
} catch (error) {
	if (error instanceof TravianApiError) {
		console.error(error.status, error.statusText, error.body);
	}
}

Cancellation & timeouts

Pass an AbortSignal through the second argument:

await getMapData(
	{ url: 'https://cz4.kingdoms.com', privateApiKey: 'xxx' },
	{ signal: AbortSignal.timeout(5000) },
);

Contributing

Development setup and the release process live in CONTRIBUTING.md.

License

MIT JaLe

Keywords