Files
Sankofa/portal/src/lib/crossplane-client.ts
defiQUG 9daf1fd378 Apply Composer changes: comprehensive API updates, migrations, middleware, and infrastructure improvements
- Add comprehensive database migrations (001-024) for schema evolution
- Enhance API schema with expanded type definitions and resolvers
- Add new middleware: audit logging, rate limiting, MFA enforcement, security, tenant auth
- Implement new services: AI optimization, billing, blockchain, compliance, marketplace
- Add adapter layer for cloud integrations (Cloudflare, Kubernetes, Proxmox, storage)
- Update Crossplane provider with enhanced VM management capabilities
- Add comprehensive test suite for API endpoints and services
- Update frontend components with improved GraphQL subscriptions and real-time updates
- Enhance security configurations and headers (CSP, CORS, etc.)
- Update documentation and configuration files
- Add new CI/CD workflows and validation scripts
- Implement design system improvements and UI enhancements
2025-12-12 18:01:35 -08:00

169 lines
4.3 KiB
TypeScript

import axios, { AxiosInstance, AxiosError } from 'axios';
const crossplaneAPI = process.env.NEXT_PUBLIC_CROSSPLANE_API || 'http://localhost:8080';
// Error types
export class CrossplaneError extends Error {
constructor(
message: string,
public statusCode?: number,
public code?: string
) {
super(message);
this.name = 'CrossplaneError';
Object.setPrototypeOf(this, CrossplaneError.prototype);
}
}
function handleAxiosError(error: unknown): never {
if (axios.isAxiosError(error)) {
const axiosError = error as AxiosError<{ message?: string }>;
const statusCode = axiosError.response?.status;
const message = (axiosError.response?.data as { message?: string })?.message || axiosError.message || 'An error occurred';
throw new CrossplaneError(message, statusCode, axiosError.code);
}
if (error instanceof Error) {
throw new CrossplaneError(error.message);
}
throw new CrossplaneError('An unknown error occurred');
}
export interface CrossplaneClient {
getVMs(): Promise<VM[]>;
getVM(name: string): Promise<VM>;
createVM(spec: VMSpec): Promise<VM>;
updateVM(name: string, spec: Partial<VMSpec>): Promise<VM>;
deleteVM(name: string): Promise<void>;
}
export interface VM {
metadata: {
name: string;
namespace: string;
creationTimestamp: string;
};
spec: VMSpec;
status: {
vmId?: number;
state?: string;
ipAddress?: string;
conditions?: Array<{
type: string;
status: string;
reason?: string;
message?: string;
}>;
};
}
export interface VMSpec {
forProvider: {
node: string;
name: string;
cpu: number;
memory: string;
disk: string;
storage: string;
network: string;
image: string;
site: string;
userData?: string;
sshKeys?: string[];
};
providerConfigRef: {
name: string;
};
}
class CrossplaneClientImpl implements CrossplaneClient {
private client: AxiosInstance;
constructor(accessToken?: string) {
this.client = axios.create({
baseURL: crossplaneAPI,
headers: accessToken
? {
Authorization: `Bearer ${accessToken}`,
}
: {},
});
}
async getVMs(): Promise<VM[]> {
try {
const apiGroup = process.env.NEXT_PUBLIC_CROSSPLANE_API_GROUP || 'proxmox.sankofa.nexus'
const response = await this.client.get(`/apis/${apiGroup}/v1alpha1/proxmoxvms`);
return response.data.items || [];
} catch (error) {
handleAxiosError(error);
}
}
async getVM(name: string): Promise<VM> {
try {
const apiGroup = process.env.NEXT_PUBLIC_CROSSPLANE_API_GROUP || 'proxmox.sankofa.nexus'
const response = await this.client.get(
`/apis/${apiGroup}/v1alpha1/proxmoxvms/${name}`
);
return response.data;
} catch (error) {
handleAxiosError(error);
}
}
async createVM(spec: VMSpec): Promise<VM> {
try {
const apiGroup = process.env.NEXT_PUBLIC_CROSSPLANE_API_GROUP || 'proxmox.sankofa.nexus'
const response = await this.client.post(`/apis/${apiGroup}/v1alpha1/proxmoxvms`, {
apiVersion: `${apiGroup}/v1alpha1`,
kind: 'ProxmoxVM',
metadata: {
name: spec.forProvider.name,
namespace: 'default',
},
spec,
});
return response.data;
} catch (error) {
handleAxiosError(error);
}
}
async updateVM(name: string, spec: Partial<VMSpec>): Promise<VM> {
try {
const apiGroup = process.env.NEXT_PUBLIC_CROSSPLANE_API_GROUP || 'proxmox.sankofa.nexus'
const response = await this.client.patch(
`/apis/${apiGroup}/v1alpha1/proxmoxvms/${name}`,
{
spec,
},
{
headers: {
'Content-Type': 'application/merge-patch+json',
},
}
);
return response.data;
} catch (error) {
handleAxiosError(error);
}
}
async deleteVM(name: string): Promise<void> {
try {
const apiGroup = process.env.NEXT_PUBLIC_CROSSPLANE_API_GROUP || 'proxmox.sankofa.nexus'
await this.client.delete(`/apis/${apiGroup}/v1alpha1/proxmoxvms/${name}`);
} catch (error) {
handleAxiosError(error);
}
}
}
export function createCrossplaneClient(accessToken?: string): CrossplaneClient {
return new CrossplaneClientImpl(accessToken);
}