DéveloppeursSDK TypeScript
SDK Hostwolf Apps pour JavaScript et TypeScript
@hostwolf/apps-sdk est le client typé officiel de l’API Hostwolf Apps. Il vous permet de déployer et de faire tourner vos apps depuis votre code : projets, applications, déploiements et journaux, variables d’environnement, bases de données managées, mise à l’échelle automatique, volumes et plus encore.
npm install https://app.hostwolf.net/dl/hostwolf-apps-sdk-0.2.1.tgz
Le SDK est servi depuis app.hostwolf.net plutôt que depuis le registre npm. La commande ci-dessus l’ajoute à votre package.json sous la forme "@hostwolf/apps-sdk": "https://app.hostwolf.net/dl/hostwolf-apps-sdk-0.2.1.tgz", et vous l’importez sous le nom @hostwolf/apps-sdk. pnpm, yarn et bun acceptent la même URL. Chaque version a sa propre URL ; voir Versions.
Il fonctionne avec Node 18+, Bun et Deno, et n’a aucune dépendance à l’exécution.
Voir aussi : Référence de l’API REST · Serveur MCP · Journal des modifications · Obtenir un jeton d’API
Démarrage rapide#
Créez un jeton d’API dans la console sous Clés et jetons → Jetons d’API, puis :
import { HostwolfApps } from '@hostwolf/apps-sdk';
const hw = new HostwolfApps({ token: process.env.HOSTWOLF_APPS_TOKEN! });
const server = (await hw.servers.purchased()).find((s) => s.kind === 'app' && s.status === 'ready')!;
const { uuid: project } = await hw.projects.create({ name: 'shop' });
const app = await hw.applications.createFromGit({
project_uuid: project,
environment_name: 'production',
server_uuid: server.server_uuid!,
git_repository: 'https://github.com/acme/shop',
git_branch: 'main',
build_pack: 'nixpacks',
ports_exposes: '3000',
});
await hw.applications.setEnvs(app.uuid, { NODE_ENV: 'production' });
const deployment = await hw.deployAndWait(app.uuid);
console.log(deployment.status, await hw.applications.logs(app.uuid, { lines: 20 }));
Les ressources sont désignées par leur uuid. Les objets renvoyés utilisent les noms de champs de l’API (snake_case), et leurs types TypeScript sont exportés, par ex. Application, Deployment et ManagedDatabase.
Options#
new HostwolfApps({
token: '12|abc...', // required
baseUrl: 'https://console.app.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
language: 'de', // error messages in en, de, fr, es or fi
fetch: customFetch, // optional
});
Projets et environnements#
REST : Endpoints des projets
| Méthode | Ce que fait l’appel |
|---|---|
projects.list() / get(uuid) | Projets ; get inclut les environnements |
projects.create({ name }) | Nouveau projet avec un environnement production |
projects.update / delete | Renommer, ou supprimer un projet vide |
projects.environments(uuid) | Environnements d’un projet |
projects.environment(uuid, 'staging') | Un environnement (par nom ou uuid) avec ses ressources |
projects.createEnvironment / updateEnvironment / deleteEnvironment | Gérer les environnements |
projects.sharedEnvs / environmentSharedEnvs | Variables partagées par toutes les apps d’un projet ou d’un environnement |
Applications#
REST : Endpoints des applications
| Méthode | Ce que fait l’appel |
|---|---|
applications.list({ tag }) | Toutes les applications de l’équipe |
applications.get(uuid) | Une application avec ses réglages |
applications.createFromGit(input) | À partir d’un dépôt public (nixpacks, railpack, dockerfile ou static) |
applications.createFromPrivateRepo(input) | À partir d’un dépôt privé avec une clé de déploiement (private_key_uuid) |
applications.createFromGithubApp(input) | À partir d’un dépôt d’une GitHub App connectée (github_app_uuid) ; les déploiements par push fonctionnent d’emblée |
applications.createFromDockerfile(input) | À partir du texte d’un Dockerfile, sans dépôt |
applications.createFromImage(input) | À partir d’une image préconstruite comme ghcr.io/acme/web |
applications.update(uuid, changes) | Nom, domaines, ports, branche, commandes de build et de démarrage, contrôle de santé, limites |
applications.deploy(uuid, { force }) | Faire le build et démarrer ; renvoie le deployment_uuid |
applications.restart / stop | Redémarrer sans rebuild, ou arrêter |
applications.logs(uuid, { lines }) | Sortie récente du conteneur (le jeton nécessite read:sensitive) |
applications.metrics(uuid, { minutes }) | Historique du CPU et de la mémoire |
applications.rollbackImages / rollback(uuid, tag) | Redéployer une image précédente |
applications.delete(uuid, { deleteVolumes }) | Supprimer l’app (et, par défaut, ses volumes) |
Les apps tournent sur vos serveurs d’applications. server_uuid est le champ server_uuid de servers.purchased() (ou l’uuid de servers.list()). Omettez domains pour obtenir une adresse *.app.hostwolf.net générée.
Variables d’environnement#
| Méthode | Ce que fait l’appel |
|---|---|
applications.envs(uuid) | Variables ; les valeurs valent null sauf si le jeton a read:sensitive |
applications.setEnvs(uuid, { KEY: 'value' }) | En créer ou en mettre à jour plusieurs d’un coup |
applications.setEnv(uuid, { key, value, is_shown_once }) | En créer ou en mettre à jour une |
applications.createEnv / updateEnv | Création stricte (409 si elle existe) et mise à jour |
applications.deleteEnv(uuid, envUuid) / deleteEnvByKey(uuid, key) | Supprimer une variable |
teams.sharedEnvs() et méthodes associées | Variables à l’échelle de l’équipe, utilisées sous la forme {{team.KEY}} |
Les conteneurs en cours d’exécution voient les variables modifiées après le prochain déploiement.
Déploiements#
REST : Endpoints des déploiements
const { deployment_uuid } = await hw.applications.deploy(app.uuid);
const done = await hw.deployments.wait(deployment_uuid!, {
timeoutMs: 10 * 60_000,
onStatus: (status) => console.log(status), // queued, in_progress, finished
});
wait et deployAndWait lèvent une HostwolfAppsError avec le code deployment_failed (et les dernières lignes du journal dans le message), deployment_cancelled ou timeout. Passez throwOnFailure: false pour récupérer plutôt le déploiement échoué.
| Méthode | Ce que fait l’appel |
|---|---|
deployments.running() | Déploiements en file d’attente ou en cours, pour toute l’équipe |
deployments.get(uuid) | Un déploiement, avec son journal de build dans logs |
parseDeploymentLogs(deployment) | Le journal de build sous forme de lignes ({ output, type, timestamp }) |
deployments.forApplication(uuid, { skip, take }) | Une page des déploiements d’une app, du plus récent au plus ancien |
deployments.allForApplication(uuid) | Itérateur asynchrone sur l’ensemble |
deployments.deploy({ uuid, tag, force }) | Déployer plusieurs apps par uuid ou par tag |
deployments.cancel(uuid) | Annuler un déploiement en file d’attente ou en cours |
Serveurs#
| Méthode | Ce que fait l’appel |
|---|---|
servers.purchased() / purchasedServer(uuid) | Serveurs d’applications et VPS achetés : taille, ville, état, prix et server_uuid |
servers.list() / get(uuid) | Serveurs d’applications sur lesquels les apps peuvent tourner |
servers.resources(uuid) / domains(uuid) | Ce qui tourne sur un serveur, et ses domaines |
servers.metrics(uuid, { minutes }) | Historique du CPU et de la mémoire |
servers.destinations(uuid) | Les réseaux Docker d’un serveur (pour le multi-serveur) |
servers.traffic(uuid, { month }) | Le trafic sortant d’un serveur acheté et sa facture à ce jour (1 To par mois inclus) |
servers.teamTraffic({ month }) | La même chose pour tous les serveurs de l’équipe, avec le total |
servers.regions({ size }) | Les villes avec le prix mensuel par taille, et celles où la mise à l’échelle automatique peut ajouter des serveurs |
L’achat et la résiliation de serveurs ne sont possibles que dans la console ; un jeton d’API ne peut donc jamais acheter de serveur.
Multi-serveur#
Faites tourner des copies d’une même app sur plusieurs de vos serveurs d’applications. Hostwolf fait le build de l’image une seule fois, démarre une copie sur chaque serveur et répartit la charge entre elles.
await hw.applications.addServer(app.uuid, otherServer.server_uuid!);
await hw.deployAndWait(app.uuid);
console.log(await hw.applications.destinations(app.uuid)); // primary + copies
removeDestination(appUuid, destinationUuid) arrête de nouveau la copie sur ce serveur.
Bases de données managées#
PostgreSQL, MySQL/MariaDB et Redis sur des serveurs de bases de données Hostwolf, séparés de vos serveurs d’applications, avec TLS, sauvegardes nocturnes hors site et restauration à un instant donné pour PostgreSQL.
const plans = await hw.databases.catalog(); // engines, plans, pool sizes, regions, prices
const db = await hw.databases.create({ engine: 'postgres', plan: 'small', region: 'vultr:ams' });
await hw.databases.waitUntilReady(db.uuid);
await hw.databases.attach(db.uuid, app.uuid); // DATABASE_URL (pooled) + DATABASE_DIRECT_URL
await hw.deployAndWait(app.uuid);
Une base de données est facturée à l’heure sur votre abonnement serveur dès sa création. create envoie une Idempotency-Key, si bien qu’un appel relancé ne crée jamais de seconde base ; passez la vôtre avec { idempotencyKey }.
connection(uuid) renvoie deux URL. url passe par le pooler de connexions (PgBouncer sur le port 6432, ProxySQL sur le 6033) : utilisez-la dans votre app. direct_url atteint directement la base de données : utilisez-la pour les migrations, LISTEN/NOTIFY, les réglages de session et les transactions longues. Redis n’a qu’une URL.
| Méthode | Ce que fait l’appel |
|---|---|
databases.list() / get(uuid) | Vos bases de données avec moteur, offre, région, état, prix, limites, upgrades et advice |
databases.connection(uuid) | Les URL poolée et directe avec le mot de passe (le jeton doit avoir read:sensitive) |
databases.attach(uuid, appUuid, { envKey, overwrite }) | Enregistrer l’URL poolée sous DATABASE_URL et l’URL directe sous DATABASE_DIRECT_URL (Redis : REDIS_URL). Si l’application les a déjà avec une autre valeur, l’appel lève conflict avec error.conflicts et error.suggestedEnvKey ; passez envKey ou overwrite: true |
databases.upgrade(uuid, plan, { confirm: true }) | Passer à une offre supérieure parmi upgrades ; l’URL reste la même |
databases.setEvictionPolicy(uuid, policy) | Redis : allkeys-lru pour un cache, noeviction pour des files d’attente (appliqué à chaud) |
databases.backup(uuid) | Lancer une sauvegarde supplémentaire maintenant |
databases.delete(uuid) | La supprimer et arrêter la facturation ; le support peut la restaurer pendant 7 jours |
upgrade sans { confirm: true } ne change rien : il lève une HostwolfAppsError avec le code confirm_required, et error.quote contient le nouveau prix mensuel à afficher d’abord.
Mise à l’échelle automatique#
const { policy, blocker, status } = await hw.autoscaling.get(app.uuid);
await hw.autoscaling.enable(app.uuid, { min_copies: 1, max_copies: 4, monthly_cap_usd: 40 });
La mise à l’échelle automatique ajoute des serveurs d’applications près de vos visiteurs quand le CPU reste élevé, et les retire quand il baisse. Les serveurs ajoutés sont facturés à l’heure au prix normal, jusqu’à monthly_cap_usd. blocker indique pourquoi elle ne peut pas encore être activée (par exemple, aucun abonnement serveur actif). Les champs que vous omettez gardent leur valeur ; disable(uuid) la désactive. cities liste les identifiants de région qu’accepte allowed_cities pour l’app, avec le prix horaire à cet endroit ; servers.regions() liste toutes les villes.
Volumes de stockage#
Du stockage en bloc pour vos serveurs d’applications et VPS : de 10 à 1000 Go, monté sur /mnt/volume-<id> sur le serveur, facturé à l’heure. Les appels qui augmentent la facture nécessitent { confirm: true } ; sans cela, ils ne changent rien et lèvent le code confirm_required avec le prix dans error.quote.
const offer = await hw.volumes.offer(server.uuid, { sizeGb: 50 }); // sizes allowed here and the price
const volume = await hw.volumes.create(server.uuid, { size_gb: 50, autogrow_max_gb: 200 }, { confirm: true });
await hw.volumes.waitFor(volume.id); // mounted in about a minute
await hw.volumes.resize(server.uuid, volume.id, 100, { confirm: true });
| Méthode | Ce que fait l’appel |
|---|---|
volumes.list(serverUuid) / listAll({ status }) / get(id) | Les volumes d’un serveur, ou tous les volumes de l’équipe (status: 'detached' pour les volumes détachés) |
volumes.offer(serverUuid, { sizeGb }) | Si la ville du serveur propose des volumes, les tailles et un prix |
volumes.create(serverUuid, { size_gb, backups, autogrow_max_gb }, { confirm }) | Ajouter un volume (sauvegardes activées par défaut) |
volumes.resize / setBackups / setAutogrow / update | Agrandir (jamais réduire), activer ou désactiver les sauvegardes, régler la limite de croissance automatique |
volumes.detach(serverUuid, id) | Le démonter et le détacher ; il conserve ses fichiers et reste facturé |
volumes.attach(id, serverUuid, { confirm }) | Rattacher un volume détaché à un serveur de la même ville |
volumes.backups(id) / backupNow(serverUuid, id) | Les sauvegardes restaurables, ou en lancer une maintenant |
volumes.restore(serverUuid, id, backupId, 'same' | 'new', { confirm }) | Restaurer dans le volume lui-même ou dans un nouveau |
volumes.restoreDetached(id, backupId, serverUuid, { confirm }) | Restaurer la sauvegarde d’un volume détaché dans un nouveau volume |
volumes.delete(id, { confirm: true }) | Le supprimer avec ses fichiers |
Quand un serveur est supprimé, ses volumes sont détachés et conservés gratuitement pendant 7 jours (kept_until) ; rattachez-en un à un autre serveur de la même ville d’ici là, sinon il est supprimé.
Volumes d’app#
| Méthode | Ce que fait l’appel |
|---|---|
applications.storages(uuid) | Volumes persistants et fichiers montés |
applications.createStorage(uuid, { type: 'persistent', name, mount_path }) | Ajouter un volume (redéployez pour le monter) |
applications.updateStorage / deleteStorage | En modifier ou en supprimer une |
applications.setVolumeBackup(uuid, storageUuid, { frequency: 'daily' }) | Sauvegarder un volume selon un planning |
applications.runVolumeBackup / deleteVolumeBackup | Sauvegarder maintenant, ou supprimer le planning |
Équipes#
| Méthode | Ce que fait l’appel |
|---|---|
teams.current() / members() | L’équipe du jeton et ses membres |
teams.update({ name }) | Renommer l’équipe |
teams.auditEvents({ page }) / allAuditEvents() | Le journal d’audit de l’équipe (administrateurs et propriétaires) |
Pagination#
Les listes paginées par l’API sont proposées de deux façons : un appel renvoie une seule page, et une méthode all… renvoie un itérateur asynchrone sur tous les éléments. collect transforme un itérateur en tableau :
import { collect } from '@hostwolf/apps-sdk';
const deployments = await collect(hw.deployments.allForApplication(app.uuid), 100);
for await (const event of hw.teams.allAuditEvents({ action: 'deploy' })) console.log(event.description);
Erreurs#
Les appels qui échouent lèvent une HostwolfAppsError.
import { HostwolfAppsError } from '@hostwolf/apps-sdk';
try {
await hw.applications.createFromDockerfile({ project_uuid, server_uuid, dockerfile });
} catch (e) {
if (e instanceof HostwolfAppsError && e.isValidation) console.log(e.errors); // { field: ['message'] }
else throw e;
}
Elle possède ces propriétés :
status: le statut HTTP, ou 0 pour les erreurs réseau, les délais dépassés et les déploiements échoués.code: un code court commevalidation_failed,unauthenticated,forbidden,not_found,rate_limited,confirm_required,deployment_failedoutimeout.quote: avecconfirm_required, le prix annoncé par l’API (affichez-le, puis relancez l’appel avec{ confirm: true }).retryAfter: sur une 429, le nombre de secondes avant que l’appel soit de nouveau autorisé. Les attentes courtes sont relancées pour vous ; les plus longues échouent tout de suite avec ce champ renseigné.message: une description lisible, erreurs par champ comprises.errors: les erreurs par champ d’une 422, sous la forme{ field: ['message'] }.body: le corps de la réponse. Une 403 sur une action que Hostwolf gère pour vous (comme l’ajout de serveurs) contient un liendocs.- Indicateurs raccourcis :
isNotFound,isRateLimited,isValidation,isUnauthorizedetisConfirmRequired.
Requêtes brutes#
Si un endpoint n’a pas encore de méthode dédiée, appelez-le directement :
await hw.http.get(`/applications/${uuid}/scheduled-tasks`);
await hw.http.post(`/applications/${uuid}/scheduled-tasks`, { name: 'cleanup', command: 'npm run cleanup', frequency: '0 3 * * *' });
Les chemins sont relatifs à /api/v1. Consultez la référence de l’API pour tous les endpoints.
Versions#
| Fichier | Utilisation |
|---|---|
https://app.hostwolf.net/dl/hostwolf-apps-sdk- | Une version figée. À utiliser dans package.json. |
https://app.hostwolf.net/dl/hostwolf-apps-sdk.tgz | Toujours la dernière version. Les gestionnaires de paquets mettent en cache selon l’URL ; préférez donc les URL versionnées. |
https://app.hostwolf.net/dl/index.json | Versions actuelles, avec empreintes SHA-256 et d’intégrité npm. |
Pour mettre à jour, installez l’URL versionnée la plus récente.
Licence#
MIT