"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.__tsfTypeAliases = exports.MeshLinkPeer = void 0;
const tslib_1 = require("tslib");
const _a = tslib_1.__importStar(require("@zyno-io/ts-server-foundation/type-metadata-runtime"));
const node_crypto_1 = require("node:crypto");
const ws_1 = tslib_1.__importDefault(require("ws"));
const helpers_1 = require("../../helpers");
const types_1 = require("../../srpc/types");
const protocol_1 = require("./protocol");
const __tsf_metadata_type = _a.createCompactMetadataRegistryV1("[1,[{\"kind\":2,\"typeName\":\"() =\\u003e void\"},{\"kind\":18,\"typeName\":\"Omit\",\"utilityType\":\"Omit\",\"typeArguments\":[{\"kind\":18,\"typeName\":\"MeshLinkFrameHeader\",\"types\":[{\"kind\":20,\"name\":\"version\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"type\",\"type\":{\"kind\":12,\"types\":[{\"kind\":10,\"literal\":\"invoke\"},{\"kind\":10,\"literal\":\"reserveStreamIds\"},{\"kind\":10,\"literal\":\"confirmStreamIds\"},{\"kind\":10,\"literal\":\"releaseStreamIds\"},{\"kind\":10,\"literal\":\"streamWrite\"},{\"kind\":10,\"literal\":\"streamFinish\"},{\"kind\":10,\"literal\":\"streamDestroy\"},{\"kind\":10,\"literal\":\"streamActivate\"},{\"kind\":10,\"literal\":\"streamAttach\"},{\"kind\":10,\"literal\":\"revokeCapability\"},{\"kind\":10,\"literal\":\"clientInvoke\"},{\"kind\":10,\"literal\":\"fenceClient\"},{\"kind\":10,\"literal\":\"clientUpdateMetadata\"},{\"kind\":10,\"literal\":\"disconnect\"},{\"kind\":10,\"literal\":\"updateMetadata\"},{\"kind\":10,\"literal\":\"accepted\"},{\"kind\":10,\"literal\":\"result\"},{\"kind\":10,\"literal\":\"ping\"},{\"kind\":10,\"literal\":\"pong\"},{\"kind\":10,\"literal\":\"goAway\"}],\"typeName\":\"MeshLinkFrameType\"},\"optional\":false},{\"kind\":20,\"name\":\"meshKey\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"id\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"replyTo\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"clientId\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"connectionId\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"prefix\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"timeoutMs\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"deadlineAt\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"streamId\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"count\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"ids\",\"type\":{\"kind\":12,\"types\":[{\"kind\":14,\"type\":{\"kind\":7}},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"capability\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"reservationId\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"ok\",\"type\":{\"kind\":12,\"types\":[{\"kind\":8},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"error\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"errorName\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"userError\",\"type\":{\"kind\":12,\"types\":[{\"kind\":8},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"reason\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"closeCapability\",\"type\":{\"kind\":12,\"types\":[{\"kind\":8},{\"kind\":4}]},\"optional\":true}]}],\"utilityKeys\":[\"version\",\"id\"],\"types\":[{\"kind\":20,\"name\":\"type\",\"type\":{\"kind\":12,\"types\":[{\"kind\":10,\"literal\":\"invoke\"},{\"kind\":10,\"literal\":\"reserveStreamIds\"},{\"kind\":10,\"literal\":\"confirmStreamIds\"},{\"kind\":10,\"literal\":\"releaseStreamIds\"},{\"kind\":10,\"literal\":\"streamWrite\"},{\"kind\":10,\"literal\":\"streamFinish\"},{\"kind\":10,\"literal\":\"streamDestroy\"},{\"kind\":10,\"literal\":\"streamActivate\"},{\"kind\":10,\"literal\":\"streamAttach\"},{\"kind\":10,\"literal\":\"revokeCapability\"},{\"kind\":10,\"literal\":\"clientInvoke\"},{\"kind\":10,\"literal\":\"fenceClient\"},{\"kind\":10,\"literal\":\"clientUpdateMetadata\"},{\"kind\":10,\"literal\":\"disconnect\"},{\"kind\":10,\"literal\":\"updateMetadata\"},{\"kind\":10,\"literal\":\"accepted\"},{\"kind\":10,\"literal\":\"result\"},{\"kind\":10,\"literal\":\"ping\"},{\"kind\":10,\"literal\":\"pong\"},{\"kind\":10,\"literal\":\"goAway\"}],\"typeName\":\"MeshLinkFrameType\"},\"optional\":false},{\"kind\":20,\"name\":\"meshKey\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"replyTo\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"clientId\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"connectionId\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"prefix\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"timeoutMs\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"deadlineAt\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"streamId\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"count\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"ids\",\"type\":{\"kind\":12,\"types\":[{\"kind\":14,\"type\":{\"kind\":7}},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"capability\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"reservationId\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"ok\",\"type\":{\"kind\":12,\"types\":[{\"kind\":8},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"error\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"errorName\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"userError\",\"type\":{\"kind\":12,\"types\":[{\"kind\":8},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"reason\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"closeCapability\",\"type\":{\"kind\":12,\"types\":[{\"kind\":8},{\"kind\":4}]},\"optional\":true}]},{\"kind\":7},{\"kind\":18,\"typeName\":\"Omit\",\"utilityType\":\"Omit\",\"typeArguments\":[{\"kind\":18,\"typeName\":\"MeshLinkFrameHeader\",\"types\":[{\"kind\":20,\"name\":\"version\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"type\",\"type\":{\"kind\":12,\"types\":[{\"kind\":10,\"literal\":\"invoke\"},{\"kind\":10,\"literal\":\"reserveStreamIds\"},{\"kind\":10,\"literal\":\"confirmStreamIds\"},{\"kind\":10,\"literal\":\"releaseStreamIds\"},{\"kind\":10,\"literal\":\"streamWrite\"},{\"kind\":10,\"literal\":\"streamFinish\"},{\"kind\":10,\"literal\":\"streamDestroy\"},{\"kind\":10,\"literal\":\"streamActivate\"},{\"kind\":10,\"literal\":\"streamAttach\"},{\"kind\":10,\"literal\":\"revokeCapability\"},{\"kind\":10,\"literal\":\"clientInvoke\"},{\"kind\":10,\"literal\":\"fenceClient\"},{\"kind\":10,\"literal\":\"clientUpdateMetadata\"},{\"kind\":10,\"literal\":\"disconnect\"},{\"kind\":10,\"literal\":\"updateMetadata\"},{\"kind\":10,\"literal\":\"accepted\"},{\"kind\":10,\"literal\":\"result\"},{\"kind\":10,\"literal\":\"ping\"},{\"kind\":10,\"literal\":\"pong\"},{\"kind\":10,\"literal\":\"goAway\"}],\"typeName\":\"MeshLinkFrameType\"},\"optional\":false},{\"kind\":20,\"name\":\"meshKey\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"id\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"replyTo\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"clientId\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"connectionId\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"prefix\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"timeoutMs\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"deadlineAt\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"streamId\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"count\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"ids\",\"type\":{\"kind\":12,\"types\":[{\"kind\":14,\"type\":{\"kind\":7}},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"capability\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"reservationId\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"ok\",\"type\":{\"kind\":12,\"types\":[{\"kind\":8},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"error\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"errorName\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"userError\",\"type\":{\"kind\":12,\"types\":[{\"kind\":8},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"reason\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"closeCapability\",\"type\":{\"kind\":12,\"types\":[{\"kind\":8},{\"kind\":4}]},\"optional\":true}]}],\"utilityKeys\":[\"version\"],\"types\":[{\"kind\":20,\"name\":\"type\",\"type\":{\"kind\":12,\"types\":[{\"kind\":10,\"literal\":\"invoke\"},{\"kind\":10,\"literal\":\"reserveStreamIds\"},{\"kind\":10,\"literal\":\"confirmStreamIds\"},{\"kind\":10,\"literal\":\"releaseStreamIds\"},{\"kind\":10,\"literal\":\"streamWrite\"},{\"kind\":10,\"literal\":\"streamFinish\"},{\"kind\":10,\"literal\":\"streamDestroy\"},{\"kind\":10,\"literal\":\"streamActivate\"},{\"kind\":10,\"literal\":\"streamAttach\"},{\"kind\":10,\"literal\":\"revokeCapability\"},{\"kind\":10,\"literal\":\"clientInvoke\"},{\"kind\":10,\"literal\":\"fenceClient\"},{\"kind\":10,\"literal\":\"clientUpdateMetadata\"},{\"kind\":10,\"literal\":\"disconnect\"},{\"kind\":10,\"literal\":\"updateMetadata\"},{\"kind\":10,\"literal\":\"accepted\"},{\"kind\":10,\"literal\":\"result\"},{\"kind\":10,\"literal\":\"ping\"},{\"kind\":10,\"literal\":\"pong\"},{\"kind\":10,\"literal\":\"goAway\"}],\"typeName\":\"MeshLinkFrameType\"},\"optional\":false},{\"kind\":20,\"name\":\"meshKey\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"id\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"replyTo\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"clientId\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"connectionId\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"prefix\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"timeoutMs\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"deadlineAt\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"streamId\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"count\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"ids\",\"type\":{\"kind\":12,\"types\":[{\"kind\":14,\"type\":{\"kind\":7}},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"capability\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"reservationId\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"ok\",\"type\":{\"kind\":12,\"types\":[{\"kind\":8},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"error\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"errorName\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"userError\",\"type\":{\"kind\":12,\"types\":[{\"kind\":8},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"reason\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"closeCapability\",\"type\":{\"kind\":12,\"types\":[{\"kind\":8},{\"kind\":4}]},\"optional\":true}]},{\"kind\":3},{\"kind\":2},{\"kind\":6},{\"kind\":2,\"typeName\":\"(peer: MeshLinkPeer, frame: MeshLinkFrame) =\\u003e Promise\\u003cMeshLinkFrame\\u003e\",\"typeName\":\"MeshLinkRequestHandler\"},{\"kind\":18,\"typeName\":\"MeshLinkIncomingBudget\",\"types\":[{\"kind\":20,\"name\":\"activeRequests\",\"type\":{\"kind\":7},\"optional\":false},{\"kind\":20,\"name\":\"activeBytes\",\"type\":{\"kind\":7},\"optional\":false}]}]]", []);
const MaxInFlightRequests = 4096;
const MaxInFlightRequestBytes = 64 * 1024 * 1024;
const MaxCompletedRequests = 4096;
const MaxCompletedRequestBytes = 64 * 1024 * 1024;
const CompletedTombstoneReserveBytes = 2 * 1024 * 1024;
const PingIntervalMs = 15000;
const PongTimeoutMs = 30000;
const CompletedRequestTtlMs = 60000;
let _MeshLinkPeerMetadata_1;
class MeshLinkPeer {
    processId;
    ws;
    maxFrameBytes;
    maxBufferedBytes;
    handler;
    endpointId;
    incomingBudget;
    publicKey;
    pending = new Map();
    closeHandlers = new Set();
    closed = false;
    closeNotified = false;
    lastActivityAt = Date.now();
    lastPongAt = Date.now();
    activeIncomingRequests = 0;
    activeIncomingBytes = 0;
    activeIncoming = new Map();
    /** Per-handler reservations that guarantee a completed-request tombstone can be retained. */
    activeIncomingTombstones = new Map();
    activeIncomingTombstoneBytes = 0;
    completedIncoming = new Map();
    completedIncomingBytes = 0;
    pingTimer;
    constructor(processId, ws, maxFrameBytes, maxBufferedBytes, handler, endpointId = processId, incomingBudget, 
    /** Verified v2 endpoint signing key (SPKI DER/base64). */
    publicKey = '') {
        this.processId = processId;
        this.ws = ws;
        this.maxFrameBytes = maxFrameBytes;
        this.maxBufferedBytes = maxBufferedBytes;
        this.handler = handler;
        this.endpointId = endpointId;
        this.incomingBudget = incomingBudget;
        this.publicKey = publicKey;
        ws.binaryType = 'nodebuffer';
        ws.on('message', data => this.handleMessage(toBuffer(data)));
        ws.on('close', () => this.handleClose());
        ws.on('error', () => this.handleClose());
        ws.on('pong', () => {
            this.lastPongAt = Date.now();
        });
        this.pingTimer = setInterval(() => this.ping(), PingIntervalMs);
        this.pingTimer.unref?.();
    }
    get connected() {
        return !this.closed && this.ws.readyState === ws_1.default.OPEN;
    }
    get idleSince() {
        return this.lastActivityAt;
    }
    get hasActiveWork() {
        return this.pending.size > 0 || this.activeIncomingRequests > 0;
    }
    onClose(handler) {
        if (this.closeNotified) {
            let active = true;
            queueMicrotask(() => {
                if (active)
                    handler();
            });
            return () => {
                active = false;
            };
        }
        this.closeHandlers.add(handler);
        return () => this.closeHandlers.delete(handler);
    }
    async request(header, body, timeoutMs) {
        (0, helpers_1.assertSafeTimerMs)(timeoutMs, 'sRPC mesh request timeout');
        if (this.pending.size >= MaxInFlightRequests)
            throw new types_1.SrpcBackpressureError('Too many in-flight sRPC mesh requests');
        const id = (0, node_crypto_1.randomUUID)();
        const clientId = header.clientId ?? 'unknown';
        return new Promise((resolve, reject) => {
            const timer = setTimeout(() => {
                const pending = this.pending.get(id);
                this.pending.delete(id);
                reject(pending?.dispatched ? new types_1.SrpcIndeterminateDeliveryError(clientId) : new Error(`sRPC mesh request timed out after ${timeoutMs}ms`));
            }, timeoutMs);
            timer.unref?.();
            const pending = { clientId, accepted: false, dispatched: false, resolve, reject, timer };
            this.pending.set(id, pending);
            try {
                this.send({ ...header, id }, body);
                pending.dispatched = true;
            }
            catch (error) {
                clearTimeout(timer);
                this.pending.delete(id);
                reject(error);
            }
        });
    }
    send(header, body = new Uint8Array()) {
        if (!this.connected)
            throw new types_1.SrpcOwnerUnavailableError(header.clientId ?? 'unknown');
        const encoded = (0, protocol_1.encodeMeshLinkFrame)(header, body, this.maxFrameBytes);
        if (this.ws.bufferedAmount + encoded.length > this.maxBufferedBytes)
            throw new types_1.SrpcBackpressureError();
        this.lastActivityAt = Date.now();
        this.ws.send(encoded);
    }
    close(code = 1000, reason = 'sRPC mesh peer closed') {
        if (this.closed)
            return;
        this.closed = true;
        if (this.ws.readyState === ws_1.default.OPEN || this.ws.readyState === ws_1.default.CONNECTING)
            this.ws.close(code, reason.slice(0, 123));
        this.handleClose();
    }
    handleMessage(data) {
        this.lastActivityAt = Date.now();
        let frame;
        try {
            frame = (0, protocol_1.decodeMeshLinkFrame)(data, this.maxFrameBytes);
        }
        catch {
            this.close(4000, 'Invalid sRPC mesh frame');
            return;
        }
        const replyTo = frame.header.replyTo;
        if (replyTo) {
            const pending = this.pending.get(replyTo);
            if (!pending)
                return;
            if (frame.header.type === 'accepted') {
                pending.accepted = true;
                return;
            }
            clearTimeout(pending.timer);
            this.pending.delete(replyTo);
            if (frame.header.ok === false) {
                const error = new Error(frame.header.error ?? 'Remote sRPC mesh operation failed');
                error.name = frame.header.errorName ?? 'Error';
                if (typeof frame.header.userError === 'boolean') {
                    error.isUserError = frame.header.userError;
                }
                pending.reject(error);
            }
            else {
                pending.resolve(frame);
            }
            return;
        }
        if (!frame.header.id) {
            this.close(4000, 'Missing sRPC mesh request ID');
            return;
        }
        const requestId = frame.header.id;
        this.pruneCompletedIncoming();
        if (this.activeIncoming.has(requestId)) {
            // The first frame owns the handler and budget. Re-acknowledge a retry
            // without overwriting its accounting or executing the handler twice.
            this.sendReply({ type: 'accepted', replyTo: requestId });
            return;
        }
        const completed = this.completedIncoming.get(requestId);
        if (completed) {
            this.sendReply(completed.header, completed.body);
            return;
        }
        const requestBytes = data.length;
        const tombstone = this.createCompletedTombstone(requestId);
        if (this.activeIncomingRequests >= MaxInFlightRequests ||
            this.activeIncomingBytes + requestBytes > MaxInFlightRequestBytes ||
            (this.incomingBudget !== undefined &&
                (this.incomingBudget.activeRequests >= MaxInFlightRequests ||
                    this.incomingBudget.activeBytes + requestBytes > MaxInFlightRequestBytes))) {
            this.sendReply({
                type: 'result',
                replyTo: requestId,
                ok: false,
                error: 'Too many in-flight sRPC mesh requests or bytes',
                errorName: 'SrpcBackpressureError'
            });
            return;
        }
        if (!this.canReserveCompletedRequest(tombstone.retainedBytes)) {
            this.sendReply({
                type: 'result',
                replyTo: requestId,
                ok: false,
                error: 'Completed sRPC mesh request dedupe capacity is full',
                errorName: 'SrpcBackpressureError'
            });
            return;
        }
        this.activeIncomingRequests++;
        this.activeIncomingBytes += requestBytes;
        this.activeIncoming.set(requestId, requestBytes);
        this.activeIncomingTombstones.set(requestId, tombstone.retainedBytes);
        this.activeIncomingTombstoneBytes += tombstone.retainedBytes;
        if (this.incomingBudget) {
            this.incomingBudget.activeRequests++;
            this.incomingBudget.activeBytes += requestBytes;
        }
        try {
            this.send({ type: 'accepted', replyTo: requestId });
        }
        catch {
            // Do not process a request that we could not acknowledge. The
            // requester may safely retry it, and this callback must not leak
            // an in-flight slot when the socket is closing or backpressured.
            this.releaseIncomingRequest(requestId);
            this.close(1011, 'Unable to acknowledge sRPC mesh request');
            return;
        }
        this.handler(this, frame)
            .then(response => {
            const header = { ...response.header, type: 'result', replyTo: requestId, ok: true };
            const body = Buffer.from(response.body);
            this.rememberCompleted(requestId, header, body);
            this.sendReply(header, body);
        }, error => {
            const serialized = (0, types_1.serializeSrpcError)(error);
            const header = {
                type: 'result',
                replyTo: requestId,
                ok: false,
                error: error instanceof types_1.SrpcError ? serialized.error : error instanceof Error ? error.message : String(error),
                errorName: error instanceof Error ? error.name : undefined,
                ...(error instanceof types_1.SrpcError && typeof serialized.userError === 'boolean' ? { userError: serialized.userError } : {})
            };
            this.rememberCompleted(requestId, header);
            this.sendReply(header);
        })
            .finally(() => {
            this.releaseIncomingRequest(requestId);
        });
    }
    releaseIncomingRequest(requestId) {
        const requestBytes = this.activeIncoming.get(requestId);
        if (requestBytes === undefined)
            return;
        this.activeIncoming.delete(requestId);
        this.activeIncomingRequests = Math.max(0, this.activeIncomingRequests - 1);
        this.activeIncomingBytes = Math.max(0, this.activeIncomingBytes - requestBytes);
        const tombstoneBytes = this.activeIncomingTombstones.get(requestId);
        if (tombstoneBytes !== undefined) {
            this.activeIncomingTombstones.delete(requestId);
            this.activeIncomingTombstoneBytes = Math.max(0, this.activeIncomingTombstoneBytes - tombstoneBytes);
        }
        if (this.incomingBudget) {
            this.incomingBudget.activeRequests = Math.max(0, this.incomingBudget.activeRequests - 1);
            this.incomingBudget.activeBytes = Math.max(0, this.incomingBudget.activeBytes - requestBytes);
        }
    }
    handleClose() {
        if (this.closeNotified)
            return;
        this.closeNotified = true;
        this.closed = true;
        clearInterval(this.pingTimer);
        for (const [id, pending] of this.pending) {
            clearTimeout(pending.timer);
            pending.reject(pending.dispatched ? new types_1.SrpcIndeterminateDeliveryError(pending.clientId) : new types_1.SrpcOwnerUnavailableError(pending.clientId));
            this.pending.delete(id);
        }
        // Running handlers cannot be cancelled. Keep their shared budget charged
        // until their finally blocks finish, even though this peer is no longer
        // eligible for new work.
        for (const handler of this.closeHandlers) {
            try {
                handler();
            }
            catch {
                // Close cleanup must remain deterministic even when a consumer throws.
            }
        }
        this.closeHandlers.clear();
    }
    sendReply(header, body) {
        try {
            this.send(header, body);
        }
        catch {
            // A failed terminal reply makes the remote delivery result
            // unknowable. Fence the peer so its close handlers release any
            // capabilities and grants tied to this transport generation.
            this.close(1011, 'Unable to send sRPC mesh reply');
        }
    }
    rememberCompleted(requestId, header, body) {
        const retainedBytes = Buffer.byteLength(JSON.stringify(header)) + (body?.byteLength ?? 0);
        if (retainedBytes <= MaxCompletedRequestBytes - CompletedTombstoneReserveBytes) {
            if (this.storeCompleted(requestId, {
                header,
                body,
                expiresAt: Date.now() + CompletedRequestTtlMs,
                retainedBytes
            })) {
                return;
            }
        }
        // The side effect already completed, so forgetting the request ID
        // would permit a retry to execute it again. Retain a small bounded
        // tombstone and tell duplicate callers the original response cannot
        // be replayed.
        const tombstone = this.createCompletedTombstone(requestId);
        if (!this.storeCompleted(requestId, tombstone)) {
            // Every accepted request reserves enough completed-cache capacity
            // for this tombstone before its handler starts. Keep this guard for
            // direct internal callers, which do not hold that reservation.
            return;
        }
    }
    createCompletedTombstone(requestId) {
        const header = {
            type: 'result',
            replyTo: requestId,
            ok: false,
            error: 'Completed sRPC mesh response is no longer replayable',
            errorName: 'SrpcIndeterminateDeliveryError'
        };
        return {
            header,
            expiresAt: Date.now() + CompletedRequestTtlMs,
            retainedBytes: Buffer.byteLength(JSON.stringify(header))
        };
    }
    canReserveCompletedRequest(tombstoneBytes) {
        return (this.completedIncoming.size + this.activeIncoming.size < MaxCompletedRequests &&
            this.completedIncomingBytes + this.activeIncomingTombstoneBytes + tombstoneBytes <= MaxCompletedRequestBytes);
    }
    storeCompleted(requestId, completed) {
        this.pruneCompletedIncoming();
        const existing = this.completedIncoming.get(requestId);
        const activeTombstoneBytes = this.activeIncomingTombstones.get(requestId) ?? 0;
        const activeReservationCount = activeTombstoneBytes === 0 ? 0 : 1;
        const projectedCount = this.completedIncoming.size - Number(existing !== undefined) + 1 + this.activeIncoming.size - activeReservationCount;
        const projectedBytes = this.completedIncomingBytes -
            (existing?.retainedBytes ?? 0) +
            completed.retainedBytes +
            this.activeIncomingTombstoneBytes -
            activeTombstoneBytes;
        if (projectedCount > MaxCompletedRequests || projectedBytes > MaxCompletedRequestBytes)
            return false;
        this.removeCompleted(requestId);
        this.completedIncoming.set(requestId, completed);
        this.completedIncomingBytes += completed.retainedBytes;
        return true;
    }
    removeCompleted(requestId) {
        const completed = this.completedIncoming.get(requestId);
        if (!completed)
            return;
        this.completedIncoming.delete(requestId);
        this.completedIncomingBytes = Math.max(0, this.completedIncomingBytes - completed.retainedBytes);
    }
    pruneCompletedIncoming() {
        const now = Date.now();
        for (const [requestId, completed] of this.completedIncoming) {
            if (completed.expiresAt <= now)
                this.removeCompleted(requestId);
        }
    }
    ping() {
        if (!this.connected)
            return;
        if (this.lastPongAt < Date.now() - PongTimeoutMs) {
            this.ws.terminate();
            return;
        }
        this.ws.ping();
    }
    static __tsfType = _MeshLinkPeerMetadata_1 = _a.decodeCompactMetadataV1("[1,{\"kind\":16,\"name\":\"MeshLinkPeer\",\"typeName\":\"MeshLinkPeer\",\"classType\":{\"$tsf\":0},\"properties\":[],\"methods\":[{\"name\":\"onClose\",\"parameters\":[{\"name\":\"handler\",\"type\":{\"$tsfType\":0},\"optional\":false,\"default\":false}],\"returnType\":{\"$tsfType\":0}},{\"name\":\"request\",\"parameters\":[{\"name\":\"header\",\"type\":{\"$tsfType\":1},\"optional\":false,\"default\":false},{\"name\":\"body\",\"type\":{\"kind\":16,\"typeName\":\"Uint8Array\",\"classType\":{\"$tsf\":1}},\"optional\":false,\"default\":false},{\"name\":\"timeoutMs\",\"type\":{\"$tsfType\":2},\"optional\":false,\"default\":false}],\"returnType\":{\"kind\":22,\"type\":{\"kind\":18,\"typeName\":\"MeshLinkFrame\",\"types\":[{\"kind\":20,\"name\":\"header\",\"type\":{\"kind\":18,\"typeName\":\"MeshLinkFrameHeader\",\"types\":[{\"kind\":20,\"name\":\"version\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"type\",\"type\":{\"kind\":12,\"types\":[{\"kind\":10,\"literal\":\"invoke\"},{\"kind\":10,\"literal\":\"reserveStreamIds\"},{\"kind\":10,\"literal\":\"confirmStreamIds\"},{\"kind\":10,\"literal\":\"releaseStreamIds\"},{\"kind\":10,\"literal\":\"streamWrite\"},{\"kind\":10,\"literal\":\"streamFinish\"},{\"kind\":10,\"literal\":\"streamDestroy\"},{\"kind\":10,\"literal\":\"streamActivate\"},{\"kind\":10,\"literal\":\"streamAttach\"},{\"kind\":10,\"literal\":\"revokeCapability\"},{\"kind\":10,\"literal\":\"clientInvoke\"},{\"kind\":10,\"literal\":\"fenceClient\"},{\"kind\":10,\"literal\":\"clientUpdateMetadata\"},{\"kind\":10,\"literal\":\"disconnect\"},{\"kind\":10,\"literal\":\"updateMetadata\"},{\"kind\":10,\"literal\":\"accepted\"},{\"kind\":10,\"literal\":\"result\"},{\"kind\":10,\"literal\":\"ping\"},{\"kind\":10,\"literal\":\"pong\"},{\"kind\":10,\"literal\":\"goAway\"}],\"typeName\":\"MeshLinkFrameType\"},\"optional\":false},{\"kind\":20,\"name\":\"meshKey\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"id\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"replyTo\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"clientId\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"connectionId\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"prefix\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"timeoutMs\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"deadlineAt\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"streamId\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"count\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"ids\",\"type\":{\"kind\":12,\"types\":[{\"kind\":14,\"type\":{\"kind\":7}},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"capability\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"reservationId\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"ok\",\"type\":{\"kind\":12,\"types\":[{\"kind\":8},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"error\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"errorName\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"userError\",\"type\":{\"kind\":12,\"types\":[{\"kind\":8},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"reason\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"closeCapability\",\"type\":{\"kind\":12,\"types\":[{\"kind\":8},{\"kind\":4}]},\"optional\":true}]},\"optional\":false},{\"kind\":20,\"name\":\"body\",\"type\":{\"kind\":16,\"typeName\":\"Buffer\",\"classType\":{\"$tsf\":2}},\"optional\":false}]}}},{\"name\":\"send\",\"parameters\":[{\"name\":\"header\",\"type\":{\"$tsfType\":3},\"optional\":false,\"default\":false},{\"name\":\"body\",\"type\":{\"kind\":16,\"typeName\":\"Uint8Array\",\"classType\":{\"$tsf\":1}},\"optional\":true,\"default\":true}],\"returnType\":{\"$tsfType\":4}},{\"name\":\"close\",\"parameters\":[{\"name\":\"code\",\"type\":{\"$tsfType\":5},\"optional\":true,\"default\":true},{\"name\":\"reason\",\"type\":{\"$tsfType\":5},\"optional\":true,\"default\":true}],\"returnType\":{\"$tsfType\":4}}],\"hasConstructor\":true,\"constructorParameters\":[{\"name\":\"processId\",\"type\":{\"$tsfType\":6},\"optional\":false,\"default\":false},{\"name\":\"ws\",\"type\":{\"kind\":16,\"typeName\":\"WebSocket\",\"classType\":{\"$tsf\":3}},\"optional\":false,\"default\":false},{\"name\":\"maxFrameBytes\",\"type\":{\"$tsfType\":2},\"optional\":false,\"default\":false},{\"name\":\"maxBufferedBytes\",\"type\":{\"$tsfType\":2},\"optional\":false,\"default\":false},{\"name\":\"handler\",\"type\":{\"$tsfType\":7},\"optional\":false,\"default\":false},{\"name\":\"endpointId\",\"type\":{\"$tsfType\":5},\"optional\":true,\"default\":true},{\"name\":\"incomingBudget\",\"type\":{\"$tsfType\":8},\"optional\":true,\"default\":false},{\"name\":\"publicKey\",\"type\":{\"$tsfType\":5},\"optional\":true,\"default\":true}]}]", [() => MeshLinkPeer, () => (typeof Uint8Array !== "undefined" ? Uint8Array : (typeof exports !== "undefined" ? exports.Uint8Array : undefined)), () => (typeof Buffer !== "undefined" ? Buffer : (typeof exports !== "undefined" ? exports.Buffer : undefined)), () => (typeof WebSocket !== "undefined" ? WebSocket : (typeof exports !== "undefined" ? exports.WebSocket : undefined))], __tsf_metadata_type);
}
exports.MeshLinkPeer = MeshLinkPeer;
_MeshLinkPeerMetadata_1.classType = MeshLinkPeer;
MeshLinkPeer.__tsfType = _MeshLinkPeerMetadata_1;
function toBuffer(data) {
    if (Buffer.isBuffer(data))
        return data;
    if (Array.isArray(data))
        return Buffer.concat(data);
    return Buffer.from(data);
}
exports.__tsfTypeAliases = JSON.parse("[1,{\"MeshLinkIncomingBudget\":{\"kind\":18,\"typeName\":\"MeshLinkIncomingBudget\",\"types\":[{\"kind\":20,\"name\":\"activeRequests\",\"type\":{\"kind\":7},\"optional\":false},{\"kind\":20,\"name\":\"activeBytes\",\"type\":{\"kind\":7},\"optional\":false}]},\"MeshLinkRequestHandler\":{\"kind\":2,\"typeName\":\"(peer: MeshLinkPeer, frame: MeshLinkFrame) =\\u003e Promise\\u003cMeshLinkFrame\\u003e\",\"typeName\":\"MeshLinkRequestHandler\"}}]")[1];
//# sourceMappingURL=peer.js.map