reticulum-js
    Preparing search index...

    Class RFedNode

    A rfed federation node.

    After start, the node owns its destinations, validates and stores inbound SENDs, fans out to present subscribers, defers for absent ones, and serves /rfed/pull. Call stop to detach the announce listener.

    Index
    _announceListener: ((event: any) => void) | null
    _backupTickRunning: boolean

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

    _nodeDest: Destination | null
    _notifyDest: Destination | null
    _notifyRegisterDest: Destination | null
    _notifyUnregisterDest: Destination | null
    _publishDest: Destination | null
    _pullDest: Destination | null
    _rfedNodeNameHash: Uint8Array<ArrayBufferLike> | null
    _started: boolean
    _subscribeDest: Destination | null
    _syncPeersRunning: boolean

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

    _unsubscribeDest: Destination | null
    blobStore: BlobStore
    blobTtlSecs: number
    deferred: DeferredQueue
    deferredQueueLimit: number
    deferredTtlSecs: number
    fedSync: FedSync

    Federation sync engine (SPEC §4). Tracks peers and schedules sync attempts.

    identity: Identity
    inboundPublishes: Map<any, any>

    hex(resource hash) → in-flight inbound publish transfers.

    maxInboundPublishes: number

    Cap on concurrent inbound publish Resource transfers. Oversized publishes arriving beyond the cap are refused with RESOURCE_RCL at advertisement; single-packet publishes are unaffected.

    maxPublishBytes: number

    Cap on a single inbound publish Resource (bytes) for unidentified or untrusted publishers — bounds what one publisher can pin in transfer buffers. Trusted peers keep the core's default ceiling.

    name: string
    notifyRegistry: NotifyRegistry
    ownerOfflineSecs: number
    policyFor: (subscriberHash: Uint8Array) => { deferredQueueLimit: number }

    Per-subscriber policy lookup (mirrors Rust NodeConfig::policy_for). Defaults to the flat configured limits; a runner overrides this to drive VIP tiers from real config. Used today for the per-subscriber deferred queue cap.

    presenceTtlSec: number
    primaryNode: Uint8Array<ArrayBufferLike> | null
    pullPageSize: number
    rns: any
    secondaryNodes: Uint8Array<ArrayBufferLike>[]
    stampCost: number | null
    stampFlexibility: number
    stampThrottleSecs: number

    Throttle window (seconds) for identified publishers whose publish failed stamp validation.

    subscriptions: SubscriptionTable
    syncBytesSent: number

    Bytes served by /rfed/get in the current budget period.

    syncLimitBytes: number
    syncPeriodStart: number

    Start of the current budget period (ms).

    throttledPublishers: Map<any, any>

    hex(identityHash) → throttle-until epoch seconds (stamp offenders).

    transferLimitBytes: number
    trustedBackupPeers: Uint8Array<ArrayBufferLike>[]

    If non-empty, only accept /rfed/backup/push from these owner hashes.

    trustedPublishers: Set<string>

    Publisher identity hashes (hex) bypassing the admission gates (the LXMF staticPeerHashes lever, keyed by identity — publishers have no single canonical destination to derive a hash from).

    • get nodeHash(): Uint8Array<ArrayBufferLike> | null

      The rfed.node destination hash (the canonical node identifier).

      Returns Uint8Array<ArrayBufferLike> | null

    • Sends a §9.3 notify wake packet to a registered relay's rfed.notify destination. Fire-and-forget: failures are logged and swallowed (the subscriber still gets the blob via deferred pull / live fanout later). The relay identity must be recallable (it was remembered at registration).

      Parameters

      • reg: { relayHash: string }
      • parts: {
            channel?: Uint8Array<ArrayBufferLike> | null;
            receiver: Uint8Array;
            sender?: Uint8Array<ArrayBufferLike> | null;
        }

      Returns Promise<void>

    • Live-delivers everything queued for a subscriber (FIFO), then the bucket is empty for future /rfed/pull / fanout. Backup entries have no identity and are pull-served, so a null identity here is a no-op.

      Parameters

      • sub: { identity: Identity | null; subscriberHash: Uint8Array }

      Returns Promise<void>

    • Fans a blob out to every subscriber of channelHash. Present subscribers (their rfed.delivery announced within the TTL) receive it immediately; absent subscribers get it enqueued in the deferred queue.

      Parameters

      • channelHash: Uint8Array<ArrayBufferLike>
      • innerBlob: Uint8Array<ArrayBufferLike>

      Returns Promise<void>

    • /rfed/backup/push (SPEC §11) — an owner node replicates its (subscriber_hash, channel_hash) pairs to this backup. The payload is the shared signed [value, pubkey, sig] form where value is the msgpack of [[sub_hash, ch_hash], …]; the owner identity is derived from pubkey and its rfed.node hash tags the resulting backup subscriptions. Replies true on success, false on any verification/trust failure. Mirrors Rust backup_push_cb.

      Parameters

      • data: any

      Returns Promise<boolean>

    • /rfed/get (SPEC §3/§4) — encodes the requested blobs into the §3 stream ch(16)‖id(16)‖len(4 BE)‖blob, stopping once transferLimitBytes would be exceeded (per-response cap) or the hour's syncLimitBytes budget is spent. The responder is never uncapped. Returns the raw stream bytes; the Link wraps them in a msgpack Binary for transit (Rust handle_message_get).

      Blobs transit stamp-stripped; no stamp validation here.

      Parameters

      • data: any

        Decoded msgpack [id, …].

      Returns Uint8Array<ArrayBufferLike>

    • /rfed/notify/clear — removes ALL relay registrations for the caller (every channel + LXMF). Served on legacy rfed.notify only.

      Parameters

      • data: any

      Returns Promise<boolean>

    • /rfed/notify/register (SPEC §9.1) — verifies the signed command, validates the relay hash, remembers the relay identity (so we can later route a wake to it), issues a path request, and records the registration.

      Parameters

      • data: any

      Returns Promise<boolean>

    • /rfed/notify/unregister — removes one (subscriber, channel, relay) registration.

      Parameters

      • data: any

      Returns Promise<boolean>

    • /rfed/offer (SPEC §4) — returns the node's full store manifest as [[channelHash, messageId], …] so the caller can compute its gap. (Rust handle_offer; the caller's offered IDs are accepted but unused.)

      Returns [Uint8Array<ArrayBufferLike>, Uint8Array<ArrayBufferLike>][]

    • /rfed/pull — drains one page of the caller's deferred queue for the requested channel. Caller is authenticated by the identified link.

      An unidentified caller gets ERROR_NO_IDENTITY (0xF0) and a malformed payload gets ERROR_INVALID_DATA (0xF4) — bare msgpack integers, exactly as the reference rfed emits them. Never answer silence or a fabricated empty page: the client distinguishes refusal from success by msgpack type.

      Parameters

      • data: any

        bin(16) channel hash.

      • caller: Identity | null

      Returns Promise<
          | number
          | [[Uint8Array<ArrayBufferLike>, Uint8Array<ArrayBufferLike>][], boolean],
      >

    • Ingests a published SEND payload (both the fire-and-forget DATA path and the oversized Resource path land here): validate the stamp (when configured), store the blob, and fan out / defer to subscribers.

      Parameters

      • data: Uint8Array<ArrayBufferLike>

      Returns Promise<{ ok: boolean; reason?: "stamp" | "malformed" }>

    • /rfed/subscribe — verifies the signed [channel_hash, pubkey, sig] payload, records the subscription, replies [true, stamp_cost|nil].

      Parameters

      • data: any

      Returns Promise<[boolean, number | null]>

    • /rfed/unsubscribe — verifies the signed payload, drops the subscription.

      Parameters

      • data: any

      Returns Promise<boolean>

    • Stores the blob (sync-side) and dispatches it to subscribers: live fanout for present subscribers, deferred queue for the rest.

      Parameters

      • channelHash: Uint8Array<ArrayBufferLike>
      • innerBlob: Uint8Array<ArrayBufferLike>

      Returns Promise<void>

    • Transport "announce" handler: records the destination as present and, if it is a subscriber's rfed.delivery, drains that subscriber's deferred queue and live-delivers (SPEC §7 trigger 1).

      Parameters

      • event: any

      Returns Promise<void>

    • Builds and sends an outbound DATA packet to a subscriber's rfed.delivery.

      Parameters

      • subscriberIdentity: Identity
      • payload: Uint8Array<ArrayBufferLike>

        [ channel_hash ‖ inner_blob ].

      Returns Promise<void>

    • Internal sync implementation without peer tracking side-effects.

      Parameters

      • peerNodeHash: Uint8Array<ArrayBufferLike>

      Returns Promise<number>

    • Announces rfed.node (with stamp-cost app_data) and the four service destinations so clients can discover and path-request them.

      Returns Promise<void>

    • Whether a subscriber's rfed.delivery has been heard from within the TTL. Exposed so callers (and tests) can inspect reachability before acting.

      Parameters

      • deliveryHash: Uint8Array<ArrayBufferLike>

      Returns boolean

    • Brings up the five inbound destinations, registers the request/Send handlers, binds the announce listener, and announces rfed.node + the service destinations so clients can path-request them.

      Returns Promise<void>

    • Detaches the announce listener.

      Returns void

    • Syncs with all federation peers that are due for sync. Matches LXMF router's syncPeers() API pattern.

      Called periodically by the runner (e.g., every 10-60 seconds).

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

      Returns Promise<number>

      Total number of blobs ingested from all peers

    • Synchronises with a peer rfed.node: OFFER (our held IDs) → receive the peer's manifest → compute the gap (channels we subscribe to, don't hold) → MESSAGE_GET the missing blobs → ingest each (store under the upstream id, then fan out to local subscribers). Mirrors Rust run_sync_session.

      Returns the number of newly-ingested blobs. Throws if the peer identity cannot be recalled or the link fails.

      Parameters

      • peerNodeHash: Uint8Array<ArrayBufferLike>

        The peer's rfed.node destination hash.

      Returns Promise<number>

    • Backup-failover tick (SPEC §11) — a runner calls this every BACKUP_TICK_SECS seconds (30s). Three tasks:

      1. Push own subscriptions: drain {@link _pendingBackupPushes} and forward to ONE resolved backup node.
      2. Prune stale backup entries (chain unravel; TTL = max(ownerOfflineSecs × 2, 90)).
      3. Failover: for each held backup whose owner has gone silent, dump the channel backlog into the deferred queue + fire notify wakes, and re-push adopted entries to our own backup (chain of custody).

      Mirrors Rust tick_backup_delivery. Auto-selection from federation peers (Rust priority 5) is not implemented — only configured primaryNode / secondaryNodes are used.

      Returns Promise<{ adopted: number; pruned: number; pushed: number; repushed: number }>

    • Periodic maintenance — a runner calls this hourly (SPEC §5/§7). Prunes expired blobs (30-day TTL) and deferred-queue entries (7-day TTL) and evicts blob-store overflow to the capacity limit.

      Returns { blobsEvicted: number; deferredEvicted: number }