/**
 * @license
 * Copyright 2025 Vybestack LLC
 * SPDX-License-Identifier: Apache-2.0
 */
import crypto from 'node:crypto';
export class PKCESessionStore {
    sessions = new Map();
    sessionTimeoutMs;
    gcInterval = null;
    constructor(sessionTimeoutMs = 600_000) {
        const envTimeoutSeconds = process.env.LLXPRT_OAUTH_SESSION_TIMEOUT_SECONDS;
        const parsedEnvTimeoutSeconds = Number.parseInt(envTimeoutSeconds ?? '', 10);
        this.sessionTimeoutMs =
            Number.isFinite(parsedEnvTimeoutSeconds) && parsedEnvTimeoutSeconds > 0
                ? parsedEnvTimeoutSeconds * 1000
                : sessionTimeoutMs;
    }
    startGC() {
        if (this.gcInterval) {
            clearInterval(this.gcInterval);
        }
        this.gcInterval = setInterval(() => this.sweepExpired(), 60_000);
    }
    sweepExpired() {
        const now = Date.now();
        for (const [sessionId, session] of this.sessions) {
            if (now - session.createdAt > this.sessionTimeoutMs || session.used) {
                session.abortController?.abort();
                this.sessions.delete(sessionId);
            }
        }
    }
    createSession(provider, bucket, flowType, flowInstance, peerIdentity) {
        const sessionId = crypto.randomBytes(16).toString('hex');
        this.sessions.set(sessionId, {
            sessionId,
            provider,
            bucket,
            flowType,
            flowInstance,
            createdAt: Date.now(),
            peerIdentity,
            used: false,
        });
        return sessionId;
    }
    getSession(sessionId, peerIdentity) {
        const session = this.sessions.get(sessionId);
        if (!session) {
            throw new Error('SESSION_NOT_FOUND');
        }
        if (session.used) {
            throw new Error('SESSION_ALREADY_USED');
        }
        if (Date.now() - session.createdAt > this.sessionTimeoutMs) {
            session.abortController?.abort();
            this.sessions.delete(sessionId);
            throw new Error('SESSION_EXPIRED');
        }
        if (this.isUidPeerIdentity(session.peerIdentity) &&
            this.isUidPeerIdentity(peerIdentity) &&
            session.peerIdentity.uid !== peerIdentity.uid) {
            throw new Error('UNAUTHORIZED: Session peer identity mismatch');
        }
        return session;
    }
    markUsed(sessionId) {
        const session = this.sessions.get(sessionId);
        if (session) {
            session.used = true;
        }
    }
    removeSession(sessionId) {
        const session = this.sessions.get(sessionId);
        if (session?.abortController) {
            session.abortController.abort();
        }
        this.sessions.delete(sessionId);
    }
    clearAll() {
        for (const session of this.sessions.values()) {
            session.abortController?.abort();
        }
        this.sessions.clear();
        if (this.gcInterval) {
            clearInterval(this.gcInterval);
            this.gcInterval = null;
        }
    }
    isUidPeerIdentity(peerIdentity) {
        return (typeof peerIdentity === 'object' &&
            peerIdentity !== null &&
            'type' in peerIdentity &&
            'uid' in peerIdentity &&
            peerIdentity.type === 'uid' &&
            typeof peerIdentity.uid === 'number');
    }
}
//# sourceMappingURL=oauth-session-manager.js.map