"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.__tsfTypeAliases = exports.MeshService = exports.MeshBroadcastIndeterminateDeliveryError = void 0;
exports.destroyMeshRedis = destroyMeshRedis;
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 node_os_1 = require("node:os");
const node_perf_hooks_1 = require("node:perf_hooks");
const helpers_1 = require("../helpers");
const lifecycle_1 = require("../helpers/redis/lifecycle");
const redis_1 = require("../helpers/redis/redis");
const leader_1 = require("./leader");
const logger_1 = require("./logger");
const __tsf_metadata_type = _a.createCompactMetadataRegistryV1("[1,[{\"kind\":6},{\"kind\":2},{\"kind\":2,\"typeName\":\"K\"},{\"kind\":2,\"typeName\":\"(data: B[K], senderInstanceId: number, context: MeshHandlerContext) =\\u003e void | Promise\\u003cvoid\\u003e\"},{\"kind\":3},{\"kind\":2,\"typeName\":\"(instanceId: number) =\\u003e void | Promise\\u003cvoid\\u003e\"},{\"kind\":2,\"typeName\":\"(reason?: Error) =\\u003e void | Promise\\u003cvoid\\u003e\"},{\"kind\":22,\"type\":{\"kind\":3}},{\"kind\":22,\"type\":{\"kind\":14,\"type\":{\"kind\":18,\"typeName\":\"MeshNode\",\"types\":[{\"kind\":20,\"name\":\"instanceId\",\"type\":{\"kind\":7},\"optional\":false},{\"kind\":20,\"name\":\"hostname\",\"type\":{\"kind\":6},\"optional\":false},{\"kind\":20,\"name\":\"self\",\"type\":{\"kind\":8},\"optional\":false},{\"kind\":20,\"name\":\"processId\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"linkEndpointId\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"linkEndpointPublicKey\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"linkUrl\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"startedAt\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true}]}}},{\"kind\":7},{\"kind\":22,\"type\":{\"kind\":12,\"types\":[{\"kind\":18,\"typeName\":\"MeshNode\",\"types\":[{\"kind\":20,\"name\":\"instanceId\",\"type\":{\"kind\":7},\"optional\":false},{\"kind\":20,\"name\":\"hostname\",\"type\":{\"kind\":6},\"optional\":false},{\"kind\":20,\"name\":\"self\",\"type\":{\"kind\":8},\"optional\":false},{\"kind\":20,\"name\":\"processId\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"linkEndpointId\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"linkEndpointPublicKey\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"linkUrl\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"startedAt\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true}]},{\"kind\":4}]}},{\"kind\":18,\"typeName\":\"Omit\",\"utilityType\":\"Omit\",\"typeArguments\":[{\"kind\":18,\"typeName\":\"MeshNode\",\"types\":[{\"kind\":20,\"name\":\"instanceId\",\"type\":{\"kind\":7},\"optional\":false},{\"kind\":20,\"name\":\"hostname\",\"type\":{\"kind\":6},\"optional\":false},{\"kind\":20,\"name\":\"self\",\"type\":{\"kind\":8},\"optional\":false},{\"kind\":20,\"name\":\"processId\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"linkEndpointId\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"linkEndpointPublicKey\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"linkUrl\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"startedAt\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true}]}],\"utilityKeys\":[\"instanceId\",\"hostname\",\"self\"],\"types\":[{\"kind\":20,\"name\":\"processId\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"linkEndpointId\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"linkEndpointPublicKey\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"linkUrl\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"startedAt\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true}]},{\"kind\":2,\"typeName\":\"B[K]\"},{\"kind\":18,\"typeName\":\"MeshBroadcastOptions\",\"types\":[{\"kind\":20,\"name\":\"skipSelf\",\"type\":{\"kind\":12,\"types\":[{\"kind\":8},{\"kind\":4}]},\"optional\":true}]},{\"kind\":18,\"typeName\":\"MeshServiceOptions\",\"types\":[{\"kind\":20,\"name\":\"heartbeatIntervalMs\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"nodeTtlMs\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"leaderOptions\",\"type\":{\"kind\":12,\"types\":[{\"kind\":18,\"typeName\":\"LeaderServiceOptions\",\"types\":[{\"kind\":20,\"name\":\"ttlMs\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"renewalIntervalMs\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"retryDelayMs\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true}]},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"nodeMetadata\",\"type\":{\"kind\":12,\"types\":[{\"kind\":18,\"typeName\":\"Omit\",\"utilityType\":\"Omit\",\"typeArguments\":[{\"kind\":18,\"typeName\":\"MeshNode\",\"types\":[{\"kind\":20,\"name\":\"instanceId\",\"type\":{\"kind\":7},\"optional\":false},{\"kind\":20,\"name\":\"hostname\",\"type\":{\"kind\":6},\"optional\":false},{\"kind\":20,\"name\":\"self\",\"type\":{\"kind\":8},\"optional\":false},{\"kind\":20,\"name\":\"processId\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"linkEndpointId\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"linkEndpointPublicKey\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"linkUrl\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"startedAt\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true}]}],\"utilityKeys\":[\"instanceId\",\"hostname\",\"self\"],\"types\":[{\"kind\":20,\"name\":\"processId\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"linkEndpointId\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"linkEndpointPublicKey\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"linkUrl\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"startedAt\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true}]},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"maxMessageBytes\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"maxActiveHandlers\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"maxActiveHandlerBytes\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"cleanupBatchSize\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true}]}]]", []);
let _MeshBroadcastIndeterminateDeliveryErrorMetadata_1;
class MeshBroadcastIndeterminateDeliveryError extends Error {
    constructor(type, cause) {
        super(`Mesh broadcast delivery is indeterminate (type: ${type})`, cause === undefined ? undefined : { cause });
        this.name = 'MeshBroadcastIndeterminateDeliveryError';
    }
    static __tsfType = _MeshBroadcastIndeterminateDeliveryErrorMetadata_1 = _a.decodeCompactMetadataV1("[1,{\"kind\":16,\"name\":\"MeshBroadcastIndeterminateDeliveryError\",\"typeName\":\"MeshBroadcastIndeterminateDeliveryError\",\"classType\":{\"$tsf\":0},\"properties\":[],\"methods\":[],\"hasConstructor\":true,\"constructorParameters\":[{\"name\":\"type\",\"type\":{\"$tsfType\":0},\"optional\":false,\"default\":false},{\"name\":\"cause\",\"type\":{\"$tsfType\":1},\"optional\":true,\"default\":false}]}]", [() => MeshBroadcastIndeterminateDeliveryError], __tsf_metadata_type);
}
exports.MeshBroadcastIndeterminateDeliveryError = MeshBroadcastIndeterminateDeliveryError;
_MeshBroadcastIndeterminateDeliveryErrorMetadata_1.classType = MeshBroadcastIndeterminateDeliveryError;
MeshBroadcastIndeterminateDeliveryError.__tsfType = _MeshBroadcastIndeterminateDeliveryErrorMetadata_1;
// --- Lua Scripts ---
const HEARTBEAT_SCRIPT = `
local time = redis.call("time")
local now_ms = tonumber(time[1]) * 1000 + math.floor(tonumber(time[2]) / 1000)
if ARGV[2] == "create" then
    redis.call("zadd", KEYS[1], "NX", now_ms, ARGV[1])
else
    local score = redis.call("zscore", KEYS[1], ARGV[1])
    if not score or tonumber(score) <= now_ms - tonumber(ARGV[3]) then
        return 0
    end
    redis.call("zadd", KEYS[1], now_ms, ARGV[1])
end
return now_ms
`;
const CLEANUP_SCRIPT = `
local time = redis.call("time")
local now_ms = tonumber(time[1]) * 1000 + math.floor(tonumber(time[2]) / 1000)
local cutoff = now_ms - tonumber(ARGV[1])
local expired = redis.call("zrangebyscore", KEYS[1], "-inf", cutoff, "LIMIT", 0, tonumber(ARGV[2]))
for i, id in ipairs(expired) do
    redis.call("zrem", KEYS[1], id)
    redis.call("hdel", KEYS[2], id)
    redis.call("lpush", KEYS[3], id)
end
return expired
`;
const DEREGISTER_SCRIPT = `
redis.call("zrem", KEYS[1], ARGV[1])
redis.call("hdel", KEYS[2], ARGV[1])
return 1
`;
// Metadata must never recreate a node which has already been deregistered or
// expired.  Keep the liveness check and HSET in one Redis-time transaction so
// it is serialized with CLEANUP/DEREGISTER.
const UPDATE_METADATA_SCRIPT = `
local time = redis.call("time")
local now_ms = tonumber(time[1]) * 1000 + math.floor(tonumber(time[2]) / 1000)
local score = redis.call("zscore", KEYS[1], ARGV[1])
if not score or tonumber(score) <= now_ms - tonumber(ARGV[3]) then return 0 end
redis.call("hset", KEYS[2], ARGV[1], ARGV[2])
return 1
`;
const ACTIVE_MEMBERS_SCRIPT = `
local time = redis.call("time")
local now_ms = tonumber(time[1]) * 1000 + math.floor(tonumber(time[2]) / 1000)
return redis.call("zrangebyscore", KEYS[1], now_ms - tonumber(ARGV[1]), "+inf")
`;
const ACTIVE_SCORE_SCRIPT = `
local time = redis.call("time")
local now_ms = tonumber(time[1]) * 1000 + math.floor(tonumber(time[2]) / 1000)
local score = redis.call("zscore", KEYS[1], ARGV[1])
if not score or tonumber(score) <= now_ms - tonumber(ARGV[2]) then return nil end
return score
`;
const RECOVER_CLEANUP_SCRIPT = `
local recovered = 0
while recovered < tonumber(ARGV[1]) do
    local id = redis.call("rpop", KEYS[2])
    if not id then break end
    local separator = string.find(id, "|")
    redis.call("lpush", KEYS[1], separator and string.sub(id, 1, separator - 1) or id)
    recovered = recovered + 1
end
return recovered
`;
const CLAIM_CLEANUP_SCRIPT = `
local id = redis.call("rpop", KEYS[1])
if not id then return "" end
local claim = id .. "|" .. ARGV[1]
redis.call("lpush", KEYS[2], claim)
return claim
`;
const ACK_CLEANUP_SCRIPT = `
return redis.call("lrem", KEYS[1], 1, ARGV[1])
`;
const NACK_CLEANUP_SCRIPT = `
if redis.call("lrem", KEYS[2], 1, ARGV[1]) == 1 then
    -- Consumers pop from the right. Requeue a failed obligation on the left so
    -- it cannot indefinitely starve healthy work already waiting in the list.
    local separator = string.find(ARGV[1], "|")
    local id = separator and string.sub(ARGV[1], 1, separator - 1) or ARGV[1]
    redis.call("lpush", KEYS[1], id)
    return 1
end
return 0
`;
let meshRedis = null;
function getMeshRedis() {
    if (!meshRedis) {
        const { client, prefix } = (0, redis_1.createRedis)('MESH');
        client.defineCommand('HEARTBEAT', { lua: HEARTBEAT_SCRIPT, numberOfKeys: 1 });
        client.defineCommand('CLEANUP', { lua: CLEANUP_SCRIPT, numberOfKeys: 3 });
        client.defineCommand('DEREGISTER', { lua: DEREGISTER_SCRIPT, numberOfKeys: 2 });
        client.defineCommand('UPDATE_METADATA', { lua: UPDATE_METADATA_SCRIPT, numberOfKeys: 2 });
        client.defineCommand('ACTIVE_MEMBERS', { lua: ACTIVE_MEMBERS_SCRIPT, numberOfKeys: 1 });
        client.defineCommand('ACTIVE_SCORE', { lua: ACTIVE_SCORE_SCRIPT, numberOfKeys: 1 });
        client.defineCommand('RECOVER_CLEANUP', { lua: RECOVER_CLEANUP_SCRIPT, numberOfKeys: 2 });
        client.defineCommand('CLAIM_CLEANUP', { lua: CLAIM_CLEANUP_SCRIPT, numberOfKeys: 2 });
        client.defineCommand('ACK_CLEANUP', { lua: ACK_CLEANUP_SCRIPT, numberOfKeys: 1 });
        client.defineCommand('NACK_CLEANUP', { lua: NACK_CLEANUP_SCRIPT, numberOfKeys: 2 });
        const nextClient = client;
        (0, lifecycle_1.registerRedisStateReset)(nextClient, () => {
            if (meshRedis?.client === nextClient)
                meshRedis = null;
        });
        meshRedis = { client: nextClient, prefix };
    }
    return meshRedis;
}
function destroyMeshRedis() {
    if (meshRedis) {
        meshRedis.client.disconnect();
        meshRedis = null;
    }
}
let _MeshServiceMetadata_1;
// --- MeshService ---
class MeshService {
    _instanceId = 0;
    key;
    prefix = '';
    running = false;
    heartbeatIntervalMs;
    nodeTtlMs;
    maxMessageBytes;
    maxActiveHandlers;
    maxActiveHandlerBytes;
    cleanupBatchSize;
    leaderOptions;
    nodeMetadata;
    heartbeatTimer = null;
    leaderService = null;
    /** Changes on every acquire/loss, including reacquisition by one object. */
    leaderEpoch = 0;
    subscriberClient = null;
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    broadcastHandlers = new Map();
    broadcastGeneration = createBroadcastGeneration(0);
    activeIncomingMessages = 0;
    activeIncomingBytes = 0;
    nodeCleanedUpCallback = null;
    leaseLostCallback = null;
    leaseLost = false;
    heartbeatGeneration = null;
    cleanupDrains = new Map();
    leaseSafeUntil = 0;
    leaseSafetyTimer = null;
    lifecycle = Promise.resolve();
    generation = 0;
    leaseFencePromise;
    /** @internal Overridable by focused lifecycle tests. */
    leaseLossCallbackTimeoutMs = 2000;
    logger = (0, logger_1.createLogger)(this);
    constructor(key, options) {
        validateMeshOptions(options);
        this.key = key;
        this.heartbeatIntervalMs = options?.heartbeatIntervalMs ?? 5000;
        this.nodeTtlMs = options?.nodeTtlMs ?? 15000;
        this.maxMessageBytes = options?.maxMessageBytes ?? 1024 * 1024;
        this.maxActiveHandlers = options?.maxActiveHandlers ?? 4096;
        this.maxActiveHandlerBytes = options?.maxActiveHandlerBytes ?? 64 * 1024 * 1024;
        this.cleanupBatchSize = options?.cleanupBatchSize ?? 100;
        this.leaderOptions = options?.leaderOptions;
        this.nodeMetadata = options?.nodeMetadata ?? {};
    }
    get instanceId() {
        return this._instanceId;
    }
    registerBroadcastHandler(type, handler) {
        this.broadcastHandlers.set(type, handler);
    }
    setNodeCleanedUpCallback(cb) {
        this.nodeCleanedUpCallback = cb;
    }
    /** Fires once after renewal proves this instance is no longer a member. */
    setLeaseLostCallback(cb) {
        this.leaseLostCallback = cb;
    }
    /**
     * Synchronously fences work once the last conservatively-known membership
     * lease can no longer be valid.
     */
    assertLeaseSafe() {
        const reason = new Error('Mesh membership lease is no longer safe');
        if (!this.running || this.leaseLost)
            throw reason;
        if (node_perf_hooks_1.performance.now() < this.leaseSafeUntil)
            return;
        this.fenceLeaseLoss(reason);
        throw reason;
    }
    /**
     * @internal Synchronously revokes this generation's membership authority
     * and handler state. Physical Redis/subscriber shutdown continues
     * asynchronously and the returned promise settles after lease-loss
     * callbacks finish.
     */
    fence(reason) {
        return this.fenceLeaseLoss(reason);
    }
    async getNodes() {
        this.assertLeaseSafe();
        const { client } = getMeshRedis();
        const members = await client.ACTIVE_MEMBERS(this.heartbeatsKey(), String(this.nodeTtlMs));
        this.assertLeaseSafe();
        if (members.length === 0)
            return [];
        const records = await client.hmget(this.nodesKey(), ...members);
        this.assertLeaseSafe();
        return members.map((id, i) => this.parseNode(id, records[i]));
    }
    async getNode(instanceId) {
        this.assertLeaseSafe();
        const { client } = getMeshRedis();
        const alive = await client.ACTIVE_SCORE(this.heartbeatsKey(), String(instanceId), String(this.nodeTtlMs));
        this.assertLeaseSafe();
        if (alive === null)
            return undefined;
        const raw = await client.hget(this.nodesKey(), String(instanceId));
        this.assertLeaseSafe();
        return this.parseNode(String(instanceId), raw);
    }
    async updateNodeMetadata(metadata) {
        this.nodeMetadata = { ...this.nodeMetadata, ...metadata };
        if (!this.running)
            return;
        const { client } = getMeshRedis();
        this.assertLeaseSafe();
        const updated = await client.UPDATE_METADATA(this.heartbeatsKey(), this.nodesKey(), String(this._instanceId), this.serializeNode(), String(this.nodeTtlMs));
        if (updated !== 1) {
            this.fenceLeaseLoss(new Error('Mesh membership disappeared while updating node metadata'));
            throw new Error('Mesh membership disappeared while updating node metadata');
        }
        this.assertLeaseSafe();
    }
    async broadcast(type, data, options) {
        this.assertLeaseSafe();
        const message = {
            protocolVersion: 2,
            broadcast: true,
            senderInstanceId: this._instanceId,
            type,
            data
        };
        const payload = this.encodeEnvelope(message);
        this.assertLeaseSafe();
        const publisher = this.getPublisher();
        const publish = publisher.publish;
        if (typeof publish !== 'function') {
            throw new TypeError('Redis publisher does not expose a callable publish method');
        }
        // Recheck immediately before the first delivery side effect. No
        // asynchronous or fallible operation separates local delivery from
        // invoking Redis publish after this point.
        this.assertLeaseSafe();
        if (!options?.skipSelf) {
            // Match local delivery to the exact JSON representation sent to
            // peers (including Date and non-finite number normalization).
            this.handleBroadcastMessage(JSON.parse(payload));
        }
        try {
            // Local delivery and Redis delivery are now both possible. Any
            // failure after entering the call is therefore ambiguous, even
            // when the publisher throws synchronously.
            await publish.call(publisher, this.broadcastChannel(), payload);
            this.assertLeaseSafe();
        }
        catch (error) {
            throw new MeshBroadcastIndeterminateDeliveryError(type, error);
        }
    }
    start() {
        return this.runLifecycle(() => this.startImpl());
    }
    async startImpl() {
        if (this.running) {
            throw new Error('MeshService is already running');
        }
        const { client, prefix } = getMeshRedis();
        this.prefix = prefix;
        const generation = ++this.generation;
        this.broadcastGeneration = createBroadcastGeneration(generation);
        // Acquire unique instance ID
        this._instanceId = await client.incr(this.nextIdKey());
        // Redis pub/sub is retained solely for optional fan-out broadcasts.
        const { client: subClient } = (0, redis_1.createRedis)('MESH');
        this.subscriberClient = subClient;
        try {
            const broadcastCh = this.broadcastChannel();
            await subClient.subscribe(broadcastCh);
            subClient.on('message', (channel, message) => {
                if (generation !== this.generation || channel !== broadcastCh)
                    return;
                this.scheduleIncomingMessage(message, generation);
            });
            // Register heartbeat and node metadata
            const heartbeatStartedAt = node_perf_hooks_1.performance.now();
            await client.HEARTBEAT(this.heartbeatsKey(), String(this._instanceId), 'create', String(this.nodeTtlMs));
            const metadataWritten = await client.UPDATE_METADATA(this.heartbeatsKey(), this.nodesKey(), String(this._instanceId), this.serializeNode(), String(this.nodeTtlMs));
            if (metadataWritten !== 1)
                throw new Error('Mesh membership disappeared during startup metadata registration');
            this.leaseSafeUntil = heartbeatStartedAt + this.nodeTtlMs;
            if (node_perf_hooks_1.performance.now() >= this.leaseSafeUntil) {
                throw new Error('Mesh membership lease expired during startup');
            }
        }
        catch (err) {
            if (this.broadcastGeneration.generation === generation) {
                this.broadcastGeneration.abortController.abort(err);
                this.broadcastGeneration = createBroadcastGeneration(this.generation);
            }
            // Clean up subscriber on partial init failure
            try {
                subClient.removeAllListeners('message');
                subClient.disconnect();
            }
            catch {
                // ignore cleanup errors
            }
            this.subscriberClient = null;
            const failedInstanceId = this._instanceId;
            this._instanceId = 0;
            if (failedInstanceId !== 0) {
                try {
                    await client.DEREGISTER(this.heartbeatsKey(), this.nodesKey(), String(failedInstanceId));
                }
                catch {
                    // Preserve the startup failure; normal TTL/leader cleanup is the fallback.
                }
            }
            throw err;
        }
        this.leaseLost = false;
        this.leaseFencePromise = undefined;
        this.running = true;
        this.armLeaseSafetyTimer(generation);
        // Start heartbeat interval
        this.heartbeatTimer = setInterval(() => this.doHeartbeat(), this.heartbeatIntervalMs);
        // Start leader service for cleanup duties
        this.leaderService = new leader_1.LeaderService(`mesh:${this.key}`, this.leaderOptions);
        this.leaderService.setBecameLeaderCallback(() => {
            this.leaderEpoch++;
            if (this.running)
                this.startCleanup();
        });
        this.leaderService.setLostLeaderCallback(() => {
            this.leaderEpoch++;
        });
        this.leaderService.start();
        this.logger.info('mesh node started', { instanceId: this._instanceId, key: this.key });
    }
    stop() {
        this.running = false;
        this.discardBroadcastGeneration(new Error('MeshService generation stopped'), this.generation);
        return this.runLifecycle(() => this.stopImpl());
    }
    async stopImpl() {
        this.running = false;
        this.generation++;
        this.leaderEpoch++;
        this.discardBroadcastGeneration(new Error('MeshService generation stopped'), this.generation);
        // A callback may be arbitrary user code and cannot be forcibly
        // cancelled.  Fence it first, then wait only a bounded period; its
        // processing-list entry is deliberately left for RECOVER_CLEANUP.
        if (this.cleanupDrains.size)
            await settleMeshCleanup(Promise.allSettled(this.cleanupDrains.values()), 2000);
        // Stop leader service
        if (this.leaderService) {
            await this.leaderService.stop();
            this.leaderService = null;
        }
        // Stop heartbeat
        if (this.heartbeatTimer) {
            clearInterval(this.heartbeatTimer);
            this.heartbeatTimer = null;
        }
        this.clearLeaseSafetyTimer();
        // Unsubscribe and quit subscriber
        if (this.subscriberClient) {
            const subscriber = this.subscriberClient;
            this.subscriberClient = null;
            try {
                subscriber.removeAllListeners('message');
                subscriber.disconnect();
            }
            catch {
                // ignore errors during cleanup
            }
        }
        // Atomically remove self from heartbeats and nodes
        if (this._instanceId !== 0) {
            const stoppedInstanceId = this._instanceId;
            this._instanceId = 0;
            try {
                const { client } = getMeshRedis();
                await client.DEREGISTER(this.heartbeatsKey(), this.nodesKey(), String(stoppedInstanceId));
            }
            catch {
                // ignore errors during cleanup
            }
            this.logger.info('mesh node stopped', { instanceId: stoppedInstanceId, key: this.key });
        }
    }
    // --- Private ---
    runLifecycle(operation) {
        const next = this.lifecycle.then(operation, operation);
        this.lifecycle = next.catch(() => { });
        return next;
    }
    discardBroadcastGeneration(reason, nextGeneration) {
        const state = this.broadcastGeneration;
        this.broadcastGeneration = createBroadcastGeneration(nextGeneration);
        if (!state.abortController.signal.aborted)
            state.abortController.abort(reason);
        state.activeHandlerCount = 0;
        state.activeHandlerBytes = 0;
    }
    scheduleIncomingMessage(raw, generation) {
        const bytes = Buffer.byteLength(raw);
        if (bytes > this.maxMessageBytes ||
            this.activeIncomingMessages >= this.maxActiveHandlers ||
            this.activeIncomingBytes + bytes > this.maxActiveHandlerBytes) {
            this.logger.warn('mesh inbound envelope capacity exceeded');
            return;
        }
        this.activeIncomingMessages++;
        this.activeIncomingBytes += bytes;
        const task = this.handleBroadcastIncoming(raw, generation);
        void task
            .catch(err => this.logger.warn('mesh inbound envelope processing failed', { err }))
            .finally(() => {
            this.activeIncomingMessages = Math.max(0, this.activeIncomingMessages - 1);
            this.activeIncomingBytes = Math.max(0, this.activeIncomingBytes - bytes);
        });
    }
    encodeEnvelope(message) {
        const envelope = {
            ...message,
            protocolVersion: 2
        };
        const payload = JSON.stringify(envelope);
        if (Buffer.byteLength(payload) > this.maxMessageBytes)
            throw new Error('Mesh message exceeds the configured message limit');
        return payload;
    }
    /** @internal Overridable by focused broadcast-delivery tests. */
    getPublisher() {
        return getMeshRedis().client;
    }
    async validateIncomingSender(envelope) {
        if (!isInstanceId(envelope.senderInstanceId))
            return false;
        if (envelope.protocolVersion !== 2)
            return false;
        try {
            const { client } = getMeshRedis();
            this.assertLeaseSafe();
            const active = (await client.ACTIVE_SCORE(this.heartbeatsKey(), String(envelope.senderInstanceId), String(this.nodeTtlMs))) !== null;
            this.assertLeaseSafe();
            return active;
        }
        catch (err) {
            this.logger.warn('failed to validate mesh sender lease', { err });
            return false;
        }
    }
    nextIdKey() {
        return `${this.prefix}:mesh:${this.key}:next_id`;
    }
    serializeNode() {
        return JSON.stringify({
            hostname: (0, node_os_1.hostname)(),
            ...this.nodeMetadata
        });
    }
    parseNode(id, raw) {
        let metadata = {};
        if (raw) {
            try {
                const parsed = JSON.parse(raw);
                metadata = typeof parsed === 'object' && parsed !== null ? parsed : { hostname: raw };
            }
            catch {
                metadata = { hostname: raw };
            }
        }
        return {
            instanceId: parseInt(id, 10),
            hostname: typeof metadata.hostname === 'string' ? metadata.hostname : 'unknown',
            self: parseInt(id, 10) === this._instanceId,
            processId: typeof metadata.processId === 'string' ? metadata.processId : undefined,
            linkEndpointId: typeof metadata.linkEndpointId === 'string' ? metadata.linkEndpointId : undefined,
            linkEndpointPublicKey: typeof metadata.linkEndpointPublicKey === 'string' ? metadata.linkEndpointPublicKey : undefined,
            linkUrl: typeof metadata.linkUrl === 'string' ? metadata.linkUrl : undefined,
            startedAt: typeof metadata.startedAt === 'number' ? metadata.startedAt : undefined
        };
    }
    heartbeatsKey() {
        return `${this.prefix}:mesh:${this.key}:heartbeats`;
    }
    nodesKey() {
        return `${this.prefix}:mesh:${this.key}:nodes`;
    }
    cleanupKey() {
        return `${this.prefix}:mesh:${this.key}:cleanup`;
    }
    cleanupProcessingKey() {
        return `${this.prefix}:mesh:${this.key}:cleanup:processing`;
    }
    broadcastChannel() {
        return `${this.prefix}:mesh:${this.key}:broadcast`;
    }
    async doHeartbeat() {
        const generation = this.generation;
        if (!this.running || this.heartbeatGeneration === generation)
            return;
        this.heartbeatGeneration = generation;
        let runCleanup = false;
        try {
            try {
                const { client } = getMeshRedis();
                const heartbeatStartedAt = node_perf_hooks_1.performance.now();
                const renewed = await client.HEARTBEAT(this.heartbeatsKey(), String(this._instanceId), 'renew', String(this.nodeTtlMs));
                if (renewed === 0) {
                    if (generation !== this.generation)
                        return;
                    this.fenceLeaseLoss(new Error('Mesh membership lease was removed or expired'));
                    return;
                }
                if (generation !== this.generation || !this.running)
                    return;
                this.leaseSafeUntil = heartbeatStartedAt + this.nodeTtlMs;
                this.armLeaseSafetyTimer(generation);
            }
            catch (err) {
                this.logger.warn('mesh heartbeat failed', { err });
                if (generation === this.generation && this.running && node_perf_hooks_1.performance.now() >= this.leaseSafeUntil) {
                    this.fenceLeaseLoss(new Error('Mesh membership lease can no longer be safely renewed before expiry'));
                    return;
                }
            }
            runCleanup = generation === this.generation && this.running && this.leaderService?.isLeader === true;
        }
        finally {
            if (this.heartbeatGeneration === generation)
                this.heartbeatGeneration = null;
        }
        if (runCleanup)
            this.startCleanup();
    }
    startCleanup() {
        const epochKey = `${this.generation}:${this.leaderEpoch}`;
        if (this.cleanupDrains.has(epochKey))
            return;
        // Arbitrary callbacks cannot be killed. Bound retained stale drains,
        // but never let one old epoch monopolize the current leader epoch.
        if (this.cleanupDrains.size >= 8) {
            const leader = this.leaderService;
            this.leaderService = null;
            this.leaderEpoch++;
            void leader?.stop().catch(err => this.logger.warn('failed to relinquish saturated cleanup leadership', { err }));
            this.fenceLeaseLoss(new Error('Mesh cleanup stale-drain limit was exhausted'));
            return;
        }
        const cleanup = this.doCleanup();
        this.cleanupDrains.set(epochKey, cleanup);
        void cleanup.finally(() => {
            if (this.cleanupDrains.get(epochKey) === cleanup)
                this.cleanupDrains.delete(epochKey);
        });
    }
    async doCleanup() {
        const generation = this.generation;
        const leader = this.leaderService;
        const leaderEpoch = this.leaderEpoch;
        // Keep the private/manual maintenance hook usable for focused Redis
        // repair tests; production leader work always captures a live epoch.
        const enforceFence = this.running || leader !== null || this.leaseLost;
        const canContinue = () => !enforceFence ||
            (this.running &&
                generation === this.generation &&
                leader === this.leaderService &&
                leaderEpoch === this.leaderEpoch &&
                leader?.isLeader === true &&
                !this.leaseLost &&
                node_perf_hooks_1.performance.now() < this.leaseSafeUntil);
        let continueCleanup = false;
        try {
            if (!canContinue())
                return;
            const { client } = getMeshRedis();
            const recovered = await client.RECOVER_CLEANUP(this.cleanupKey(), this.cleanupProcessingKey(), String(this.cleanupBatchSize));
            if (!canContinue())
                return;
            const expired = await client.CLEANUP(this.heartbeatsKey(), this.nodesKey(), this.cleanupKey(), String(this.nodeTtlMs), String(this.cleanupBatchSize));
            if (!canContinue())
                return;
            continueCleanup = recovered === this.cleanupBatchSize || expired.length === this.cleanupBatchSize;
            if (expired.length > 0) {
                this.logger.info('cleaned up expired mesh nodes', { expired });
            }
            // Keep obligations in Redis until the callback succeeds. A new leader
            // can resume this list after the current process dies.
            for (let count = 0; count < this.cleanupBatchSize; count++) {
                if (!canContinue())
                    return;
                const claim = await client.CLAIM_CLEANUP(this.cleanupKey(), this.cleanupProcessingKey(), (0, node_crypto_1.randomUUID)());
                if (!canContinue())
                    return;
                if (!claim)
                    break;
                const idStr = claim.split('|', 1)[0];
                const id = parseInt(idStr, 10);
                try {
                    if (!canContinue())
                        return;
                    await this.nodeCleanedUpCallback?.(id);
                    // User callbacks cannot be forcibly cancelled without an
                    // API break.  A fenced callback may finish, but it cannot
                    // acknowledge, nack, or cause further framework work.
                    if (!canContinue())
                        return;
                    await client.ACK_CLEANUP(this.cleanupProcessingKey(), claim);
                    if (!canContinue())
                        return;
                }
                catch (err) {
                    if (!canContinue())
                        return;
                    await client.NACK_CLEANUP(this.cleanupKey(), this.cleanupProcessingKey(), claim);
                    if (!canContinue())
                        return;
                    this.logger.warn('node cleanup callback error; retained for retry', { err, instanceId: id });
                    break;
                }
                if (count + 1 === this.cleanupBatchSize)
                    continueCleanup = true;
            }
        }
        catch (err) {
            this.logger.warn('mesh cleanup failed', { err });
        }
        // Each Lua run and each callback drain is bounded. Continue promptly
        // without turning one leader heartbeat into an unbounded Redis script.
        if (continueCleanup && canContinue())
            this.scheduleCleanupContinuation();
    }
    scheduleCleanupContinuation() {
        if (!this.running || this.leaderService?.isLeader !== true)
            return;
        // Defer one turn so the tracked cleanup promise has settled and a new
        // generation cannot be coalesced into the previous fenced pass.
        const timer = setTimeout(() => {
            if (this.running && this.leaderService?.isLeader === true)
                this.startCleanup();
        }, 0);
        timer.unref?.();
    }
    fenceLeaseLoss(reason) {
        if (this.leaseLost)
            return this.leaseFencePromise ?? Promise.resolve();
        this.leaseLost = true;
        // Fence synchronously before invoking user code: renewal is intentionally
        // unable to recreate the sorted-set member after this point.
        this.running = false;
        this.discardBroadcastGeneration(reason, this.generation);
        if (this.heartbeatTimer) {
            clearInterval(this.heartbeatTimer);
            this.heartbeatTimer = null;
        }
        this.clearLeaseSafetyTimer();
        const callback = this.leaseLostCallback;
        let callbackPromise;
        try {
            // Invoke before joining the serialized lifecycle. Async callbacks run
            // synchronously through their first await, so physical stream fences
            // begin before Redis shutdown or any queued lifecycle operation.
            callbackPromise = Promise.resolve(callback?.(reason));
        }
        catch (err) {
            callbackPromise = Promise.reject(err);
        }
        const observedCallback = callbackPromise.catch(err => {
            this.logger.warn('mesh lease loss callback error', { err });
        });
        const fence = this.runLifecycle(async () => {
            await this.stopImpl();
            // User cleanup is advisory after the synchronous authority fence.
            // Never let a hung callback poison this or later lifecycle work.
            await settleMeshCleanup(observedCallback, this.leaseLossCallbackTimeoutMs);
        });
        this.leaseFencePromise = fence;
        void fence.catch(err => this.logger.warn('mesh lease fence shutdown failed', { err }));
        return fence;
    }
    armLeaseSafetyTimer(generation) {
        this.clearLeaseSafetyTimer();
        const delay = Math.max(1, Math.ceil(this.leaseSafeUntil - node_perf_hooks_1.performance.now()));
        this.leaseSafetyTimer = setTimeout(() => {
            this.leaseSafetyTimer = null;
            if (!this.running || this.generation !== generation)
                return;
            if (node_perf_hooks_1.performance.now() < this.leaseSafeUntil) {
                this.armLeaseSafetyTimer(generation);
                return;
            }
            this.fenceLeaseLoss(new Error('Mesh membership lease expired before renewal completed'));
        }, delay);
        this.leaseSafetyTimer.unref?.();
    }
    clearLeaseSafetyTimer() {
        if (!this.leaseSafetyTimer)
            return;
        clearTimeout(this.leaseSafetyTimer);
        this.leaseSafetyTimer = null;
    }
    async handleBroadcastIncoming(raw, generation = this.generation) {
        if (!this.running || generation !== this.generation)
            return;
        try {
            this.assertLeaseSafe();
        }
        catch {
            return;
        }
        if (Buffer.byteLength(raw) > this.maxMessageBytes)
            return;
        let msg;
        try {
            msg = JSON.parse(raw);
        }
        catch {
            return;
        }
        if (typeof msg !== 'object' || msg === null)
            return;
        const envelope = msg;
        const obj = envelope;
        // Skip self-sent broadcasts (we already delivered locally in broadcast())
        if (obj.senderInstanceId === this._instanceId)
            return;
        if (obj.broadcast !== true || !isMessageType(obj.type))
            return;
        try {
            this.assertLeaseSafe();
            if (!(await this.validateIncomingSender(envelope)))
                return;
            this.assertLeaseSafe();
        }
        catch {
            return;
        }
        if (!this.running || generation !== this.generation)
            return;
        this.handleBroadcastMessage(obj);
    }
    handleBroadcastMessage(msg) {
        const handler = this.broadcastHandlers.get(msg.type);
        if (!handler)
            return;
        const state = this.broadcastGeneration;
        const messageBytes = jsonByteLength(msg);
        if (state.activeHandlerCount >= this.maxActiveHandlers || state.activeHandlerBytes + messageBytes > this.maxActiveHandlerBytes) {
            this.logger.warn('mesh broadcast handler capacity exceeded', { type: msg.type });
            return;
        }
        state.activeHandlerCount++;
        state.activeHandlerBytes += messageBytes;
        Promise.resolve()
            .then(() => {
            if (state !== this.broadcastGeneration || state.abortController.signal.aborted)
                return;
            this.assertLeaseSafe();
            return handler(msg.data, msg.senderInstanceId, { signal: state.abortController.signal });
        })
            .catch(err => {
            this.logger.warn('broadcast handler error', { err, type: msg.type });
        })
            .finally(() => {
            state.activeHandlerCount = Math.max(0, state.activeHandlerCount - 1);
            state.activeHandlerBytes = Math.max(0, state.activeHandlerBytes - messageBytes);
        });
    }
    static __tsfType = _MeshServiceMetadata_1 = _a.decodeCompactMetadataV1("[1,{\"kind\":16,\"name\":\"MeshService\",\"typeName\":\"MeshService\",\"classType\":{\"$tsf\":0},\"properties\":[],\"methods\":[{\"name\":\"registerBroadcastHandler\",\"parameters\":[{\"name\":\"type\",\"type\":{\"$tsfType\":2},\"optional\":false,\"default\":false},{\"name\":\"handler\",\"type\":{\"$tsfType\":3},\"optional\":false,\"default\":false}],\"returnType\":{\"$tsfType\":4}},{\"name\":\"setNodeCleanedUpCallback\",\"parameters\":[{\"name\":\"cb\",\"type\":{\"$tsfType\":5},\"optional\":false,\"default\":false}],\"returnType\":{\"$tsfType\":4}},{\"name\":\"setLeaseLostCallback\",\"parameters\":[{\"name\":\"cb\",\"type\":{\"$tsfType\":6},\"optional\":false,\"default\":false}],\"returnType\":{\"$tsfType\":4},\"description\":\"Fires once after renewal proves this instance is no longer a member.\"},{\"name\":\"assertLeaseSafe\",\"parameters\":[],\"returnType\":{\"$tsfType\":4},\"description\":\"Synchronously fences work once the last conservatively-known membership lease can no longer be valid.\"},{\"name\":\"fence\",\"parameters\":[{\"name\":\"reason\",\"type\":{\"kind\":16,\"typeName\":\"Error\",\"classType\":{\"$tsf\":1}},\"optional\":false,\"default\":false}],\"returnType\":{\"$tsfType\":7}},{\"name\":\"getNodes\",\"parameters\":[],\"returnType\":{\"$tsfType\":8}},{\"name\":\"getNode\",\"parameters\":[{\"name\":\"instanceId\",\"type\":{\"$tsfType\":9},\"optional\":false,\"default\":false}],\"returnType\":{\"$tsfType\":10}},{\"name\":\"updateNodeMetadata\",\"parameters\":[{\"name\":\"metadata\",\"type\":{\"$tsfType\":11},\"optional\":false,\"default\":false}],\"returnType\":{\"$tsfType\":7}},{\"name\":\"broadcast\",\"parameters\":[{\"name\":\"type\",\"type\":{\"$tsfType\":2},\"optional\":false,\"default\":false},{\"name\":\"data\",\"type\":{\"$tsfType\":12},\"optional\":false,\"default\":false},{\"name\":\"options\",\"type\":{\"$tsfType\":13},\"optional\":true,\"default\":false}],\"returnType\":{\"$tsfType\":7}},{\"name\":\"start\",\"parameters\":[],\"returnType\":{\"$tsfType\":7}},{\"name\":\"stop\",\"parameters\":[],\"returnType\":{\"$tsfType\":7}}],\"hasConstructor\":true,\"constructorParameters\":[{\"name\":\"key\",\"type\":{\"$tsfType\":0},\"optional\":false,\"default\":false},{\"name\":\"options\",\"type\":{\"$tsfType\":14},\"optional\":true,\"default\":false}]}]", [() => MeshService, () => (typeof Error !== "undefined" ? Error : (typeof exports !== "undefined" ? exports.Error : undefined))], __tsf_metadata_type);
}
exports.MeshService = MeshService;
_MeshServiceMetadata_1.classType = MeshService;
MeshService.__tsfType = _MeshServiceMetadata_1;
function createBroadcastGeneration(generation) {
    return {
        generation,
        abortController: new AbortController(),
        activeHandlerCount: 0,
        activeHandlerBytes: 0
    };
}
function validateMeshOptions(options) {
    const heartbeatIntervalMs = options?.heartbeatIntervalMs ?? 5000;
    const nodeTtlMs = options?.nodeTtlMs ?? 15000;
    const maxMessageBytes = options?.maxMessageBytes ?? 1024 * 1024;
    const maxActiveHandlers = options?.maxActiveHandlers ?? 4096;
    const maxActiveHandlerBytes = options?.maxActiveHandlerBytes ?? 64 * 1024 * 1024;
    const cleanupBatchSize = options?.cleanupBatchSize ?? 100;
    for (const [name, value] of [
        ['heartbeatIntervalMs', heartbeatIntervalMs],
        ['nodeTtlMs', nodeTtlMs],
        ['maxMessageBytes', maxMessageBytes],
        ['maxActiveHandlers', maxActiveHandlers],
        ['maxActiveHandlerBytes', maxActiveHandlerBytes],
        ['cleanupBatchSize', cleanupBatchSize]
    ]) {
        if (!Number.isSafeInteger(value) || value < 1)
            throw new Error(`MeshService ${name} must be a positive integer`);
    }
    if (heartbeatIntervalMs > nodeTtlMs) {
        throw new Error('MeshService heartbeat interval must not exceed the node TTL');
    }
    if (heartbeatIntervalMs > helpers_1.MAX_SAFE_TIMER_MS || nodeTtlMs > helpers_1.MAX_SAFE_TIMER_MS) {
        throw new Error('MeshService timer configuration exceeds the platform timer limit');
    }
    if (maxMessageBytes < 1024)
        throw new Error('MeshService maxMessageBytes must be at least 1024');
}
function isInstanceId(value) {
    return typeof value === 'number' && Number.isSafeInteger(value) && value > 0;
}
function isMessageType(value) {
    return typeof value === 'string' && value.length > 0 && value.length <= 256;
}
async function settleMeshCleanup(promise, timeoutMs) {
    await Promise.race([
        promise.then(() => undefined, () => undefined),
        new Promise(resolve => {
            const timer = setTimeout(resolve, timeoutMs);
            timer.unref?.();
        })
    ]);
}
function jsonByteLength(value) {
    const encoded = JSON.stringify(value);
    return encoded === undefined ? 0 : Buffer.byteLength(encoded);
}
exports.__tsfTypeAliases = _a.decodeCompactMetadataV1("[1,{\"MeshBroadcastMap\":{\"kind\":18,\"typeName\":\"Record\",\"utilityType\":\"Record\",\"typeArguments\":[{\"kind\":6},{\"kind\":2}],\"index\":{\"kind\":2},\"types\":[],\"typeName\":\"MeshBroadcastMap\"},\"MeshBroadcastOptions\":{\"kind\":18,\"typeName\":\"MeshBroadcastOptions\",\"types\":[{\"kind\":20,\"name\":\"skipSelf\",\"type\":{\"kind\":12,\"types\":[{\"kind\":8},{\"kind\":4}]},\"optional\":true}]},\"MeshHandlerContext\":{\"kind\":18,\"typeName\":\"MeshHandlerContext\",\"types\":[{\"kind\":20,\"name\":\"signal\",\"type\":{\"kind\":16,\"typeName\":\"AbortSignal\",\"classType\":{\"$tsf\":0}},\"optional\":false}]},\"MeshNode\":{\"kind\":18,\"typeName\":\"MeshNode\",\"types\":[{\"kind\":20,\"name\":\"instanceId\",\"type\":{\"kind\":7},\"optional\":false},{\"kind\":20,\"name\":\"hostname\",\"type\":{\"kind\":6},\"optional\":false},{\"kind\":20,\"name\":\"self\",\"type\":{\"kind\":8},\"optional\":false},{\"kind\":20,\"name\":\"processId\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"linkEndpointId\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"linkEndpointPublicKey\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"linkUrl\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"startedAt\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true}]},\"MeshServiceOptions\":{\"kind\":18,\"typeName\":\"MeshServiceOptions\",\"types\":[{\"kind\":20,\"name\":\"heartbeatIntervalMs\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"nodeTtlMs\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"leaderOptions\",\"type\":{\"kind\":12,\"types\":[{\"kind\":18,\"typeName\":\"LeaderServiceOptions\",\"types\":[{\"kind\":20,\"name\":\"ttlMs\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"renewalIntervalMs\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"retryDelayMs\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true}]},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"nodeMetadata\",\"type\":{\"kind\":12,\"types\":[{\"kind\":18,\"typeName\":\"Omit\",\"utilityType\":\"Omit\",\"typeArguments\":[{\"kind\":18,\"typeName\":\"MeshNode\",\"types\":[{\"kind\":20,\"name\":\"instanceId\",\"type\":{\"kind\":7},\"optional\":false},{\"kind\":20,\"name\":\"hostname\",\"type\":{\"kind\":6},\"optional\":false},{\"kind\":20,\"name\":\"self\",\"type\":{\"kind\":8},\"optional\":false},{\"kind\":20,\"name\":\"processId\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"linkEndpointId\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"linkEndpointPublicKey\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"linkUrl\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"startedAt\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true}]}],\"utilityKeys\":[\"instanceId\",\"hostname\",\"self\"],\"types\":[{\"kind\":20,\"name\":\"processId\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"linkEndpointId\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"linkEndpointPublicKey\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"linkUrl\",\"type\":{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"startedAt\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true}]},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"maxMessageBytes\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"maxActiveHandlers\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"maxActiveHandlerBytes\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"cleanupBatchSize\",\"type\":{\"kind\":12,\"types\":[{\"kind\":7},{\"kind\":4}]},\"optional\":true}]}}]", [() => (typeof AbortSignal !== "undefined" ? AbortSignal : (typeof exports !== "undefined" ? exports.AbortSignal : undefined))], __tsf_metadata_type);
//# sourceMappingURL=mesh.js.map