import type {
DroydConfig,
AgentChatRequest,
AgentChatResponse,
SearchRequest,
SearchResponse,
ProjectSearchRequest,
ProjectSearchResponse,
ProjectFilterRequest,
ProjectFilterResponse,
WatchlistRequest,
WatchlistResponse,
OpenTradeRequest,
OpenTradeResponse,
ManageTradeRequest,
ManageTradeResponse,
PositionsResponse,
LegStatus,
} from './types.js';
const DEFAULT_BASE_URL = 'https://api.droyd.ai';
export class DroydApiError extends Error {
constructor(
message: string,
public statusCode: number,
public details?: unknown
) {
super(message);
this.name = 'DroydApiError';
}
}
export class DroydClient {
private apiKey: string;
private baseUrl: string;
constructor(config: DroydConfig) {
this.apiKey = config.apiKey;
this.baseUrl = config.baseUrl || DEFAULT_BASE_URL;
}
// ---------------------------------------------------------------------------
// Private Helpers
// ---------------------------------------------------------------------------
private getHeaders(): Record<string, string> {
return {
'Content-Type': 'application/json',
'x-droyd-api-key': this.apiKey,
};
}
private async request<T>(
method: 'GET' | 'POST',
endpoint: string,
body?: unknown
): Promise<T> {
const url = `${this.baseUrl}${endpoint}`;
const options: RequestInit = {
method,
headers: this.getHeaders(),
};
if (body && method === 'POST') {
options.body = JSON.stringify(body);
}
const response = await fetch(url, options);
const data = (await response.json()) as Record<string, unknown>;
if (!response.ok) {
throw new DroydApiError(
(data.error as string) || `HTTP ${response.status}`,
response.status,
data.details
);
}
if (data.success === false) {
throw new DroydApiError(
(data.error as string) || 'Unknown error',
response.status,
data
);
}
return data as T;
}
// ---------------------------------------------------------------------------
// Agent Chat Endpoint
// ---------------------------------------------------------------------------
/**
* Chat with a DROYD AI agent (multi-turn conversations supported)
*/
async chat(
request: AgentChatRequest,
stream = false
): Promise<{ success: boolean; data: AgentChatResponse }> {
const endpoint = stream
? '/api/v1/agent/chat?stream=true'
: '/api/v1/agent/chat';
return this.request('POST', endpoint, request);
}
// ---------------------------------------------------------------------------
// Search Endpoint
// ---------------------------------------------------------------------------
/**
* Search the DROYD knowledge base for crypto content
*/
async searchContent(request: SearchRequest): Promise<{ success: boolean } & SearchResponse> {
return this.request('POST', '/api/v1/search', request);
}
// ---------------------------------------------------------------------------
// Project Endpoints
// ---------------------------------------------------------------------------
/**
* Search for crypto projects by name, symbol, address, or semantic query
*/
async searchProjects(request: ProjectSearchRequest): Promise<{ success: boolean; error: null } & ProjectSearchResponse> {
return this.request('POST', '/api/v1/projects/search', request);
}
/**
* Filter and screen projects using market filters
*/
async filterProjects(request: ProjectFilterRequest): Promise<{ success: boolean; error: null } & ProjectFilterResponse> {
return this.request('POST', '/api/v1/projects/filter', request);
}
/**
* Get watchlist projects for the authenticated user
*/
async getWatchlist(request: WatchlistRequest = {}): Promise<{ success: boolean; error: null } & WatchlistResponse> {
return this.request('POST', '/api/v1/projects/watchlist', request);
}
// ---------------------------------------------------------------------------
// Trading Endpoints
// ---------------------------------------------------------------------------
/**
* Open a new trading position with flexible leg configurations
*/
async openTrade(request: OpenTradeRequest): Promise<{ success: boolean; error: null } & OpenTradeResponse> {
return this.request('POST', '/api/v1/trade/open', request);
}
/**
* Manage existing trading positions (close, buy, sell, update)
*/
async manageTrade(request: ManageTradeRequest): Promise<{ success: boolean; error: null; data: ManageTradeResponse }> {
return this.request('POST', '/api/v1/trade/manage', request);
}
/**
* Get active trading positions and wallet holdings
*/
async getPositions(legStatus: LegStatus = 'active'): Promise<{ success: boolean; error: null; data: PositionsResponse }> {
return this.request('GET', `/api/v1/trade/positions?leg_status=${legStatus}`);
}
}
// Factory function for creating client from environment
export function createClientFromEnv(): DroydClient {
const apiKey = process.env.DROYD_API_KEY;
if (!apiKey) {
throw new Error('DROYD_API_KEY environment variable is required');
}
return new DroydClient({
apiKey,
baseUrl: process.env.DROYD_BASE_URL,
});
}