import { RateLimiter } from "../../infra/rate-limit/rate-limiter.js";
import { FailureLimiter } from "../../infra/rate-limit/failure-limiter.js";
//#region src/gateway/rate-limit/buckets.ts
/**
* Named rate-limit buckets used across the gateway. Each is a thin wrapper
* over a primitive limiter ({@link RateLimiter} or {@link FailureLimiter})
* that hard-codes its config and exposes a small surface.
*
* All buckets are owned by a process-level singleton {@link BucketRegistry}
* so that:
*   - lifecycle (cleanup timers) is centralized — `destroyAll()` on shutdown,
*   - tests get one obvious reset entry point (`resetAllForTests`),
*   - new buckets are added in exactly one place.
*
* Tuning policy:
*   - `auth_failure` is read from runtime config because users tune it per
*     deployment. Other buckets keep static defaults until a real need
*     emerges to expose them. (YAGNI > premature configurability.)
*/
const DEFAULT_AUTH_RATE_LIMIT = {
	enabled: true,
	maxFailures: 5,
	windowMs: 900 * 1e3,
	blockDurationMs: 300 * 1e3,
	burstCoalesceMs: 1e3,
	exemptLoopback: true
};
function resolveAuthRateLimit(input) {
	if (!input) return { ...DEFAULT_AUTH_RATE_LIMIT };
	const blockDurationMs = input.blockDurationMs ?? input.lockoutMs ?? DEFAULT_AUTH_RATE_LIMIT.blockDurationMs;
	return {
		enabled: input.enabled ?? DEFAULT_AUTH_RATE_LIMIT.enabled,
		maxFailures: Math.max(1, Math.floor(input.maxAttempts ?? DEFAULT_AUTH_RATE_LIMIT.maxFailures)),
		windowMs: Math.max(1e3, Math.floor(input.windowMs ?? DEFAULT_AUTH_RATE_LIMIT.windowMs)),
		blockDurationMs: Math.max(1e3, Math.floor(blockDurationMs)),
		burstCoalesceMs: Math.max(0, Math.floor(input.burstCoalesceMs ?? DEFAULT_AUTH_RATE_LIMIT.burstCoalesceMs)),
		exemptLoopback: input.exemptLoopback ?? DEFAULT_AUTH_RATE_LIMIT.exemptLoopback
	};
}
function authPolicyConfig(cfg) {
	return {
		enabled: cfg.enabled,
		exemptLoopback: cfg.exemptLoopback
	};
}
var BucketRegistry = class {
	authFailureLimiter;
	authFailureSignature;
	strictApiLimiter;
	tunnelMutateLimiter;
	pairingExchangeLimiter;
	sharePublicShortLimiter;
	sharePublicLongLimiter;
	/**
	* Reconfigured on the fly when `gateway.auth.rateLimit` is reloaded —
	* compares a stable signature to avoid swapping out a hot bucket on every
	* config read.
	*/
	authFailure(cfg) {
		const sig = `${cfg.maxFailures}|${cfg.windowMs}|${cfg.blockDurationMs}|${cfg.burstCoalesceMs}`;
		if (!this.authFailureLimiter || this.authFailureSignature !== sig) {
			this.authFailureLimiter?.destroy();
			this.authFailureLimiter = new FailureLimiter({
				maxFailures: cfg.maxFailures,
				windowMs: cfg.windowMs,
				blockDurationMs: cfg.blockDurationMs,
				burstCoalesceMs: cfg.burstCoalesceMs
			});
			this.authFailureSignature = sig;
		}
		return this.authFailureLimiter;
	}
	/** Sensitive admin / mutation endpoints — 15 req / 60 s per client IP. */
	strictApi() {
		if (!this.strictApiLimiter) this.strictApiLimiter = new RateLimiter({
			maxRequests: 15,
			windowMs: 6e4
		});
		return this.strictApiLimiter;
	}
	/** Tunnel mutation calls — 12 req / 5 min per gateway-token fingerprint. */
	tunnelMutate() {
		if (!this.tunnelMutateLimiter) this.tunnelMutateLimiter = new RateLimiter({
			maxRequests: 12,
			windowMs: 5 * 6e4
		});
		return this.tunnelMutateLimiter;
	}
	/** Failed pairing-exchange attempts — 30 failures / 5 min per client IP. */
	pairingExchange() {
		if (!this.pairingExchangeLimiter) this.pairingExchangeLimiter = new FailureLimiter({
			maxFailures: 30,
			windowMs: 5 * 6e4,
			blockDurationMs: 5 * 6e4
		});
		return this.pairingExchangeLimiter;
	}
	/** Public share download short window — 60 req / min per client IP. */
	sharePublicShort() {
		if (!this.sharePublicShortLimiter) this.sharePublicShortLimiter = new RateLimiter({
			maxRequests: 60,
			windowMs: 6e4
		});
		return this.sharePublicShortLimiter;
	}
	/** Public share download long window — 300 req / 15 min per client IP. */
	sharePublicLong() {
		if (!this.sharePublicLongLimiter) this.sharePublicLongLimiter = new RateLimiter({
			maxRequests: 300,
			windowMs: 15 * 6e4
		});
		return this.sharePublicLongLimiter;
	}
	destroyAll() {
		this.authFailureLimiter?.destroy();
		this.strictApiLimiter?.destroy();
		this.tunnelMutateLimiter?.destroy();
		this.pairingExchangeLimiter?.destroy();
		this.sharePublicShortLimiter?.destroy();
		this.sharePublicLongLimiter?.destroy();
		this.authFailureLimiter = void 0;
		this.strictApiLimiter = void 0;
		this.tunnelMutateLimiter = void 0;
		this.pairingExchangeLimiter = void 0;
		this.sharePublicShortLimiter = void 0;
		this.sharePublicLongLimiter = void 0;
		this.authFailureSignature = void 0;
	}
	/** @internal */
	resetAllForTests() {
		this.authFailureLimiter?.resetForTests();
		this.strictApiLimiter?.resetForTests();
		this.tunnelMutateLimiter?.resetForTests();
		this.pairingExchangeLimiter?.resetForTests();
		this.sharePublicShortLimiter?.resetForTests();
		this.sharePublicLongLimiter?.resetForTests();
	}
};
const buckets = new BucketRegistry();
//#endregion
export { authPolicyConfig, buckets, resolveAuthRateLimit };

//# sourceMappingURL=buckets.js.map