Compare commits

..

18 Commits

Author SHA1 Message Date
philkunz 4c327e5e32 1.0.14 2024-02-18 23:25:57 +01:00
philkunz a898928bd3 fix(core): update 2024-02-18 23:25:57 +01:00
philkunz aba8182422 1.0.13 2024-02-18 23:23:21 +01:00
philkunz 5412ab524b fix(core): update 2024-02-18 23:23:20 +01:00
philkunz 2f175e9d64 1.0.12 2024-02-18 01:17:15 +01:00
philkunz d2b1018234 fix(core): update 2024-02-18 01:17:15 +01:00
philkunz e7babf5222 1.0.11 2024-02-17 21:59:11 +01:00
philkunz 63660ecc03 fix(core): update 2024-02-17 21:59:10 +01:00
philkunz 336e27f383 1.0.10 2024-02-17 21:58:11 +01:00
philkunz 9174571ea4 fix(core): update 2024-02-17 21:58:10 +01:00
philkunz 4a722b79b7 1.0.9 2024-02-17 21:55:53 +01:00
philkunz 866dc35403 fix(core): update 2024-02-17 21:55:52 +01:00
philkunz 84d74a131a 1.0.8 2024-02-17 21:55:26 +01:00
philkunz 929404fadd fix(core): update 2024-02-17 21:55:25 +01:00
philkunz 332a4a4195 1.0.7 2024-02-17 20:41:22 +01:00
philkunz 07d625fa1f fix(core): update 2024-02-17 20:41:21 +01:00
philkunz e7cafd9c1c 1.0.6 2024-01-29 21:17:14 +01:00
philkunz 60725ecdcb fix(core): update 2024-01-29 21:17:14 +01:00
12 changed files with 169 additions and 35 deletions
+4 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@apiclient.xyz/hetznercloud", "name": "@apiclient.xyz/hetznercloud",
"version": "1.0.5", "version": "1.0.14",
"private": false, "private": false,
"description": "an unofficial api client for the hetzner cloud api", "description": "an unofficial api client for the hetzner cloud api",
"main": "dist_ts/index.js", "main": "dist_ts/index.js",
@@ -19,12 +19,14 @@
"@git.zone/tsbundle": "^2.0.5", "@git.zone/tsbundle": "^2.0.5",
"@git.zone/tsrun": "^1.2.46", "@git.zone/tsrun": "^1.2.46",
"@git.zone/tstest": "^1.0.44", "@git.zone/tstest": "^1.0.44",
"@push.rocks/qenv": "^6.0.5",
"@push.rocks/tapbundle": "^5.0.15", "@push.rocks/tapbundle": "^5.0.15",
"@types/node": "^20.8.7" "@types/node": "^20.8.7"
}, },
"dependencies": { "dependencies": {
"@push.rocks/smartrequest": "^2.0.21", "@push.rocks/smartrequest": "^2.0.21",
"@tempfix/hetzner-openapi": "^1.0.4" "@tempfix/hetzner-openapi": "^1.0.4",
"@tsclass/tsclass": "^4.0.52"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
+30 -10
View File
@@ -11,6 +11,9 @@ dependencies:
'@tempfix/hetzner-openapi': '@tempfix/hetzner-openapi':
specifier: ^1.0.4 specifier: ^1.0.4
version: 1.0.4 version: 1.0.4
'@tsclass/tsclass':
specifier: ^4.0.52
version: 4.0.52
devDependencies: devDependencies:
'@git.zone/tsbuild': '@git.zone/tsbuild':
@@ -25,6 +28,9 @@ devDependencies:
'@git.zone/tstest': '@git.zone/tstest':
specifier: ^1.0.44 specifier: ^1.0.44
version: 1.0.86(@types/node@20.11.10)(sinon@17.0.1) version: 1.0.86(@types/node@20.11.10)(sinon@17.0.1)
'@push.rocks/qenv':
specifier: ^6.0.5
version: 6.0.5
'@push.rocks/tapbundle': '@push.rocks/tapbundle':
specifier: ^5.0.15 specifier: ^5.0.15
version: 5.0.15(sinon@17.0.1) version: 5.0.15(sinon@17.0.1)
@@ -74,7 +80,7 @@ packages:
'@push.rocks/smartstream': 3.0.30 '@push.rocks/smartstream': 3.0.30
'@push.rocks/smarttime': 4.0.6 '@push.rocks/smarttime': 4.0.6
'@push.rocks/webstore': 2.0.13 '@push.rocks/webstore': 2.0.13
'@tsclass/tsclass': 4.0.46 '@tsclass/tsclass': 4.0.52
'@types/express': 4.17.21 '@types/express': 4.17.21
body-parser: 1.20.2 body-parser: 1.20.2
cors: 2.8.5 cors: 2.8.5
@@ -134,6 +140,12 @@ packages:
js-tokens: 4.0.0 js-tokens: 4.0.0
dev: true dev: true
/@configvault.io/interfaces@1.0.17:
resolution: {integrity: sha512-bEcCUR2VBDJsTin8HQh8Uw/mlYl2v8A3jMIaQ+MTB9Hrqd6CZL2dL7iJdWyFl/3EIX+LDxWFR+Oq7liIq7w+1Q==}
dependencies:
'@api.global/typedrequest-interfaces': 3.0.1
dev: true
/@cspotcode/source-map-support@0.8.1: /@cspotcode/source-map-support@0.8.1:
resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
engines: {node: '>=12'} engines: {node: '>=12'}
@@ -596,6 +608,16 @@ packages:
symbol-tree: 3.2.4 symbol-tree: 3.2.4
dev: true dev: true
/@push.rocks/qenv@6.0.5:
resolution: {integrity: sha512-Id/eSKKqSDUGe+0Cp5HEJ58J1iVv1jQseLUMs9kFTPYwG+NJSETUCRsJV50w5cPv8bRFcSkSU+xVbUbOc1p29A==}
dependencies:
'@api.global/typedrequest': 3.0.4
'@configvault.io/interfaces': 1.0.17
'@push.rocks/smartfile': 11.0.4
'@push.rocks/smartlog': 3.0.3
'@push.rocks/smartpath': 5.0.11
dev: true
/@push.rocks/smartbrowser@2.0.6: /@push.rocks/smartbrowser@2.0.6:
resolution: {integrity: sha512-Ne+KCVhV/DROc1rHRRw59K6h0+LpQAK9fdOUtgDZ7laLPmB/tmnbUh3IuRDNcIY1iVA9pydoobwjnTjVgio9eQ==} resolution: {integrity: sha512-Ne+KCVhV/DROc1rHRRw59K6h0+LpQAK9fdOUtgDZ7laLPmB/tmnbUh3IuRDNcIY1iVA9pydoobwjnTjVgio9eQ==}
dependencies: dependencies:
@@ -817,7 +839,7 @@ packages:
'@push.rocks/smartpromise': 4.0.3 '@push.rocks/smartpromise': 4.0.3
'@push.rocks/smartpuppeteer': 2.0.2 '@push.rocks/smartpuppeteer': 2.0.2
'@push.rocks/smartunique': 3.0.6 '@push.rocks/smartunique': 3.0.6
'@tsclass/tsclass': 4.0.46 '@tsclass/tsclass': 4.0.52
'@types/express': 4.17.21 '@types/express': 4.17.21
express: 4.18.2 express: 4.18.2
pdf-merger-js: 3.4.0 pdf-merger-js: 3.4.0
@@ -880,7 +902,7 @@ packages:
'@push.rocks/smartxml': 1.0.8 '@push.rocks/smartxml': 1.0.8
'@push.rocks/smartyaml': 2.0.5 '@push.rocks/smartyaml': 2.0.5
'@push.rocks/webrequest': 3.0.34 '@push.rocks/webrequest': 3.0.34
'@tsclass/tsclass': 4.0.46 '@tsclass/tsclass': 4.0.52
dev: true dev: true
/@push.rocks/smartsocket@2.0.24: /@push.rocks/smartsocket@2.0.24:
@@ -1321,11 +1343,10 @@ packages:
type-fest: 2.19.0 type-fest: 2.19.0
dev: true dev: true
/@tsclass/tsclass@4.0.46: /@tsclass/tsclass@4.0.52:
resolution: {integrity: sha512-UovPUvlozv1ftJp4KW5tt4MP/LQCNP3lSCinjyIrLkopOymczyzONUGvSAAwOBf1XBE9bO0tI4KtRuXWN9XBXQ==} resolution: {integrity: sha512-yjASmfnDvgWA1OKYXbz4diLIrPBSk5BpPStKuVkAhrhN8Xw4lc6/oSiJpsosEd8GDwr/FPsY2lgN8/5674vM0w==}
dependencies: dependencies:
type-fest: 4.10.1 type-fest: 4.10.2
dev: true
/@tsconfig/node10@1.0.9: /@tsconfig/node10@1.0.9:
resolution: {integrity: sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==} resolution: {integrity: sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==}
@@ -5232,10 +5253,9 @@ packages:
engines: {node: '>=12.20'} engines: {node: '>=12.20'}
dev: true dev: true
/type-fest@4.10.1: /type-fest@4.10.2:
resolution: {integrity: sha512-7ZnJYTp6uc04uYRISWtiX3DSKB/fxNQT0B5o1OUeCqiQiwF+JC9+rJiZIDrPrNCLLuTqyQmh4VdQqh/ZOkv9MQ==} resolution: {integrity: sha512-anpAG63wSpdEbLwOqH8L84urkL6PiVIov3EMmgIhhThevh9aiMQov+6Btx0wldNcvm4wV+e2/Rt1QdDwKHFbHw==}
engines: {node: '>=16'} engines: {node: '>=16'}
dev: true
/type-is@1.6.18: /type-is@1.6.18:
resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==}
+2
View File
@@ -0,0 +1,2 @@
required:
- 'HETZNER_API_TOKEN'
+2 -1
View File
@@ -26,9 +26,10 @@ BundlePhobia (total size when bundled) | [![BundlePhobia](https://badgen.net/bun
A modern approach to talking to the hetzner API. A modern approach to talking to the hetzner API.
```typescript ```typescript
// assuming top level await here
import hetznerCloud from '@apiclient.xyz/hetznercloud' import hetznerCloud from '@apiclient.xyz/hetznercloud'
const myhetznerAccount = new hetznerCloud.HetznerAccount('myToken'); const myhetznerAccount = new hetznerCloud.HetznerAccount('myToken');
const servers = myhetznerAccount.getServers(); const servers = await myhetznerAccount.getServers();
for (const server of servers) { for (const server of servers) {
await server.delete(); await server.delete();
} }
+39 -5
View File
@@ -1,8 +1,42 @@
import { expect, expectAsync, tap } from '@push.rocks/tapbundle'; import { expect, expectAsync, tap } from '@push.rocks/tapbundle';
import * as hetznercloud from '../ts/index.js' import * as hetznercloud from '../ts/index.js';
import * as qenv from '@push.rocks/qenv';
const testQenv = new qenv.Qenv('./', './.nogit/');
tap.test('first test', async () => { let testAccount: hetznercloud.HetznerAccount;
console.log(hetznercloud)
})
tap.start() tap.test('should create a valid hetzer account', async () => {
testAccount = new hetznercloud.HetznerAccount(
await testQenv.getEnvVarOnDemand('HETZNER_API_TOKEN')
);
expect(testAccount).toBeInstanceOf(hetznercloud.HetznerAccount);
});
tap.test('should be able to list all servers', async () => {
const servers = await testAccount.getServers();
expect(servers).toBeArray();
console.log(JSON.stringify(servers, null, 2));
});
const testserver = tap.test('should be able to create a server', async (toolsArg) => {
const newServer = await testAccount.createServer({
name: 'testserver',
location: 'nbg1',
type: 'cpx41',
labels: {
servezoneId: 'testzone',
},
});
expect(newServer).toBeInstanceOf(hetznercloud.HetznerServer);
console.log(newServer);
await toolsArg.delayFor(10000);
return newServer;
});
tap.test('should be able to delete a server', async () => {
const testServer: hetznercloud.HetznerServer =
await (testserver.testResultPromise as Promise<hetznercloud.HetznerServer>);
// await testServer.delete();
});
tap.start();
+1 -1
View File
@@ -3,6 +3,6 @@
*/ */
export const commitinfo = { export const commitinfo = {
name: '@apiclient.xyz/hetznercloud', name: '@apiclient.xyz/hetznercloud',
version: '1.0.5', version: '1.0.14',
description: 'an unofficial api client for the hetzner cloud api' description: 'an unofficial api client for the hetzner cloud api'
} }
+14
View File
@@ -11,6 +11,14 @@ export class HetznerAccount {
return HetznerServer.getServers(this); return HetznerServer.getServers(this);
} }
public async getServerByLabel(labelArg: string, valueArg?: string) {
return HetznerServer.getServerByLabel(this, labelArg, valueArg);
}
public async createServer(optionsArg: plugins.tsclass.typeFestOwn.SecondArgument<typeof HetznerServer.create>) {
return HetznerServer.create(this, optionsArg);
}
/** /**
* request things from the hetzner API * request things from the hetzner API
* @param methodArg * @param methodArg
@@ -19,13 +27,19 @@ export class HetznerAccount {
*/ */
public request = async (methodArg: string, pathArg: string, payloadArg: any) => { public request = async (methodArg: string, pathArg: string, payloadArg: any) => {
const url = `https://api.hetzner.cloud/v1${pathArg}`; const url = `https://api.hetzner.cloud/v1${pathArg}`;
console.log(`Url: ${url}`);
console.log(`Method: ${methodArg}`);
console.log(`Payload: ${JSON.stringify(payloadArg, null, 2)}`);
const response = await plugins.smartrequest.request(url, { const response = await plugins.smartrequest.request(url, {
method: methodArg, method: methodArg,
headers: { headers: {
Authorization: `Bearer ${this.token}`, Authorization: `Bearer ${this.token}`,
}, },
requestBody: payloadArg, requestBody: payloadArg,
keepAlive: false,
}); });
console.log(response.statusCode);
console.log(response.body);
return response; return response;
} }
} }
View File
+34 -12
View File
@@ -4,24 +4,37 @@ import * as types from './types.js';
export class HetznerServer { export class HetznerServer {
// STATIC // STATIC
public static async create(hetznerAccountRefArg: HetznerAccount, optionsArg: { public static async create(
name: string, hetznerAccountRefArg: HetznerAccount,
datacenter: 'nbg1-dc3', optionsArg: {
}) { name: string;
type: types.THetznerCloudServerName;
location: types.THetznerCloudLocationName;
labels?: {[key: string]: string},
userData?: string,
}
) {
const server = new HetznerServer(hetznerAccountRefArg); const server = new HetznerServer(hetznerAccountRefArg);
const createServerUrl = '/servers'; const createServerUrl = '/servers';
const createServerPayload: types.TServerCreateRequestBody = const createServerPayload: types.TServerCreateRequestBody = {
{
name: optionsArg.name, name: optionsArg.name,
datacenter: optionsArg.datacenter, image: 'ubuntu-22.04',
image: '', server_type: optionsArg.type,
server_type: '',
start_after_create: true, start_after_create: true,
user_data: '', labels: optionsArg.labels || {} as any,
location: optionsArg.location,
user_data: optionsArg.userData || '',
public_net: {
enable_ipv4: true,
enable_ipv6: true,
},
}; };
const response = await server.hetznerAccountRef.request(
const response = await server.hetznerAccountRef.request('POST', createServerUrl, createServerPayload); 'POST',
createServerUrl,
createServerPayload
);
server.data = (response.body as types.TServerCreateResponseBody).server; server.data = (response.body as types.TServerCreateResponseBody).server;
return server; return server;
} }
@@ -39,6 +52,15 @@ export class HetznerServer {
return servers; return servers;
} }
public static async getServerByLabel(hetznerAccountRefArg: HetznerAccount, labelArg: string, valueArg?: string) {
const servers = await HetznerServer.getServers(hetznerAccountRefArg);
for (const server of servers) {
if (valueArg ? server.data.labels[labelArg] === valueArg : server.data.labels[labelArg]) {
return server;
}
}
}
// INSTANCE // INSTANCE
public hetznerAccountRef: HetznerAccount; public hetznerAccountRef: HetznerAccount;
public data: types.IServer; public data: types.IServer;
+7
View File
@@ -10,3 +10,10 @@ import * as smartrequest from '@push.rocks/smartrequest';
export { export {
smartrequest, smartrequest,
} }
// @tsclass scope
import * as tsclass from '@tsclass/tsclass';
export {
tsclass,
}
+2
View File
@@ -0,0 +1,2 @@
export * from './classes.account.js';
export * from './classes.server.js';
+30
View File
@@ -10,3 +10,33 @@ export type TServersGetResponseBody = plugins.hetznerOpenapi.paths['/servers']['
export type TServerCreateRequestBody = plugins.hetznerOpenapi.paths['/servers']['post']['requestBody']['content']['application/json']; export type TServerCreateRequestBody = plugins.hetznerOpenapi.paths['/servers']['post']['requestBody']['content']['application/json'];
export type TServerCreateResponseBody = plugins.hetznerOpenapi.paths['/servers']['post']['responses']['201']['content']['application/json']; export type TServerCreateResponseBody = plugins.hetznerOpenapi.paths['/servers']['post']['responses']['201']['content']['application/json'];
// server types
export type THetznerCloudServerName =
| 'cx11'
| 'cx21'
| 'cx31'
| 'cx41'
| 'cx51'
| 'ccx11'
| 'ccx21'
| 'ccx31'
| 'ccx41'
| 'ccx51'
| 'ccx13'
| 'ccx23'
| 'ccx33'
| 'ccx43'
| 'ccx53'
| 'ccx63'
| 'cpx11'
| 'cpx21'
| 'cpx31'
| 'cpx41'
| 'cpx51'
| 'cpx61'
| 'cpx70'
| 'cpx71'
| 'cpx90';
// location types
export type THetznerCloudLocationName = 'fsn1' | 'nbg1' | 'hel1' | 'ash' | 'hil';