feat(api): add ResolveSpec and WebSocket client implementations

- Introduced ResolveSpecClient for REST API interactions.
- Added WebSocketClient for real-time communication.
- Created types and utility functions for both clients.
- Removed deprecated types and example files.
- Configured TypeScript and Vite for building the library.
This commit is contained in:
2026-02-15 15:17:39 +02:00
parent fd77385dd6
commit dc85008d7f
30 changed files with 6140 additions and 1350 deletions

View File

@@ -0,0 +1,141 @@
import type { ClientConfig, APIResponse, TableMetadata, Options, RequestBody } from '../common/types';
const instances = new Map<string, ResolveSpecClient>();
export function getResolveSpecClient(config: ClientConfig): ResolveSpecClient {
const key = config.baseUrl;
let instance = instances.get(key);
if (!instance) {
instance = new ResolveSpecClient(config);
instances.set(key, instance);
}
return instance;
}
export class ResolveSpecClient {
private config: ClientConfig;
constructor(config: ClientConfig) {
this.config = config;
}
private buildUrl(schema: string, entity: string, id?: string): string {
let url = `${this.config.baseUrl}/${schema}/${entity}`;
if (id) {
url += `/${id}`;
}
return url;
}
private baseHeaders(): HeadersInit {
const headers: Record<string, string> = {
'Content-Type': 'application/json',
};
if (this.config.token) {
headers['Authorization'] = `Bearer ${this.config.token}`;
}
return headers;
}
private async fetchWithError<T>(url: string, options: RequestInit): Promise<APIResponse<T>> {
const response = await fetch(url, options);
const data = await response.json();
if (!response.ok) {
throw new Error(data.error?.message || 'An error occurred');
}
return data;
}
async getMetadata(schema: string, entity: string): Promise<APIResponse<TableMetadata>> {
const url = this.buildUrl(schema, entity);
return this.fetchWithError<TableMetadata>(url, {
method: 'GET',
headers: this.baseHeaders(),
});
}
async read<T = any>(
schema: string,
entity: string,
id?: number | string | string[],
options?: Options
): Promise<APIResponse<T>> {
const urlId = typeof id === 'number' || typeof id === 'string' ? String(id) : undefined;
const url = this.buildUrl(schema, entity, urlId);
const body: RequestBody = {
operation: 'read',
id: Array.isArray(id) ? id : undefined,
options,
};
return this.fetchWithError<T>(url, {
method: 'POST',
headers: this.baseHeaders(),
body: JSON.stringify(body),
});
}
async create<T = any>(
schema: string,
entity: string,
data: any | any[],
options?: Options
): Promise<APIResponse<T>> {
const url = this.buildUrl(schema, entity);
const body: RequestBody = {
operation: 'create',
data,
options,
};
return this.fetchWithError<T>(url, {
method: 'POST',
headers: this.baseHeaders(),
body: JSON.stringify(body),
});
}
async update<T = any>(
schema: string,
entity: string,
data: any | any[],
id?: number | string | string[],
options?: Options
): Promise<APIResponse<T>> {
const urlId = typeof id === 'number' || typeof id === 'string' ? String(id) : undefined;
const url = this.buildUrl(schema, entity, urlId);
const body: RequestBody = {
operation: 'update',
id: Array.isArray(id) ? id : undefined,
data,
options,
};
return this.fetchWithError<T>(url, {
method: 'POST',
headers: this.baseHeaders(),
body: JSON.stringify(body),
});
}
async delete(
schema: string,
entity: string,
id: number | string
): Promise<APIResponse<void>> {
const url = this.buildUrl(schema, entity, String(id));
const body: RequestBody = {
operation: 'delete',
};
return this.fetchWithError<void>(url, {
method: 'POST',
headers: this.baseHeaders(),
body: JSON.stringify(body),
});
}
}

View File

@@ -0,0 +1 @@
export { ResolveSpecClient, getResolveSpecClient } from './client';