-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathpaystack-client.ts
More file actions
101 lines (85 loc) · 3.06 KB
/
paystack-client.ts
File metadata and controls
101 lines (85 loc) · 3.06 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
import { PaystackResponse, PaystackError } from "./types";
import { createPaystackConfig } from "./config";
const PAYSTACK_BASE_URL = 'https://api.paystack.co';
const USER_AGENT = process.env.USER_AGENT || 'Paystack-MCP-Server/0.0.1';
export class PaystackClient {
private baseUrl: string;
private secretKey: string;
private userAgent: string;
private timeout: number;
constructor(
secretKey: string,
baseUrl: string = PAYSTACK_BASE_URL,
userAgent: string = USER_AGENT,
timeout: number = 30000
) {
if (!secretKey) {
throw new Error("Paystack secret key is required");
}
this.secretKey = secretKey;
this.baseUrl = baseUrl;
this.userAgent = userAgent;
this.timeout = timeout;
}
/**
* Make an HTTP request to Paystack API
* @param method - HTTP method (GET, POST, PUT, DELETE, etc.)
* @param endpoint - API endpoint path
* @param data - Request body for POST/PUT/PATCH or query params for GET
*/
async makeRequest<T>(
method: string,
endpoint: string,
data?: any
): Promise<PaystackResponse<T>> {
let url = `${this.baseUrl}${endpoint}`;
const headers: Record<string, string> = {
'Authorization': `Bearer ${this.secretKey}`,
'User-Agent': this.userAgent,
'Accept': 'application/json',
};
const options: RequestInit = {
method: method.toUpperCase()
};
// Add Content-Type and body for requests with data
if (data && ['POST', 'PUT', 'DELETE', 'PATCH'].includes(method.toUpperCase())) {
headers['Content-Type'] = 'application/json';
options.body = JSON.stringify(data);
}
options.headers = headers;
try {
const response = await fetch(url, options);
// Parse response
const responseText = await response.text();
let responseData: PaystackResponse<T> | PaystackError;
try {
responseData = JSON.parse(responseText);
} catch (parseError) {
// Handle non-JSON responses gracefully (e.g., HTML error pages from API gateways)
const responseSnippet = responseText.length > 200
? responseText.substring(0, 200) + '...'
: responseText;
const errorMessage = `Received non-JSON response from server (HTTP ${response.status}): ${responseSnippet}`;
const nonJsonError = new Error(errorMessage);
(nonJsonError as any).statusCode = response.status;
(nonJsonError as any).responseText = responseText;
throw nonJsonError;
}
return responseData as PaystackResponse<T>;
} catch (error) {
if (error !== null && (error as any).name === 'NetworkError') {
const timeoutError = new Error(`Request timeout after ${this.timeout} ms`);
(timeoutError as any).statusCode = 408;
throw timeoutError;
}
throw error;
}
}
}
/**
* Create a PaystackClient instance with configuration
*/
export function createPaystackClient(cliApiKey?: string): PaystackClient {
const config = createPaystackConfig(cliApiKey);
return new PaystackClient(config.secretKey, config.baseURL, undefined, config.timeout);
}