mirror of
https://github.com/tale/headplane.git
synced 2026-08-26 04:16:49 +00:00
feat: switch machine apis to new runtime api client
This commit is contained in:
@@ -2,7 +2,7 @@ import { readFile } from 'node:fs/promises';
|
||||
import { data } from 'react-router';
|
||||
import { Agent, Dispatcher, errors, request } from 'undici';
|
||||
import log from '~/utils/log';
|
||||
import ResponseError from './api/error';
|
||||
import ResponseError from './api/response-error';
|
||||
|
||||
function isNodeNetworkError(error: unknown): error is NodeJS.ErrnoException {
|
||||
const keys = Object.keys(error as Record<string, unknown>);
|
||||
@@ -144,6 +144,9 @@ export async function createApiClient(base: string, certPath?: string) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use the new RuntimeApiClient instead.
|
||||
*/
|
||||
export class ApiClient {
|
||||
private agent: Agent;
|
||||
private base: string;
|
||||
@@ -153,7 +156,7 @@ export class ApiClient {
|
||||
this.base = base;
|
||||
}
|
||||
|
||||
private async defaultFetch(
|
||||
async defaultFetch(
|
||||
url: string,
|
||||
options?: Partial<Dispatcher.RequestOptions>,
|
||||
) {
|
||||
@@ -178,6 +181,9 @@ export class ApiClient {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use the new RuntimeApiClient instead.
|
||||
*/
|
||||
async healthcheck() {
|
||||
try {
|
||||
const res = await request(new URL('/health', this.base), {
|
||||
@@ -195,6 +201,9 @@ export class ApiClient {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use the new RuntimeApiClient instead.
|
||||
*/
|
||||
async get<T = unknown>(url: string, key: string) {
|
||||
const res = await this.defaultFetch(`/api/${url}`, {
|
||||
headers: {
|
||||
@@ -204,12 +213,19 @@ export class ApiClient {
|
||||
|
||||
if (res.statusCode >= 400) {
|
||||
log.debug('api', 'GET %s failed with status %d', url, res.statusCode);
|
||||
throw new ResponseError(res.statusCode, await res.body.text());
|
||||
throw new ResponseError(
|
||||
res.statusCode,
|
||||
await res.body.text(),
|
||||
`GET ${url}`,
|
||||
);
|
||||
}
|
||||
|
||||
return res.body.json() as Promise<T>;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use the new RuntimeApiClient instead.
|
||||
*/
|
||||
async post<T = unknown>(url: string, key: string, body?: unknown) {
|
||||
const res = await this.defaultFetch(`/api/${url}`, {
|
||||
method: 'POST',
|
||||
@@ -221,12 +237,19 @@ export class ApiClient {
|
||||
|
||||
if (res.statusCode >= 400) {
|
||||
log.debug('api', 'POST %s failed with status %d', url, res.statusCode);
|
||||
throw new ResponseError(res.statusCode, await res.body.text());
|
||||
throw new ResponseError(
|
||||
res.statusCode,
|
||||
await res.body.text(),
|
||||
`POST ${url}`,
|
||||
);
|
||||
}
|
||||
|
||||
return res.body.json() as Promise<T>;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use the new RuntimeApiClient instead.
|
||||
*/
|
||||
async put<T = unknown>(url: string, key: string, body?: unknown) {
|
||||
const res = await this.defaultFetch(`/api/${url}`, {
|
||||
method: 'PUT',
|
||||
@@ -238,12 +261,19 @@ export class ApiClient {
|
||||
|
||||
if (res.statusCode >= 400) {
|
||||
log.debug('api', 'PUT %s failed with status %d', url, res.statusCode);
|
||||
throw new ResponseError(res.statusCode, await res.body.text());
|
||||
throw new ResponseError(
|
||||
res.statusCode,
|
||||
await res.body.text(),
|
||||
`PUT ${url}`,
|
||||
);
|
||||
}
|
||||
|
||||
return res.body.json() as Promise<T>;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use the new RuntimeApiClient instead.
|
||||
*/
|
||||
async delete<T = unknown>(url: string, key: string) {
|
||||
const res = await this.defaultFetch(`/api/${url}`, {
|
||||
method: 'DELETE',
|
||||
@@ -254,7 +284,11 @@ export class ApiClient {
|
||||
|
||||
if (res.statusCode >= 400) {
|
||||
log.debug('api', 'DELETE %s failed with status %d', url, res.statusCode);
|
||||
throw new ResponseError(res.statusCode, await res.body.text());
|
||||
throw new ResponseError(
|
||||
res.statusCode,
|
||||
await res.body.text(),
|
||||
`DELETE ${url}`,
|
||||
);
|
||||
}
|
||||
|
||||
return res.body.json() as Promise<T>;
|
||||
|
||||
@@ -1,26 +1,6 @@
|
||||
import { data } from 'react-router';
|
||||
import { errors } from 'undici';
|
||||
|
||||
// Represents an error that occurred during a response
|
||||
// Thrown when status codes are >= 400
|
||||
export default class ResponseError extends Error {
|
||||
status: number;
|
||||
response: string;
|
||||
responseObject?: Record<string, unknown>;
|
||||
|
||||
constructor(status: number, response: string, requestUrl: string) {
|
||||
super(`${requestUrl}: status ${status} - ${response}`);
|
||||
this.name = 'ResponseError';
|
||||
this.status = status;
|
||||
this.response = response;
|
||||
|
||||
try {
|
||||
// Try to parse the response as JSON to get a response object
|
||||
this.responseObject = JSON.parse(response);
|
||||
} catch {}
|
||||
}
|
||||
}
|
||||
|
||||
function isNodeNetworkError(error: unknown): error is NodeJS.ErrnoException {
|
||||
if (typeof error !== 'object' || error === null) {
|
||||
return false;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { HeadscaleApiInterface } from '../api';
|
||||
import type { HeadscaleApiInterface } from '../api';
|
||||
|
||||
/**
|
||||
* Creates a strongly-typed group factory for a given endpoint interface.
|
||||
|
||||
@@ -3,14 +3,12 @@ import { readFile } from 'node:fs/promises';
|
||||
import { dereference } from '@readme/openapi-parser';
|
||||
import type { OpenAPIV2 } from 'openapi-types';
|
||||
import { Agent, type Dispatcher, request } from 'undici';
|
||||
import type { Key, Machine, PreAuthKey, User } from '~/types';
|
||||
import log from '~/utils/log';
|
||||
import endpointSets, { RuntimeApiClient } from './endpoints';
|
||||
import ResponseError, { friendlyError } from './error';
|
||||
import { friendlyError } from './error';
|
||||
import ResponseError from './response-error';
|
||||
import { detectApiVersion, isAtLeast, type Version } from './version';
|
||||
|
||||
export type RuntimeApiClient2 = {};
|
||||
|
||||
/**
|
||||
* A low-level composed interface for interacting with the Headscale API.
|
||||
* This interface provides direct access to the underlying Undici agent
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
// Represents an error that occurred during a response
|
||||
// Thrown when status codes are >= 400
|
||||
export default class ResponseError extends Error {
|
||||
status: number;
|
||||
response: string;
|
||||
responseObject?: Record<string, unknown>;
|
||||
|
||||
constructor(status: number, response: string, requestUrl: string) {
|
||||
super(`${requestUrl}: status ${status} - ${response}`);
|
||||
this.name = 'ResponseError';
|
||||
this.status = status;
|
||||
this.response = response;
|
||||
|
||||
try {
|
||||
// Try to parse the response as JSON to get a response object
|
||||
this.responseObject = JSON.parse(response);
|
||||
} catch {}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user