export = SubBridge; /** * Typedef Imports * @typedef {import("../client/Client")} Client * @typedef {import("../RestNio")} RestNio */ /** * @typedef SubBridgeOptions * @property {(string[]|'*'|null)} [out] - local sub channels whose frames flow * OUT to the peer link. `'*'` mirrors every channel currently in the * SubscriptionMap and any created later (greedy — see warning below). * @property {(string[]|'*'|null)} [in] - sub frames received FROM the peer that * we re-publish locally. `'*'` accepts any channel name. Channel names on the * wire ARE the names re-published locally; this side does not remap. * @property {string} [prefix] - applied to OUT channel names: local channel * `telem` is sent over the wire as `.telem`. Receiver re-publishes * under that prefixed name. Use to namespace per-source in a tree topology. * @property {boolean} [onDemand] - reserved for future ref-count-driven * subscribe/unsubscribe control. Currently a no-op (frames flow always for * configured channels). * * Wildcard warning: `out: '*'` forwards EVERY local sub channel including * internal/non-application ones. Only use in trusted topologies where you own * channel naming hygiene. Prefer explicit lists for safety. * * Echo prevention (v1 rule): a channel must be `out`-only or `in`-only on a * given bridge. Listing the same name in both throws; if you need a duplex * channel, use distinct names for the two directions. */ /** * @exports SubBridge * @class SubBridge * @author 7kasper * @classdesc * Bridges subscription pub/sub across a peer link. Attached to a single * peer-link {@link Client} (an outbound {@link InterClient} OR the inbound * {@link WebSocketClient} that mirrors a peer on the other end). Both sides of * the link configure their own bridge — direction is local-to-local, frames * cross the wire wrapped in `_type: 'sub.frame'` envelopes. * * Out flow (local emit → peer): * 1. Bridge subscribes a virtual subscriber to each local OUT channel. * 2. When `rnio.subs(channel).obj(payload)` is called locally, the virtual * subscriber's `.obj()` wraps the payload as * `{_type: 'sub.frame', channel: , payload}` and pushes it via * the peer-link client. * * In flow (peer emit → local): * 1. Peer-link's envelope dispatcher detects `_type: 'sub.frame'` and * routes it to this bridge. * 2. Bridge re-publishes the payload locally as * `rnio.subs(channel).obj(payload)`. * * Local emitters and local subscribers stay agnostic — they don't see the * bridge at all. Adding/removing a bridged peer is transparent. */ declare class SubBridge { /** * Construct via {@link Client#subBridge}, not directly. * @param {Client} client - the peer-link client this bridge is bound to. * @param {SubBridgeOptions} opts */ constructor(client: Client, opts?: SubBridgeOptions); client: import("../client/Client"); /** @type {RestNio} */ rnio: RestNio; prefix: string; onDemand: boolean; outAll: boolean; inAll: boolean; outList: Set; inList: Set; /** @type {Map} local channel name → virtual subscriber */ _outProxies: Map; _channelListener: (action: any, name: any) => void; /** * Inbound side — invoked by {@link InterClient}/{@link WebSocketClient} * when an envelope of type `sub.frame` arrives matching this bridge. * Re-publishes the payload on the local `channel`. * * Drops malformed frames silently (non-string `channel` or `undefined` * payload) instead of forwarding them. Without these guards a buggy or * malicious peer could publish `undefined` to local subs and crash any * downstream code that assumes a payload object, or pollute the * `SubscriptionMap` keyspace by passing a non-string channel. * * @param {string} channel * @param {*} payload */ handleInFrame(channel: string, payload: any): void; /** * Whether this bridge accepts inbound frames on `channel`. * @param {string} channel * @returns {boolean} */ acceptsIn(channel: string): boolean; /** * Tear down: unsubscribe all virtual proxies and detach wildcard listener. */ teardown(): void; /** * Subscribe a virtual proxy to local channel `name` so emitted frames * flow over the peer link. * * Communication methods supported on the proxy (mirroring `ClientSet`): * - `obj`, `str`, `json` — forwarded as `sub.frame` envelopes with the * value as `payload`. Receiver re-publishes via `subs(channel).obj(payload)`. * - `bin` / `buf` — NOT supported. The `sub.frame` envelope is * JSON-encoded on the wire, so a binary payload would be lossy. A warn * is logged once per bridge so missed binary fan-outs are visible. * Wire your own binary-frame transport if needed (see the wiki). * - `err`, `ok`, `close` — no-op. Connection-level semantics that don't * map to channel-data fan-out. * * @param {string} name - local sub channel name. */ _wireOut(name: string): void; } declare namespace SubBridge { export { Client, RestNio, SubBridgeOptions }; } /** * Typedef Imports */ type Client = import("../client/Client"); /** * Typedef Imports */ type RestNio = import("../RestNio"); type SubBridgeOptions = { /** * - local sub channels whose frames flow * OUT to the peer link. `'*'` mirrors every channel currently in the * SubscriptionMap and any created later (greedy — see warning below). */ out?: (string[] | "*" | null); /** * - sub frames received FROM the peer that * we re-publish locally. `'*'` accepts any channel name. Channel names on the * wire ARE the names re-published locally; this side does not remap. */ in?: (string[] | "*" | null); /** * - applied to OUT channel names: local channel * `telem` is sent over the wire as `.telem`. Receiver re-publishes * under that prefixed name. Use to namespace per-source in a tree topology. */ prefix?: string; /** * - reserved for future ref-count-driven * subscribe/unsubscribe control. Currently a no-op (frames flow always for * configured channels). * * Wildcard warning: `out: '*'` forwards EVERY local sub channel including * internal/non-application ones. Only use in trusted topologies where you own * channel naming hygiene. Prefer explicit lists for safety. * * Echo prevention (v1 rule): a channel must be `out`-only or `in`-only on a * given bridge. Listing the same name in both throws; if you need a duplex * channel, use distinct names for the two directions. */ onDemand?: boolean; };