/**
 * RenewalManager — coordinates capability-token auto-renewal.
 *
 * Triggers a re-issue when ≥80% of the token lifetime has elapsed.
 * Debounced: a renewal in flight blocks duplicate triggers; once it
 * resolves, the gate is rotated and the timer is reset.
 *
 * The manager is loop-agnostic: any caller (minimal-loop, sdk-loop, or
 * a long-running background job) can `await maybeRenew()` between tool
 * calls. The decision is purely time-based; no per-call cost reset.
 */
export class RenewalManager {
    gate;
    reissue;
    thresholdFraction;
    now;
    inFlight = null;
    constructor(opts) {
        this.gate = opts.gate;
        this.reissue = opts.reissue;
        this.thresholdFraction = opts.thresholdFraction ?? 0.8;
        if (this.thresholdFraction <= 0 || this.thresholdFraction >= 1) {
            throw new RangeError("thresholdFraction must be in (0, 1)");
        }
        this.now = opts.now ?? (() => Date.now() / 1000);
    }
    /**
     * Trigger renewal if the current token is past the threshold. Idempotent
     * across concurrent callers via the in-flight promise.
     */
    async maybeRenew() {
        if (this.inFlight) {
            await this.inFlight;
            return true;
        }
        const expiresAt = this.gate.getExpiresAt?.();
        const issuedAt = this.gate.getIssuedAt?.();
        if (expiresAt === undefined || issuedAt === undefined)
            return false;
        const lifetime = expiresAt - issuedAt;
        if (lifetime <= 0)
            return false;
        const elapsed = this.now() - issuedAt;
        if (elapsed / lifetime < this.thresholdFraction)
            return false;
        const promise = (async () => {
            const renewed = await this.reissue({
                issuedAtEpochSeconds: issuedAt,
                expiresAtEpochSeconds: expiresAt,
            });
            this.gate.rotateToken?.(renewed.token, renewed.expiresAtEpochSeconds);
        })();
        this.inFlight = promise.finally(() => {
            this.inFlight = null;
        });
        await this.inFlight;
        return true;
    }
}
//# sourceMappingURL=renewal-manager.js.map