feat(api): integrate openapi-fetch for Hetzner and Hostinger services, enhancing API interaction and simplifying data fetching

This commit is contained in:
Mauricio Siu
2025-07-23 01:21:11 -06:00
parent 6758ef1542
commit f3dc480b70
10 changed files with 36799 additions and 258 deletions

View File

@@ -28,6 +28,7 @@
"typecheck": "tsc --noEmit"
},
"dependencies": {
"openapi-fetch": "0.14.0",
"@ai-sdk/anthropic": "^1.2.12",
"@ai-sdk/azure": "^1.3.23",
"@ai-sdk/cohere": "^1.2.10",

View File

@@ -1,118 +1,49 @@
import createClient from "openapi-fetch";
import type { paths } from "../types/hetzner-types";
const HETZNER_API_URL = "https://api.hetzner.cloud/v1";
interface HetznerLocation {
id: number;
name: string;
description: string;
country: string;
city: string;
latitude: number;
longitude: number;
network_zone: string;
}
const hetznerApiKey = process.env.HETZNER_API_KEY;
interface HetznerServerType {
id: number;
name: string;
description: string;
cores: number;
memory: number;
disk: number;
prices: {
location: string;
price_hourly: {
net: string;
gross: string;
};
price_monthly: {
net: string;
gross: string;
};
}[];
storage_type: string;
cpu_type: string;
architecture: string;
}
const client = createClient<paths>({ baseUrl: HETZNER_API_URL });
interface HetznerServer {
id: number;
name: string;
status: string;
created: string;
server_type: {
id: number;
name: string;
description: string;
cores: number;
memory: number;
disk: number;
};
public_net: {
ipv4: {
ip: string;
};
ipv6: {
ip: string;
};
};
}
export const fetchHetznerLocations = async (
apiKey: string,
): Promise<HetznerLocation[]> => {
const response = await fetch(`${HETZNER_API_URL}/locations`, {
export const fetchHetznerLocations = async () => {
const { data, error } = await client.GET("/locations", {
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
Authorization: `Bearer ${hetznerApiKey}`,
},
});
if (!response.ok) {
throw new Error(
`Failed to fetch Hetzner locations: ${response.statusText}`,
);
if (error) {
throw new Error(`Failed to fetch Hetzner locations: ${error}`);
}
const data = (await response.json()) as { locations?: HetznerLocation[] };
return data.locations || [];
return data;
};
export const fetchHetznerServerTypes = async (
apiKey: string,
): Promise<HetznerServerType[]> => {
const response = await fetch(`${HETZNER_API_URL}/server_types`, {
export const fetchHetznerServerTypes = async () => {
const { data, error } = await client.GET("/server_types", {
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
Authorization: `Bearer ${hetznerApiKey}`,
},
});
if (!response.ok) {
throw new Error(
`Failed to fetch Hetzner server types: ${response.statusText}`,
);
if (error) {
throw new Error(`Failed to fetch Hetzner server types: ${error}`);
}
const data = (await response.json()) as {
server_types?: HetznerServerType[];
};
return data.server_types || [];
return data;
};
export const fetchHetznerServers = async (
apiKey: string,
): Promise<HetznerServer[]> => {
const response = await fetch(`${HETZNER_API_URL}/servers`, {
export const fetchHetznerServers = async () => {
const { data, error } = await client.GET("/servers", {
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
Authorization: `Bearer ${hetznerApiKey}`,
},
});
if (!response.ok) {
throw new Error(`Failed to fetch Hetzner servers: ${response.statusText}`);
if (error) {
throw new Error(`Failed to fetch Hetzner servers: ${error}`);
}
const data = (await response.json()) as { servers?: HetznerServer[] };
return data.servers || [];
return data;
};

View File

@@ -1,113 +1,35 @@
import createClient from "openapi-fetch";
import type { paths } from "../types/hostinger-types";
const HOSTINGER_API_URL = "https://developers.hostinger.com";
const hostingerApiKey = process.env.HOSTINGER_API_KEY;
interface HostingerCatalogItem {
id: string;
name: string;
category: string;
prices: Array<{
id: string;
name: string;
currency: string;
price: number; // en centavos
first_period_price: number; // precio promocional en centavos
period: number;
period_unit: string;
}>;
metadata: {
cpus: string;
memory: string;
bandwidth: string;
disk_space: string;
network: string;
};
}
const client = createClient<paths>({ baseUrl: HOSTINGER_API_URL });
interface HostingerServer {
id: string;
name: string;
status: string;
created_at: string;
ip_address: string;
plan: {
name: string;
cpu: number;
ram: number;
storage: number;
};
location: string;
}
interface HostingerDataCenter {
id: number;
name: string;
location: string;
country: string;
}
// Obtener catalog items (productos VPS con precios reales)
export const fetchHostingerCatalog = async (
apiKey: string,
): Promise<HostingerCatalogItem[]> => {
const response = await fetch(
`${HOSTINGER_API_URL}/api/billing/v1/catalog?category=VPS`,
{
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
},
},
);
if (!response.ok) {
throw new Error(
`Failed to fetch Hostinger catalog: ${response.statusText}`,
);
}
const data = (await response.json()) as HostingerCatalogItem[];
return data || [];
};
// Obtener VPS existentes
export const fetchHostingerServers = async (
apiKey: string,
): Promise<HostingerServer[]> => {
const response = await fetch(
`${HOSTINGER_API_URL}/api/vps/v1/virtual-machines`,
{
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
},
},
);
if (!response.ok) {
// Si no hay servidores o falla, retornamos array vacío
return [];
}
const data = (await response.json()) as { data?: HostingerServer[] };
return data.data || [];
};
// Obtener data centers disponibles
export async function fetchHostingerDataCenters(
apiKey: string,
): Promise<HostingerDataCenter[]> {
const response = await fetch(`${HOSTINGER_API_URL}/api/vps/v1/data-centers`, {
export const fetchHostingerCatalog = async () => {
const { data, error } = await client.GET("/api/billing/v1/catalog", {
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
Authorization: `Bearer ${hostingerApiKey}`,
},
});
if (!response.ok) {
throw new Error(
`Failed to fetch Hostinger data centers: ${response.statusText}`,
);
if (error) {
throw new Error(`Failed to fetch Hostinger catalog: ${error}`);
}
const data = (await response.json()) as { data?: HostingerDataCenter[] };
return data.data || [];
}
return data;
};
export const fetchHostingerDataCenters = async () => {
const { data, error } = await client.GET("/api/vps/v1/data-centers", {
headers: {
Authorization: `Bearer ${hostingerApiKey}`,
},
});
if (error) {
throw new Error(`Failed to fetch Hostinger data centers: ${error}`);
}
return data;
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff