reticulum-js
    Preparing search index...

    Class LXMRouter

    Handles LXMF routing and message processing.

    LXMF Router for managing incoming and outgoing messages

    Hierarchy

    • EventTarget
      • LXMRouter
    Index
    • Creates an LXMF router bound to the given identity and Reticulum instance.

      Parameters

      • identity: Identity
      • rnsCore: Reticulum

        The Reticulum instance

      • Optionaloptions: { stampEngine?: StamperEngine } = {}
        • OptionalstampEngine?: StamperEngine

          Optional proof-of-work stamp engine to install process-wide (work doc #45). The engine swap is global: it replaces the WebCrypto default for every stamp operation in the process (message stamp generation, propagation blob validation, peering), which is what a busy propagation node or heavy sender wants. Platform packages ship ready-made engines — e.g. nodeStamper from @reticulum/node — and omitting the option keeps the browser-safe WebCrypto default.

      Returns LXMRouter

    _lastProcessedPrune: number

    Epoch seconds of the last lazy processed-id prune (0 = due immediately).

    _peerSyncRunning: boolean

    True while a syncPeers pass is running; overlapping passes skip.

    attachedLinks: Set<any>
    autopeerEnabled: boolean
    autopeerMaxDepth: number

    Maximum announce hop count a node is auto-peered at (Python AUTOPEER_MAXDEPTH).

    autopeerMaxPeeringCost: number
    deliveryDest: Destination | null
    deliveryPerTransferLimit: number

    Client per-transfer download limit (KB) advertised in /get requests.

    directLinks: Map<string, Link>
    displayName: string | null
    identifiedLinks: Set<any>
    identity: Identity
    locallyDeliveredMessageIds: Map<string, number>
    maxPeers: number

    Cap on peered propagation nodes (Python LXMRouter.MAX_PEERS, lxmd default 20). Peering beyond the cap is refused; rotatePeers makes headroom by dropping the least-useful peers.

    outboundPropagationLink: Link | null
    outboundPropagationNode: Uint8Array<ArrayBufferLike> | null
    peers: Map<string, LXMPeer>
    pendingLinks: Map<any, any>
    pendingMessages: Map<
        string,
        {
            linkId: Uint8Array<ArrayBufferLike>
            | null;
            sourceHash: Uint8Array;
            wireData: Uint8Array;
        }[],
    >

    Messages parked while their sender's identity is unknown, keyed by hex(link_id) (or "opportunistic") → bucket of parked wire buffers. A link's bucket is dropped when the link closes (LINKIDENTIFY can never arrive on a dead link), re-processed when the link identifies or an announce lands, and the total is capped at MAX_PARKED_MESSAGES so unknown-sender floods cannot pin memory.

    processedTransientIds: Map<string, number>
    propagationDest: Destination | null
    propagationNode: PropagationNode | null
    rns: Reticulum
    stampCost: number | null
    staticPeers: Set<string>

    Peered node destination hashes protected from rotation and culling (Python static_peers).

    • The addEventListener() method of the EventTarget interface sets up a function that will be called whenever the specified event is delivered to the target.

      MDN Reference

      Parameters

      • type: string
      • callback: EventListenerOrEventListenerObject | null
      • Optionaloptions: boolean | AddEventListenerOptions

      Returns void

    • Announces the lxmf.delivery destination with the given display name.

      Builds the §4.3 msgpack app_data ([name(bin8), stamp_cost, [SF_COMPRESSION]]) and attaches it to the identity so Destination.announce signs it as part of the announce body.

      Parameters

      • displayName: string

        Human-readable node name shown to peers.

      • OptionalstampCost: number | null = null

        Active stamp cost (1-254), or null to advertise stamping as disabled.

      Returns Promise<void>

    • The dispatchEvent() method of the EventTarget sends an Event to the object, (synchronously) invoking the affected event listeners in the appropriate order. The normal event processing rules (including the capturing and optional bubbling phase) also apply to events dispatched manually with dispatchEvent().

      MDN Reference

      Parameters

      • event: Event

      Returns boolean

    • Enables autopeering (matching the Python reference's lxmd autopeer): when a lxmf.propagation announce is heard whose advertised peering cost is ≤ maxPeeringCost, a peering relationship is established automatically. Requires enablePropagation (this node must itself be a propagation node to peer).

      Parameters

      • OptionalmaxPeeringCost: number = MAX_PEERING_COST

        Max advertised peering cost to auto-peer at (default MAX_PEERING_COST).

      • Optionaloptions: {
            autopeerMaxDepth?: number;
            maxPeers?: number;
            staticPeers?: Uint8Array<ArrayBufferLike>[];
        } = {}
        • OptionalautopeerMaxDepth?: number

          Max announce hop count to auto-peer at (default AUTOPEER_MAXDEPTH).

        • OptionalmaxPeers?: number

          Override the peer-table cap (default MAX_PEERS).

        • OptionalstaticPeers?: Uint8Array<ArrayBufferLike>[]

          Peered destination hashes protected from rotation and culling (Python static_peers).

      Returns void

    • Enables the propagation-node role (§5.3): creates the lxmf.propagation destination, registers the /get message-download handler, and ingests submitted messages received via link Resources.

      The node stores propagated messages addressed to other identities and serves them to clients over /get; messages addressed to this router's own delivery identity are locally delivered (decrypted + dispatched as a message event). Returns the PropagationNode for direct access (e.g. inspecting PropagationNode.store).

      Call announcePropagationNode afterwards to broadcast the node.

      Parameters

      • Optionaloptions: PropagationNodeOptions = {}

      Returns Promise<PropagationNode>

    • Whether a message with this message id has already been delivered to local handlers, no matter which path it arrived on (matching the Python reference, keyed by message hash).

      Parameters

      • messageId: Uint8Array<ArrayBufferLike>

        SHA-256 of the signed part (§5.5).

      Returns boolean

    • Ingests a paper message delivered as an lxm:// URI (LXMRouter.ingest_lxm_uri).

      The URI body is base64-decoded into the paper payload, de-duplicated by its transient_id (so re-ingesting the same QR/URI is a no-op), decrypted with the local lxmf.delivery destination, and dispatched through the same message event path as a network-delivered message. Paper messages always disable stamp enforcement (LXMRouter.lxmf_propagation is_paper_message).

      The sender's signature is verified when their identity is already known (recalled from a prior announce); otherwise the message is still delivered with an unverified signature, exactly like the Python reference.

      Parameters

      • uri: string

        The lxm:// paper message URI.

      Returns Promise<LXMessage | null>

      The reconstructed message, or null when the URI is not addressed to this node (decryption fails) or was already ingested.

    • Initializes the router and registers the LXMF delivery destination.

      Returns Promise<void>

    • Establishes (or updates) a peering relationship with another propagation node (LXMRouter.peer). The peer's advertised limits and costs are read from its app_data; messages this node stores are then offered to it on the next syncPeers.

      Parameters

      • destinationHash: Uint8Array<ArrayBufferLike>

        Peer's lxmf.propagation hash.

      • config: {
            metadata?: Map<number, Uint8Array<ArrayBufferLike>> | null;
            peeringCost: number;
            perSyncLimitKb?: number | null;
            perTransferLimitKb?: number | null;
            stampCost: number;
            stampCostFlexibility: number;
        }
        • Optionalmetadata?: Map<number, Uint8Array<ArrayBufferLike>> | null

          Node metadata map.

        • peeringCost: number

          Peer's peering cost (≤ MAX_PEERING_COST).

        • OptionalperSyncLimitKb?: number | null

          Per-sync cumulative limit.

        • OptionalperTransferLimitKb?: number | null

          Per-message transfer limit.

        • stampCost: number

          Peer's propagation stamp cost.

        • stampCostFlexibility: number

          Peer's stamp cost flexibility.

      Returns LXMPeer | null

      the peer, or null if peering was rejected.

    • Re-processes every parked message whose sender identity may now be known (typically called after a just-validated announce made a previously- unknown identity available — first-contact opportunistic delivery).

      Each entry is fed back through _processIncomingMessage: if the identity is still unknown it is re-parked (without re-requesting the path, guarded by alreadyParked), otherwise it is verified and dispatched. Safe and cheap to call when nothing is parked.

      Returns Promise<void>

    • Call this when a new Identity is cached (e.g., in your IDENTIFY handler). It checks if any parked messages are now ready for processing.

      Pass null to re-process an opportunistic (linkless) parked message.

      Parameters

      • linkId: Uint8Array<ArrayBufferLike> | null

      Returns Promise<void>

    • The removeEventListener() method of the EventTarget interface removes an event listener previously registered with EventTarget.addEventListener() from the target. The event listener to be removed is identified using a combination of the event type, the event listener function itself, and various optional options that may affect the matching process; see Matching event listeners for removal.

      MDN Reference

      Parameters

      • type: string
      • callback: EventListenerOrEventListenerObject | null
      • Optionaloptions: boolean | EventListenerOptions

      Returns void

    • Peer rotation (Python LXMRouter.rotate_peers): when the peer table is at or over maxPeers, drop just enough of the least-useful peers to restore ROTATION_HEADROOM_PCT headroom. Candidates are non-static, IDLE peers: unreachable ones first, then peers that have been offered messages but accepted none at a rate below ROTATION_AR_MAX. Peers with nothing offered yet are spared, as are static peers and peers still mid-sync.

      Returns number

      count of peers dropped.

    • Serializes and sends an LXMF message.

      Delivery method mirrors the Python reference with automated fallback:

      • a provided linkId is reused (DIRECT over an existing link);
      • otherwise a DIRECT link to the recipient is established (and cached);
      • if DIRECT link fails or cannot be established, escalates according to fallback ("opportunistic" -> "propagation" -> "none").

      On a link this initiates, LINKIDENTIFY is sent once before the message DATA (Python LXMF otherwise drops packets that arrive before identify), and the link is wired to receive replies (backchannel).

      Parameters

      • message: LXMessage
      • senderIdentity: Identity
      • OptionaloptionsOrLinkId:
            | Uint8Array<ArrayBufferLike>
            | {
                fallback?: "opportunistic" | "propagation" | "none";
                linkId?: Uint8Array<ArrayBufferLike> | null;
                solicit?: boolean;
                timeoutMs?: number;
            }
            | null = {}

      Returns Promise<void>

    • Sets the propagation node to submit messages to and sync from, by its lxmf.propagation destination hash. The node's identity/app_data must be learned from an announce before submit/sync can run.

      Parameters

      • destinationHash: Uint8Array<ArrayBufferLike>

      Returns void

    • Starts periodic re-announcement of the lxmf.delivery destination (PROTOCOL-SPEC.md §9.7) so cached mesh paths stay fresh and peers can reach you after transit-relay TTLs lapse.

      Sets the announce app_data from displayName/stampCost (so every periodic announce advertises the same name), then delegates to Destination.startAnnouncing on the delivery destination — which fires the first announce immediately and repeats every intervalMs.

      This replaces the one-shot announce for the common "announce and keep announcing" case. Call stopAnnouncing to halt the loop.

      Parameters

      • displayName: string

        Human-readable node name shown to peers.

      • Optionaloptions: { intervalMs?: number; stampCost?: number | null } = {}
        • OptionalintervalMs?: number

          Override the default cadence (clamped to the §9.7 60 s floor).

        • OptionalstampCost?: number | null

          Active stamp cost (1-254), or null to advertise stamping as disabled.

      Returns Promise<void>

    • Submits a message to the configured propagation node for store-and-forward delivery (LXMF.md §5.8 / LXMessage PROPAGATED).

      Packs the message into propagation form (dest_hash ‖ E(src‖sig‖payload), §5.3), appends a propagation stamp meeting the node's advertised cost, and sends the msgpack([time, [lxmf_data]]) container to the node as a Link Resource. The node stores it until the recipient syncs.

      Parameters

      • message: LXMessage
      • senderIdentity: Identity
      • Optionaloptions: { stampCost?: number } = {}

        Override the stamp cost (defaults to the node's advertised cost, then PROPAGATION_COST).

      Returns Promise<{ stampCost: number; transientId: Uint8Array }>

    • Downloads messages addressed to identity from the configured propagation node (LXMRouter.request_messages_from_propagation_node).

      Drives the /get exchange: list available transient_ids, request those not already held, decrypt + dispatch each, then ack so the node purges them. Resolves with counts of received / duplicate messages.

      Parameters

      • identity: Identity

        The recipient identity to identify as (so the node serves our messages).

      • OptionalmaxMessages: number = ALL_MESSAGES

        Cap on messages fetched.

      Returns Promise<{ duplicates: number; received: number }>

    • Runs one outbound sync pass against every peered node. Resolves when all peers have completed (or postponed) their sync.

      Overlapping passes skip: drivers call this on an interval, and a pass can legitimately outlive one interval (a slow transfer, a backlog of peers). Running two passes concurrently would sync the same peer over two links at once — the second pass is a no-op instead.

      Returns Promise<void>

    • Periodic router maintenance (the Python reference's jobs-loop cleanup): prunes aged entries from the processed-transient-id dedup map. A runner calls this on its maintenance interval; the insert path also prunes lazily, so calling this is an optimization, not a requirement.

      Returns { processed: number }

      count of pruned processed-id entries.

    • Breaks a peering relationship (LXMRouter.unpeer).

      Parameters

      • destinationHash: Uint8Array<ArrayBufferLike>

      Returns void