This commit is contained in:
Juergen Kunz
2025-07-29 14:22:52 +00:00
parent b9317484bf
commit 3144c9edbf
2 changed files with 38 additions and 5 deletions

View File

@@ -162,8 +162,6 @@ tap.test('should create and download PDF statement', async () => {
});
tap.test('should create CSV statement with custom date range', async () => {
// Wait to avoid rate limiting
await new Promise(resolve => setTimeout(resolve, 3500));
console.log('Creating CSV statement export...');
// Use last month's date range to ensure it's in the past
@@ -200,8 +198,6 @@ tap.test('should create CSV statement with custom date range', async () => {
});
tap.test('should create MT940 statement', async () => {
// Wait to avoid rate limiting
await new Promise(resolve => setTimeout(resolve, 3500));
console.log('Creating MT940 statement export...');
const exportBuilder = primaryAccount.getAccountStatement({

View File

@@ -24,9 +24,46 @@ export class BunqHttpClient {
}
/**
* Make an API request to bunq
* Make an API request to bunq with automatic retry on rate limit
*/
public async request<T = any>(options: IBunqRequestOptions): Promise<T> {
const maxRetries = 3;
let lastError: Error;
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
return await this.makeRequest<T>(options);
} catch (error) {
lastError = error as Error;
// Check if it's a rate limit error
if (error instanceof BunqApiError) {
const isRateLimitError = error.errors.some(e =>
e.error_description.includes('Too many requests') ||
e.error_description.includes('rate limit')
);
if (isRateLimitError && attempt < maxRetries) {
// Exponential backoff: 1s, 2s, 4s
const backoffMs = Math.pow(2, attempt) * 1000;
console.log(`Rate limit hit, backing off for ${backoffMs}ms (attempt ${attempt + 1}/${maxRetries + 1})`);
await new Promise(resolve => setTimeout(resolve, backoffMs));
continue;
}
}
// For non-rate-limit errors or if we've exhausted retries, throw immediately
throw error;
}
}
throw lastError!;
}
/**
* Internal method to make the actual request
*/
private async makeRequest<T = any>(options: IBunqRequestOptions): Promise<T> {
let url = `${this.context.baseUrl}${options.endpoint}`;
// Prepare headers