KehittäjätTypeScript-SDK
Hostwolf-SDK JavaScriptille & TypeScriptille
@hostwolf/sdk on Hostwolf-rajapinnan virallinen tyypitetty asiakaskirjasto. Sillä ohjaat pelipalvelimiasi koodista: virta, konsoli, tiedostot, varmuuskopiot, modit, pelaajat, ajastukset ja paljon muuta.
npm install https://hostwolf.net/dl/hostwolf-sdk-0.1.8.tgz
SDK jaetaan osoitteesta hostwolf.net npm-rekisterin sijaan. Yllä oleva komento lisää sen tiedostoosi package.json muodossa "@hostwolf/sdk": "https://hostwolf.net/dl/hostwolf-sdk-0.1.8.tgz", ja tuot sen nimellä @hostwolf/sdk. pnpm, yarn ja bun hyväksyvät saman URL-osoitteen. Jokaisella versiolla on oma URL; katso Versiot.
Se toimii Node 18+:lla, Bunilla ja Denolla, eikä sillä ole ajonaikaisia riippuvuuksia. Reaaliaikaista konsolia varten aja Node-versioissa ennen 22:ta myös npm install ws.
Katso myös: REST-rajapinnan viite · MCP-palvelin · Muutosloki · Hanki API-avain
Pikaopas#
Luo API-avain osoitteessa panel.hostwolf.net/account/api ja sitten:
import { Hostwolf } from '@hostwolf/sdk';
const hw = new Hostwolf({ apiKey: process.env.HOSTWOLF_API_KEY! });
const { data: servers } = await hw.servers.list();
for (const s of servers) {
const res = await hw.servers.resources(s.identifier);
console.log(s.name, s.egg_name, res.current_state);
}
const id = servers[0].identifier;
await hw.servers.command(id, 'say Backup in 1 minute');
await hw.backups.create(id, { name: 'before-update' });
console.log(await hw.tail(id, { lines: 20 }));
Jokainen palvelinmetodi ottaa ensimmäiseksi argumentiksi palvelimen lyhyen identifier-tunnuksen (sen paneelin URL-osoitteen 8 merkkiä) tai sen UUID:n. Vastausoliot käyttävät rajapinnan omia kenttien nimiä (snake_case). Niiden TypeScript-tyypit viedään, esim. Server, Backup ja FileObject.
Asetukset#
new Hostwolf({
apiKey: 'ptlc_...', // required
baseUrl: 'https://panel.hostwolf.net', // default
timeoutMs: 30_000, // per request
maxRetries: 2, // 429s, and 502/503/504 on GET
maxRetryWaitMs: 10_000, // longer Retry-After waits fail fast instead
fetch: customFetch, // optional
WebSocket: customWebSocket, // optional, for the console
});
Palvelimet#
REST: Palvelinten rajapinnat
| Metodi | Mitä se tekee |
|---|---|
servers.list({ page, per_page }) | Sivu palvelimistasi: { data, pagination } |
servers.listAll() | Asynkroninen iteraattori kaikkien palvelinten yli |
servers.get(id, ['egg', 'subusers']) | Palvelimen tiedot varauksineen ja käynnistysmuuttujineen |
servers.resources(id) | Reaaliaikainen tila, suoritin, muisti, levy, verkko, käyntiaika |
servers.power(id, signal) / start / stop / restart / kill | Virtatoiminnot |
servers.command(id, command) | Aja konsolikomento |
servers.activity(id) | Tapahtumaloki (sivutettu) |
servers.rename(id, name, description?) | Nimeä uudelleen |
servers.reinstall(id) | Aja asennusskripti uudelleen |
servers.setDockerImage(id, image) | Vaihda ajonaikainen image (esim. Java-versio) |
servers.websocket(id) | Konsolin tunniste ja socketin URL (alla oleva konsoli käyttää niitä) |
servers.waitForState(id, 'running', { timeoutMs }) | Odottaa, kunnes palvelin on tietyssä tilassa, esim. start()-kutsun jälkeen. Palauttaa sen resurssit |
await hw.servers.start(id);
await hw.servers.waitForState(id, 'running'); // default timeout 5 minutes
const line = await hw.waitForConsole(id, /There are \d+ of a max/, { send: 'list' });
Konsoli#
const c = await hw.console(id).connect();
c.on('output', (line) => console.log(line));
c.on('stats', (s) => console.log(s.state, s.memory_bytes));
c.requestLogs(); // replay recent output
c.sendCommand('list');
// later
c.close();
// Or just fetch the recent lines (ANSI colours stripped):
const lines = await hw.tail(id, { lines: 50 });
// Or wait for one line: send a command and get its reply.
const reply = await hw.waitForConsole(id, /There are \d+ of a max/, { send: 'list', timeoutMs: 20_000 });
waitForConsole(id, pattern, { send, includeRecent, timeoutMs }) palauttaa ensimmäisen rivin, joka vastaa merkkijonoa tai RegExpiä. includeRecent hakee myös tuoreesta lokista, ja kutsu epäonnistuu koodilla Timeout, kun timeoutMs (oletus 30 sekuntia) kuluu.
Konsoli yhdistää suoraan nodeen, jossa palvelimesi toimii, ja uusii tokeninsa automaattisesti.
Tapahtumat:
readyjacloseoutputstatusstatsinstall outputdaemon messagejadaemon errorerror
Tiedostot#
REST: Tiedostojen rajapinnat
await hw.files.list(id, '/plugins');
const props = await hw.files.read(id, 'server.properties');
await hw.files.write(id, 'server.properties', props.replace('pvp=true', 'pvp=false'));
await hw.files.rename(id, '/', [{ from: 'world', to: 'world-old' }]);
await hw.files.delete(id, '/logs', ['old.log']);
await hw.files.createFolder(id, '/', 'maps');
await hw.files.compress(id, '/', ['world']); // returns the archive
await hw.files.decompress(id, '/', 'world.tar.gz');
await hw.files.pull(id, 'https://example.com/map.zip', { directory: '/maps' });
await hw.files.exists(id, 'plugins/LuckPerms.jar'); // true or false
// Binary files: upload and download go straight to the server's node.
await hw.files.upload(id, '/plugins', jarBytes, 'MyPlugin.jar'); // Blob, ArrayBuffer, Uint8Array or string
const buf = await hw.files.download(id, 'world.tar.gz'); // ArrayBuffer, in memory
// Or work with the signed URLs yourself, e.g. to stream a big file:
const url = await hw.files.downloadUrl(id, 'world.tar.gz');
const uploadUrl = await hw.files.uploadUrl(id); // POST multipart "files" to `${uploadUrl}&directory=/maps`
Olemattoman tiedoston lukeminen heittää virheen HostwolfError tilalla 404 ja koodilla NotFound. Lisäksi saatavilla: files.copy(id, path) ja files.chmod(id, root, [{ file, mode }]).
Varmuuskopiot#
const { data } = await hw.backups.list(id);
const b = await hw.backups.create(id, { name: 'nightly', is_locked: false });
await hw.backups.waitUntilDone(id, b.uuid); // polls until finished; rejects with code BackupFailed if it failed
await hw.backups.get(id, b.uuid);
await hw.backups.restore(id, b.uuid, { truncate: false });
await hw.backups.toggleLock(id, b.uuid);
await hw.backups.downloadUrl(id, b.uuid);
await hw.backups.delete(id, b.uuid);
await hw.backups.smartState(id);
await hw.backups.setSmart(id, true); // automatic backups before risky changes
Voit luoda 2 varmuuskopiota 10 minuutissa. Sen yli create() epäonnistuu heti, ja error.retryAfter on asetettu.
Tietokannat#
Jokaisella palvelimella on omalla koneellaan enintään 5 MySQL-yhteensopivaa tietokantaa. Ensimmäinen käynnistää myös tietokantapalvelun, mikä kestää noin 40 sekuntia: API vastaa 202 ja create() palauttaa odottavan tuloksen, ellet anna asetusta wait.
import { isDatabasePending } from '@hostwolf/sdk';
// Simplest: wait until the database exists (up to 2 minutes), then use it
const db = await hw.databases.create(id, 'luckperms', { wait: true });
console.log(db.host.address, db.name, db.username, db.relationships?.password?.password);
// Or handle the pending answer yourself
const r = await hw.databases.create(id, 'coreprotect');
if (isDatabasePending(r)) {
const ready = await hw.databases.waitUntilReady(id, 'coreprotect', { timeoutMs: 120_000 });
}
await hw.databases.service(id); // { status, local_address, public_address, other_servers }
await hw.databases.setRemoteAccess(id, db.id, { remoteIps: ['203.0.113.7'], anywhere: false });
await hw.databases.rotatePassword(id, db.id);
const dump = await hw.databases.export(id, db.id); // .sql.gz bytes
await hw.databases.import(id, db.id, dump, { filename: 'luckperms.sql.gz' });
await hw.databases.delete(id, db.id);
Pelipalvelimet yhdistävät osoitteeseen db.host (172.18.0.1:3306). db.name sisältää etuliitteen, esimerkiksi s12_luckperms; waitUntilReady() ottaa pyytämäsi nimen. Muut metodit ottavat db.id:n. waitUntilReady() epäonnistuu koodilla DatabaseSetupFailed, jos palvelu ei käynnistynyt, tai koodilla Timeout. Voit luoda 2 tietokantaa minuutissa ja viedä tai tuoda 6 minuutissa.
Peli, pelaajat ja asetukset#
await hw.game.versions(id); // current + available versions
await hw.game.setVersion(id, '1.21.4'); // switches and reinstalls; { resetWorld, force } for downgrades
await hw.game.settings(id); // friendly settings, grouped by file ({ supported: false } on Java Minecraft)
await hw.game.updateSettings(id, { difficulty: 'hard' }, true);
await hw.game.diagnostics(id); // "Fix my server" checks
await hw.players.info(id); // online count (+ names on Minecraft)
await hw.players.list(id); // live list via RCON/query
await hw.players.kick(id, 'Steve');
await hw.players.ban(id, { steamid: '7656...' });
await hw.players.unban(id, 'Steve');
await hw.players.broadcast(id, 'Restarting in 5 minutes');
Modit, lisäosat ja modipaketit#
const profile = await hw.addons.profile(id); // sources, install dir, frameworks
const { items } = await hw.addons.search(id, 'modrinth', 'worldedit');
await hw.addons.install(id, 'modrinth', items[0].id); // newest compatible version
const installed = await hw.addons.installed(id, { checkUpdates: true });
await hw.addons.uninstall(id, installed.addons[0].id);
const packs = await hw.modpacks.search(id, 'cobblemon');
await hw.modpacks.install(id, packs.items[0].id, { freshWorld: false });
Muut lisäosakutsut:
addons.versions(id, source, project): versiot merkittyinä yhteensopiviksi tai ei.addons.installFeatured(id, project): suositellut lisäosat yhdellä napsautuksella, listastaprofile.featured.addons.upload(id, blob, name): kunprofile.uploadon asetettu. Muuten vie tiedostot kansioonprofile.directorykutsullafiles.upload().addons.removeManual(id, file): poistaa itse lisäämäsi tiedoston.addons.setFramework(id, framework): esim. Oxide tai Carbon Rustissa.addons.workshop/setWorkshop/workshopPreview(Steam Workshopia käyttävät pelit).addons.cs2Framework(id, { repair }): Metamod + CounterStrikeSharp CS2:ssa.modpacks.current/versions/remove.
Lisää#
| Nimiavaruus | Metodit |
|---|---|
startup | get(id), setVariable(id, key, value) |
schedules | list, get, create, update, execute, delete, createTask, updateTask, deleteTask |
databases | list(id, { includePassword }), create, waitUntilReady, service, setRemoteAccess, rotatePassword, export, import, delete. Katso Tietokannat |
network | allocations, createAllocation, setNotes, setPrimary, deleteAllocation |
users | list, get, create(id, publicId, permissions), update, delete, permissions(). Tilit lisätään julkisella tunnuksella (HW-XXXXXX), ei sähköpostilla |
notifications | Palvelinkohtaiset Discord-ilmoitukset: get, update, test |
domain | Oma verkkotunnus: get, check, set, remove |
mcNetwork | Velocity/BungeeCord-verkot: get, link, unlink, installFabricProxy |
account | get, updateEmail, updatePassword, updateProfile, updateLanguage(locale, currency?), uploadAvatar, deleteAvatar, activity, getNotifications, updateNotifications, testNotification, getCurseforgeKey, setCurseforgeKey, getFactorioCredentials, setFactorioCredentials |
account.apiKeys | list, create(description, allowedIps?) (palauttaa koko avaimen kentässä token, vain kerran), delete(identifier) |
account.sshKeys | list, create(name, publicKey), delete(fingerprint) |
store | Vain luku: catalog(), orders(), billing() |
Palvelinten tilaaminen, peruminen ja maksaminen onnistuu vain paneelissa, joten API-avain ei voi koskaan käyttää rahaa.
Sivutus#
servers.list, backups.list ja activity-metodit palauttavat { data, pagination }. Näin käyt läpi kaikki palvelimet:
import { collect } from '@hostwolf/sdk';
const all = await collect(hw.servers.listAll());
Virheet#
REST: Virhemuoto ja tilakoodit
Epäonnistuneet kutsut heittävät HostwolfError-virheen.
import { HostwolfError } from '@hostwolf/sdk';
try {
await hw.game.setVersion(id, '1.16.5');
} catch (e) {
if (e instanceof HostwolfError && e.code === 'downgrade_requires_reset') {
// older versions can't load a newer world: retry with { resetWorld: true } or { force: true }
}
}
Sillä on nämä ominaisuudet:
status: HTTP-tila, tai 0 verkkovirheissä ja aikakatkaisuissa.code: virhekoodi. API:n koodien lisäksi SDK käyttää koodejaNetworkError(ei vastausta tai aikakatkaisu),Timeout(waitFor…- taiwaitUntil…-apufunktio luovutti),BackupFailed,DatabaseSetupFailed,DatabaseNotCreatedjaNotFound(puuttuva tiedosto).retryAfter: 429-virheessä sekunnit siihen, kun toiminto on taas sallittu. Lyhyet odotukset yritetään uudelleen puolestasi; pidemmät (kuten 2 varmuuskopiota 10 minuutissa) epäonnistuvat heti ja asettavat tämän arvon.message: luettava kuvaus.errors: virheiden raakalista.body: vastauksen sisältö.- Pikatarkistukset:
isNotFound,isRateLimitedjaisValidation.
Yleisimmät:
401: avain on väärä, vajaa tai peruttu.403jaThis IP address (…) does not have permission: avaimella on sallittujen IP-osoitteiden lista, jossa osoitettasi ei ole.409 downgrade_requires_resetja422 unknown_version: kutsustagame.setVersion().429: pyyntöraja; katsoretryAfter.- Aikakatkaistu kirjoitus (tila 0) voi silti valmistua paneelissa, joten tarkista ennen kuin yrität uudelleen.
Suorat pyynnöt#
Jos päätepisteelle ei vielä ole metodia, kutsu sitä suoraan:
await hw.http.get(`/servers/${id}/players`);
await hw.http.post(`/servers/${id}/command`, { command: 'list' });
Polut ovat suhteessa osoitteeseen /api/client, ja vastaukset puretaan samoin kuin valmiissa metodeissa. Kaikki päätepisteet löytyvät rajapinnan viitteestä.
Versiot#
| Tiedosto | Käyttö |
|---|---|
https://hostwolf.net/dl/hostwolf-sdk- | Kiinteä versio. Käytä tätä tiedostossa package.json. |
https://hostwolf.net/dl/hostwolf-sdk.tgz | Aina uusin versio. Paketinhallinnat tallentavat välimuistiin URL-osoitteen mukaan, joten käytä mieluummin versioituja URL-osoitteita. |
https://hostwolf.net/dl/index.json | Nykyiset versiot SHA-256- ja npm-eheystiivisteineen. |
Päivitä asentamalla uudempi versioitu URL.
Lisenssi#
MIT