import { PerformanceObserver } from "node:perf_hooks";
export class SlowFrameDetector {
    _count = 0;
    _duration = 0;
    _threshold;
    _interval;
    constructor(threshold = 200) {
        this._threshold = threshold;
    }
    start() {
        if (this._interval) {
            throw new Error("already started");
        }
        let lastFrame = Date.now();
        this._interval = setInterval(() => {
            const now = Date.now();
            const diff = now - lastFrame;
            if (diff > this._threshold) {
                this._count++;
                this._duration += diff;
            }
            lastFrame = now;
        }, 10);
    }
    stop() {
        if (!this._interval) {
            throw new Error("not started");
        }
        clearInterval(this._interval);
        this._interval = undefined;
    }
    result() {
        return {
            count: this._count,
            duration: this._duration,
        };
    }
}
// all the logic to measure and report back
export class Audit {
    _jsBootTime;
    _startTime;
    _startUsage;
    _startMemory;
    _slowFrameDetector;
    _networkAudit;
    constructor() {
        const jsBootTime = Date.now() - parseInt(process.env.START_TIME || "0", 10);
        this._jsBootTime = jsBootTime;
        this._startTime = process.hrtime();
        this._startUsage = process.cpuUsage();
        this._startMemory = process.memoryUsage();
        this._slowFrameDetector = new SlowFrameDetector();
        this._slowFrameDetector.start();
        this._networkAudit = new NetworkAudit();
        this._networkAudit.start();
    }
    _totalTime;
    _cpuUserTime;
    _cpuSystemTime;
    _endMemory;
    end() {
        const endTime = process.hrtime(this._startTime);
        const endUsage = process.cpuUsage(this._startUsage);
        const endMemory = process.memoryUsage();
        this._totalTime = (endTime[0] * 1e9 + endTime[1]) / 1e6; // ms
        this._cpuUserTime = endUsage.user / 1e3; // ms
        this._cpuSystemTime = endUsage.system / 1e3; // ms
        this._endMemory = endMemory;
        this._slowFrameDetector.stop();
        this._networkAudit.stop();
    }
    _accountsJSONSize;
    setAccountsJSONSize(size) {
        this._accountsJSONSize = size;
    }
    _preloadJSONSize;
    setPreloadJSONSize(size) {
        this._preloadJSONSize = size;
    }
    result() {
        if (!this._totalTime) {
            throw new Error("audit not ended");
        }
        return {
            jsBootTime: this._jsBootTime,
            cpuUserTime: this._cpuUserTime,
            cpuSystemTime: this._cpuSystemTime,
            totalTime: this._totalTime,
            memoryEnd: this._endMemory,
            memoryStart: this._startMemory,
            accountsJSONSize: this._accountsJSONSize,
            preloadJSONSize: this._preloadJSONSize,
            network: this._networkAudit.result(),
            slowFrames: this._slowFrameDetector.result(),
        };
    }
}
export class NetworkAudit {
    _obs;
    _totalTime = 0;
    _totalCount = 0;
    _totalResponseSize = 0;
    _totalDuplicateRequests = 0;
    _urlsSeen = new Set();
    start() {
        this._obs = new PerformanceObserver(this.onPerformanceEntry);
        this._obs.observe({ type: "http" });
    }
    stop() {
        if (this._obs) {
            this._obs.disconnect();
            this._obs = undefined;
        }
    }
    onPerformanceEntry = (items, _observer) => {
        const entries = items.getEntries();
        for (const entry of entries) {
            if (entry.entryType === "http") {
                this._totalCount = (this._totalCount || 0) + 1;
                if (entry.duration) {
                    this._totalTime = (this._totalTime || 0) + entry.duration;
                }
                const req = entry.detail?.req;
                const res = entry.detail?.res;
                if (res && req) {
                    const { url } = req;
                    if (this._urlsSeen.has(url)) {
                        this._totalDuplicateRequests = (this._totalDuplicateRequests || 0) + 1;
                    }
                    else {
                        this._urlsSeen.add(url);
                    }
                    const { headers } = res;
                    if (headers) {
                        const contentLength = headers["content-length"];
                        if (contentLength) {
                            this._totalResponseSize = (this._totalResponseSize || 0) + parseInt(contentLength);
                        }
                    }
                }
            }
        }
    };
    result() {
        return {
            totalTime: this._totalTime,
            totalCount: this._totalCount,
            totalResponseSize: this._totalResponseSize,
            totalDuplicateRequests: this._totalDuplicateRequests,
        };
    }
}
//# sourceMappingURL=audits.js.map