n8n-nodes-sevdesk-v2
Version:
n8n community node for SevDesk API v2 integration with 24 production-ready workflow templates. Direct API access without external dependencies - simplified, secure, and optimized for German accounting automation (n8n 1.101.1 compatible).
99 lines (98 loc) • 3.38 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.sevDeskRateLimiter = exports.RateLimiter = void 0;
exports.withRateLimit = withRateLimit;
class RateLimiter {
constructor(config = {}) {
this.requests = [];
this.lastRequestTime = 0;
this.config = {
maxRequests: 100,
windowMs: 60 * 1000,
minDelay: 100,
maxRetries: 3,
baseRetryDelay: 1000,
...config,
};
}
async waitForSlot() {
const now = Date.now();
this.cleanOldRequests(now);
const timeSinceLastRequest = now - this.lastRequestTime;
if (timeSinceLastRequest < this.config.minDelay) {
const delayNeeded = this.config.minDelay - timeSinceLastRequest;
await this.delay(delayNeeded);
}
if (this.requests.length >= this.config.maxRequests) {
const oldestRequest = this.requests[0];
const waitTime = (oldestRequest.timestamp + this.config.windowMs) - Date.now();
if (waitTime > 0) {
await this.delay(waitTime);
this.cleanOldRequests(Date.now());
}
}
this.requests.push({
timestamp: Date.now(),
retryCount: 0,
});
this.lastRequestTime = Date.now();
}
calculateRetryDelay(retryCount, retryAfter) {
if (retryAfter) {
return retryAfter * 1000;
}
const exponentialDelay = this.config.baseRetryDelay * Math.pow(2, retryCount);
const jitter = Math.random() * 1000;
return Math.min(exponentialDelay + jitter, 30000);
}
shouldRetry(retryCount) {
return retryCount < this.config.maxRetries;
}
getStatus() {
const now = Date.now();
this.cleanOldRequests(now);
let nextAvailableSlot = now;
const timeSinceLastRequest = now - this.lastRequestTime;
if (timeSinceLastRequest < this.config.minDelay) {
nextAvailableSlot = Math.max(nextAvailableSlot, this.lastRequestTime + this.config.minDelay);
}
if (this.requests.length >= this.config.maxRequests) {
const oldestRequest = this.requests[0];
nextAvailableSlot = Math.max(nextAvailableSlot, oldestRequest.timestamp + this.config.windowMs);
}
return {
requestsInWindow: this.requests.length,
maxRequests: this.config.maxRequests,
windowMs: this.config.windowMs,
nextAvailableSlot,
};
}
reset() {
this.requests = [];
this.lastRequestTime = 0;
}
updateConfig(newConfig) {
this.config = { ...this.config, ...newConfig };
}
cleanOldRequests(now) {
const cutoff = now - this.config.windowMs;
this.requests = this.requests.filter(req => req.timestamp > cutoff);
}
delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
}
exports.RateLimiter = RateLimiter;
exports.sevDeskRateLimiter = new RateLimiter({
maxRequests: 100,
windowMs: 60 * 1000,
minDelay: 100,
maxRetries: 3,
baseRetryDelay: 1000,
});
function withRateLimit(fn, rateLimiter = exports.sevDeskRateLimiter) {
return (async (...args) => {
await rateLimiter.waitForSlot();
return fn(...args);
});
}