update
This commit is contained in:
209
ts/classes/apiclient.ts
Normal file
209
ts/classes/apiclient.ts
Normal file
@@ -0,0 +1,209 @@
|
||||
/**
|
||||
* API Client for communicating with Onebox daemon
|
||||
*
|
||||
* Provides methods for CLI commands to interact with running daemon via HTTP API
|
||||
*/
|
||||
|
||||
import type {
|
||||
IService,
|
||||
IRegistry,
|
||||
IDnsRecord,
|
||||
ISslCertificate,
|
||||
IServiceDeployOptions,
|
||||
} from '../types.ts';
|
||||
|
||||
export class OneboxApiClient {
|
||||
private baseUrl: string;
|
||||
private token?: string;
|
||||
|
||||
constructor(port = 3000) {
|
||||
this.baseUrl = `http://localhost:${port}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if daemon is reachable
|
||||
*/
|
||||
async isReachable(): Promise<boolean> {
|
||||
try {
|
||||
const response = await fetch(`${this.baseUrl}/api/status`, {
|
||||
signal: AbortSignal.timeout(5000), // 5 second timeout
|
||||
});
|
||||
return response.ok;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// ============ Service Operations ============
|
||||
|
||||
async deployService(config: IServiceDeployOptions): Promise<IService> {
|
||||
return await this.request<IService>('POST', '/api/services', config);
|
||||
}
|
||||
|
||||
async removeService(name: string): Promise<void> {
|
||||
await this.request('DELETE', `/api/services/${name}`);
|
||||
}
|
||||
|
||||
async startService(name: string): Promise<void> {
|
||||
await this.request('POST', `/api/services/${name}/start`);
|
||||
}
|
||||
|
||||
async stopService(name: string): Promise<void> {
|
||||
await this.request('POST', `/api/services/${name}/stop`);
|
||||
}
|
||||
|
||||
async restartService(name: string): Promise<void> {
|
||||
await this.request('POST', `/api/services/${name}/restart`);
|
||||
}
|
||||
|
||||
async listServices(): Promise<IService[]> {
|
||||
return await this.request<IService[]>('GET', '/api/services');
|
||||
}
|
||||
|
||||
async getServiceLogs(name: string, limit = 1000): Promise<string[]> {
|
||||
const result = await this.request<{ logs: string[] }>(
|
||||
'GET',
|
||||
`/api/services/${name}/logs?limit=${limit}`
|
||||
);
|
||||
return result.logs;
|
||||
}
|
||||
|
||||
// ============ Registry Operations ============
|
||||
|
||||
async addRegistry(url: string, username: string, password: string): Promise<void> {
|
||||
await this.request('POST', '/api/registries', { url, username, password });
|
||||
}
|
||||
|
||||
async removeRegistry(url: string): Promise<void> {
|
||||
await this.request('DELETE', `/api/registries/${encodeURIComponent(url)}`);
|
||||
}
|
||||
|
||||
async listRegistries(): Promise<IRegistry[]> {
|
||||
return await this.request<IRegistry[]>('GET', '/api/registries');
|
||||
}
|
||||
|
||||
// ============ DNS Operations ============
|
||||
|
||||
async addDnsRecord(domain: string): Promise<void> {
|
||||
await this.request('POST', '/api/dns', { domain });
|
||||
}
|
||||
|
||||
async removeDnsRecord(domain: string): Promise<void> {
|
||||
await this.request('DELETE', `/api/dns/${domain}`);
|
||||
}
|
||||
|
||||
async listDnsRecords(): Promise<IDnsRecord[]> {
|
||||
return await this.request<IDnsRecord[]>('GET', '/api/dns');
|
||||
}
|
||||
|
||||
async syncDns(): Promise<void> {
|
||||
await this.request('POST', '/api/dns/sync');
|
||||
}
|
||||
|
||||
// ============ SSL Operations ============
|
||||
|
||||
async renewCertificate(domain?: string): Promise<void> {
|
||||
const path = domain ? `/api/ssl/renew/${domain}` : '/api/ssl/renew';
|
||||
await this.request('POST', path);
|
||||
}
|
||||
|
||||
async listCertificates(): Promise<ISslCertificate[]> {
|
||||
return await this.request<ISslCertificate[]>('GET', '/api/ssl');
|
||||
}
|
||||
|
||||
async forceRenewCertificate(domain: string): Promise<void> {
|
||||
await this.request('POST', `/api/ssl/renew/${domain}?force=true`);
|
||||
}
|
||||
|
||||
// ============ Nginx Operations ============
|
||||
|
||||
async reloadNginx(): Promise<void> {
|
||||
await this.request('POST', '/api/nginx/reload');
|
||||
}
|
||||
|
||||
async testNginx(): Promise<{ success: boolean; output: string }> {
|
||||
return await this.request('POST', '/api/nginx/test');
|
||||
}
|
||||
|
||||
async getNginxStatus(): Promise<{ status: string }> {
|
||||
return await this.request('GET', '/api/nginx/status');
|
||||
}
|
||||
|
||||
// ============ Config Operations ============
|
||||
|
||||
async getSettings(): Promise<Record<string, string>> {
|
||||
return await this.request<Record<string, string>>('GET', '/api/config');
|
||||
}
|
||||
|
||||
async setSetting(key: string, value: string): Promise<void> {
|
||||
await this.request('POST', '/api/config', { key, value });
|
||||
}
|
||||
|
||||
// ============ System Operations ============
|
||||
|
||||
async getStatus(): Promise<{
|
||||
services: { total: number; running: number; stopped: number };
|
||||
uptime: number;
|
||||
}> {
|
||||
return await this.request('GET', '/api/status');
|
||||
}
|
||||
|
||||
// ============ Helper Methods ============
|
||||
|
||||
/**
|
||||
* Make HTTP request to daemon
|
||||
*/
|
||||
private async request<T = unknown>(
|
||||
method: string,
|
||||
path: string,
|
||||
body?: unknown
|
||||
): Promise<T> {
|
||||
const url = `${this.baseUrl}${path}`;
|
||||
|
||||
const headers: Record<string, string> = {
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
|
||||
if (this.token) {
|
||||
headers['Authorization'] = `Bearer ${this.token}`;
|
||||
}
|
||||
|
||||
const options: RequestInit = {
|
||||
method,
|
||||
headers,
|
||||
signal: AbortSignal.timeout(30000), // 30 second timeout
|
||||
};
|
||||
|
||||
if (body) {
|
||||
options.body = JSON.stringify(body);
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(url, options);
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({ message: response.statusText }));
|
||||
throw new Error(errorData.message || `HTTP ${response.status}: ${response.statusText}`);
|
||||
}
|
||||
|
||||
// For DELETE and some POST requests, there might be no content
|
||||
if (response.status === 204 || response.headers.get('content-length') === '0') {
|
||||
return undefined as T;
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
if (error.name === 'TimeoutError') {
|
||||
throw new Error('Request timed out. Daemon might be unresponsive.');
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set authentication token
|
||||
*/
|
||||
setToken(token: string): void {
|
||||
this.token = token;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user