76 lines
2.2 KiB
TypeScript
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;
|
|
}
|
|
}
|