Files
RedditBot/src/mcp/api-client.ts
T

76 lines
2.2 KiB
TypeScript

export interface RedditBotApiClientOptions {
baseUrl?: string;
token?: string;
fetchImplementation?: typeof fetch;
}
export class RedditBotApiError extends Error {
constructor(message: string, readonly status: number) {
super(message);
this.name = 'RedditBotApiError';
}
}
export class RedditBotApiClient {
private readonly baseUrl: string;
private readonly token: string;
private readonly fetchImplementation: typeof fetch;
constructor(options: RedditBotApiClientOptions = {}) {
this.baseUrl = (options.baseUrl ?? process.env.REDDIT_BOT_API_URL ?? 'http://127.0.0.1:3000').replace(/\/$/, '');
this.token = options.token
?? process.env.REDDIT_BOT_AGENT_TOKEN
?? process.env.REDDIT_BOT_AGENT_CONTROL_TOKEN
?? process.env.REDDIT_BOT_AGENT_READ_TOKEN
?? process.env.WEB_DASHBOARD_TOKEN
?? '';
this.fetchImplementation = options.fetchImplementation ?? fetch;
if (!this.token) {
throw new Error('MCP server requires REDDIT_BOT_AGENT_TOKEN or WEB_DASHBOARD_TOKEN');
}
new URL(this.baseUrl);
}
get(path: string): Promise<unknown> {
return this.request(path);
}
post(path: string, body?: unknown): Promise<unknown> {
return this.request(path, {
method: 'POST',
...(body === undefined ? {} : {
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
}),
});
}
private async request(path: string, init: RequestInit = {}): Promise<unknown> {
const response = await this.fetchImplementation(`${this.baseUrl}${path}`, {
...init,
headers: {
Authorization: `Bearer ${this.token}`,
Accept: 'application/json',
...init.headers,
},
});
const text = await response.text();
let payload: unknown = null;
if (text) {
try {
payload = JSON.parse(text) as unknown;
} catch {
payload = text;
}
}
if (!response.ok) {
const message = typeof payload === 'object' && payload !== null && 'error' in payload
&& typeof payload.error === 'string'
? payload.error
: `RedditBot API request failed (${response.status})`;
throw new RedditBotApiError(message, response.status);
}
return payload;
}
}