Skip to main content
Import OfflineProtocol from @offline-protocol/mesh-sdk. These signatures match v0.27.0. Read the integration guide for prerequisites and complete usage. The native binding normally owns bridge callbacks such as wifiDirectMessageReceived and internetConfirmSent. Application integrations should use the binding transport configuration; call these low-level hooks only when implementing the corresponding bridge.

Methods on this page

getActiveTransports

Gets the list of active transports returns: Array of active transport type names

enableTransport

Enables a transport with optional configuration Re-enabling 'internet' is also the recovery from a relay supersede: it clears the transport’s latch, so any internet_session_superseded this instance is still holding for a late listener is dropped here. Held, it would tell an app with a freshly reconnected relay socket that it is connected elsewhere, with nothing to correct it. Mirrors the same discard on the native side. throws: Error if transport fails to enable

disableTransport

Disables a transport throws: Error if transport fails to disable

isBluetoothEnabled

Checks if Bluetooth is enabled on the device returns: True if Bluetooth is enabled, false otherwise

requestEnableBluetooth

Requests the user to enable Bluetooth On Android, this shows a system dialog to enable Bluetooth. On iOS, this returns false as iOS doesn’t allow programmatic Bluetooth enabling. returns: True if Bluetooth was enabled, false otherwise

getTopology

Gets the current network topology returns: Network topology snapshot including nodes, links, and stats throws: Error if topology retrieval fails

setBatteryLevel

Reports the device’s battery level to the protocol engine. This is the feed for every battery-dependent policy in the SDK: DORS energy scoring, relay promotion/demotion (relay_promoted / relay_demoted), the message-forwarding battery floor, and the telemetry device-capability snapshot. No transport can observe the host’s battery, so until this is called each of those policies runs in its unknown-level branch. Call it on start and on each platform battery notification. Prefer setBatteryState where charging state is available: a charging device is deliberately excused the soft relay battery floor, so reporting the level alone strips relay duty from plugged-in devices that should keep it.

setBatteryState

Reports the device’s battery level and charging state to the protocol engine. See setBatteryLevel for what depends on it.

getBatteryLevel

Gets the last reported battery level returns: Battery level (0-100) or null if the host has not reported one

getIsCharging

Gets the last reported charging state (false if none reported).

setRelayPriority

Sets the relay priority. A shorthand for updating only relayPriority; see updateRelayConfig for the rest. The legacy 'low' | 'medium' | 'high' spelling is still accepted and maps to never / auto / always. throws: Error if setting fails

getRelayPriority

Gets the current relay priority

updateRelayConfig

Updates the relay configuration at runtime. Governs whether this device carries other people’s traffic and under what conditions it takes the relay role. Applies to the next role evaluation and the next forwarding decision: no restart needed. Omitted fields keep their current values. The battery-dependent parts need a battery feed to do anything: see setBatteryState.

getRelayConfig

Gets the current relay configuration.

isRelay

Checks if this device is currently acting as a relay returns: True if device is a relay

getBLePeerCount

Gets the current number of discovered BLE peers returns: Number of BLE peers currently tracked

getBleDiagnostics

Gets the BLE diagnostic counters. These are the rollout alarm for the self-certifying-address migration. Each counter records a frame that took a degraded path rather than failing outright, so none of them show up as a delivery error: a fleet can be quietly falling back on every send while its success metrics look healthy. Read them together and watch the trend, not the absolute value: small counts are normal, sustained growth after a release means peers disagree about identity or MTU.
  • fragmentFallbacks: a frame for a directly-connected peer had to be broadcast to every peer instead of addressed to one. Rising means recipients are not being recognised as the connected peer they are.
  • recipientNotAmongPeers: a send named a peer that is connected over BLE but not under that id. This is the sharpest identity-mismatch signal: it is what a peer announcing one id while framing another looks like from the sender’s side.
  • undersizedMtuReports: a peer reported an MTU too small to carry a fragment header, so a conservative default was used.
All three read zero when BLE is not enabled or not yet started. returns: The three counters as of now

getTransportMetrics

Gets detailed metrics for a specific transport returns: Transport metrics or null if not available

forceTransport

Forces the protocol to use a specific transport (overrides DORS) throws: Error if forcing fails

releaseTransportLock

Releases the transport lock and lets DORS make decisions again

updateDorsConfig

Updates DORS configuration at runtime. Omitted fields keep their current values: the same partial-update contract as updateRelayConfig. Every field must therefore be expressible here: a field this signature omits cannot be set, and (before the bridges merged from the live config) was silently reset by any update that changed something else. throws: Error if update fails

getDorsConfig

Gets the current DORS configuration returns: DORS configuration

updateAckConfig

Updates ACK configuration at runtime throws: Error if update fails

updateRetryConfig

Updates retry configuration at runtime throws: Error if update fails

updateDedupConfig

Updates deduplication configuration at runtime throws: Error if update fails

getDedupStats

Gets deduplicator statistics for monitoring returns: Deduplication statistics

getMeshRelayStats

Reports how much traffic this device is carrying for other people. Counters are cumulative for the lifetime of this instance and never reset, so a rate is a difference between two reads. The exception is awaitingTransmission, a gauge that goes down as well as up. forwarded is the contribution figure to show a user; transmissions is the one the per-second budget bounds, since it counts each link separately and includes this device’s own sends. Two readings worth knowing: rateDeferred rising means forwarding is hitting its ceiling and those frames are delayed rather than dropped, and coveredByANeighbor is the mesh working as intended: a neighbor was heard carrying the frame first, so this device stood down. For whether back-pressure is actually costing anything, read refusedQueueFull and abandonedOverdue. Those are the two that count frames genuinely lost, and a device shedding traffic can otherwise show nothing but healthy-looking deferrals. Note that a device with a working relay connection forwards nothing: the mesh is only offered frames no other carrier can deliver. Zero counters on an online device are the honest answer, not a fault. returns: Cumulative mesh forwarding counters

getMeshRelayTunables

Reports the mesh forwarding tunables actually in force. Read from the governor in the Rust core, so this is what forwarding decisions really use rather than an echo of what was passed to create(): including every default this app never set. Every field is present. Nothing here needs a ?? fallback, and writing one would be inventing a second copy of a default that can drift. returns: The mesh forwarding tunables in force

getPendingAckCount

Gets the number of pending ACKs waiting for confirmation returns: Number of pending ACKs

getRetryQueueSize

Gets the current retry queue size returns: Number of messages in retry queue

shouldEscalateToWifi

Checks if DORS recommends escalating to WiFi. Use this to query whether the protocol should switch from BLE to WiFi Direct. returns: True if escalation to WiFi is recommended

wifiDirectStatusChanged

Notifies the protocol that the platform’s stream layer is up or down. Up means streams can be established, not that a peer is reachable. The slot counts as an available carrier only once a stream has proved a peer, and it queues a message only toward an address a stream has proved, so an up layer with no announced peer is not a carrier at all. Down clears every announced link.

wifiDirectMessageReceived

Hands the protocol one frame body that arrived on the stream whose preamble proved senderId. senderId is the address verifyIdentityAssertion derived from that stream’s first frame, and nothing else: the core attributes the body to it and matches Message.sender against it, so a body handed up under a socket address, a device name, or an address merely read from a discovery record is refused as unattributed. data is the body after the length prefix, exactly one message.

wifiDirectGetNextMessage

Gets the next outgoing body and the proved address of the stream to write it on. The caller frames it (u32 big-endian length, then the body) and writes it to the stream whose preamble proved recipientId; nothing is ever returned for an address no stream proved. returns: The body and its stream’s address, or null if the queue is empty

wifiDirectPeerConnected

Announces a stream whose preamble verified, under the address it proved. Call it once per announced stream with the derived address. An unproven peerId here is entered into the core’s capacity-bounded known_peers, evicting genuine neighbours, and starts an automatic key exchange toward a peer that cannot answer it, which is why nothing but the verifier’s result may be passed. A receiver holds one announced stream per address: a second stream proving an address already announced is refused or supersedes the first, and either way the core sees one announcement and, later, one loss.

wifiDirectPeerDisconnected

Reports that the announced stream for peerId ended. Only for a stream that was announced: a stream that never proved a peer has nothing to report, and reporting it would tell the core a peer it may still hold over another stream is gone.

internetStatusChanged

Notifies the protocol of internet connection state change.

internetMessageReceived

Handles an incoming internet message.

internetGetNextMessage

Gets the next outgoing internet message. After sending over the wire, you must call either internetConfirmSent(messageId) or internetSendFailed(messageId). returns: Message to send (with messageId) or null if queue is empty

internetConfirmSent

Confirms that a message was successfully sent over the wire (e.g., WebSocket). Call this after the WebSocket send() completes successfully. This feeds real delivery data into transport metrics for DORS routing.

internetSendFailed

Reports that a message failed to send over the wire. Call this when the WebSocket send() fails or the connection drops.

sendRawServerCommand

Sends a raw, caller-built relay command verbatim over the SDK’s internet socket: the generic server-command channel for relay features that are app concerns rather than SDK APIs (the invite-link lifecycle: CreateGroupInviteLink, JoinGroupViaInvite, AckGroupInviteJoin, …). Responses the SDK doesn’t consume arrive as internet_server_message events carrying the verbatim frame. GroupInfo and UserGroups are also emitted on that channel in addition to their stable typed events, so application-owned extension fields remain lossless. Correlate request/response with your own request_id where the relay supports one. Gate calls on isInternetReady() / the internet_status_changed event rather than probing with a command and retrying on false. For group-scoped commands (CreateGroupInviteLink, …) additionally await ensureGroupRegistered(groupId) first: the relay must know the group. Do not send frame types the SDK itself manages (SendMessage, CreateGroup / member deltas, LeaveGroup, CheckPresence, …): the SDK cannot correlate their answers with its own in-flight state, and a raw CreateGroup/LeaveGroup desyncs the bridge’s registration tracking. Use the typed SDK APIs for those. returns: true once the socket accepted the command (write-confirmed on iOS, enqueue-confirmed on Android: the closest OkHttp offers); false when not connected+authenticated, the JSON is invalid, or the SDK’s client-side rate limiter deferred it (the SDK’s mirror sits slightly under the relay’s 30-burst/10-per-second budget, at 28 burst / 9 per second: safe to retry after a short delay) throws: when the internet transport was never initialized (enable it via transports.internet before calling)

isInternetReady

Whether the SDK’s internet socket is connected AND relay-authenticated: the same gate sendRawServerCommand checks before writing. The positive replacement for app-side relayStatus === 'authenticated' tracking: gate raw sends on this (or on the internet_status_changed event) instead of probing with a command and retrying on false. Point-in-time; transitions arrive as internet_status_changed events. A ready socket can still defer an individual send (client-side rate limiter): sendRawServerCommand returning false while ready means retry after a short delay. Cannot tell you why it is false. An ordinary disconnect (which reconnects itself) and a relay displacement (which never will) both read false here: use isInternetSuperseded to tell them apart. returns: true when connected and authenticated; false otherwise, including when the internet transport was never initialized (never throws)

isInternetSuperseded

Whether the relay displaced this session, another device registered the same identity and took over the relay slot, and the SDK latched the internet transport stopped. This is the question isInternetReady structurally cannot answer. A false from it means “not usable right now” and nothing more: an ordinary disconnect reconnects itself within seconds, while a displaced session will never reconnect on its own, because a blind reconnect would just re-displace the other device in a loop. The two are indistinguishable from readiness alone. True here means the only recovery is a deliberate re-enable:
Complements the internet_session_superseded event rather than replacing it. The event tells an app that is listening at that instant; this answers an app that asks: including one that subscribed later, or whose process was killed and restarted, which no in-memory event hold survives. A foreground reconcile against this is the most robust shape. returns: true while the session is superseded; false otherwise, including when the internet transport was never initialized (never throws)

forceInternetReconnect

Forces an immediate teardown + reconnect + re-authenticate of the SDK’s internet socket, bypassing the exponential reconnect backoff. isInternetReady() is a point-in-time cached flag, not a liveness probe: an OS suspend can kill the TCP connection before a clean WebSocket close, so after a background→foreground transition the socket may be a zombie (dead but still reported ready) or alive-but-deregistered by the relay. Neither is detectable by a ping, and both are healed by the same action: a full reconnect that re-runs the relay authenticate/register handshake. You normally do NOT need to call this on foreground: as of the automatic foreground-heal, both native bridges (iOS applicationWillEnterForeground, Android onHostResume) already force a reconnect themselves after a background stay long enough to have killed the socket (~4s), gated on monotonic background duration: and iOS additionally tears down a zombie on the first stalled write via the write-stall watchdog. Calling this method in addition, on every foreground, would double-reconnect and drop a genuinely-healthy socket, forcing a wasted group re-registration round-trip. Keep it for the cases the automatic heal does not cover: a deliberate user-initiated “reconnect now”, or a stale socket you detect while already foregrounded (e.g. a long idle period with no background transition). If you do drive foreground recovery yourself, debounce and gate on background duration rather than calling on every foreground. Recovery lands in ~1s rather than waiting ~20-30s for zombie ping detection. Emits a transient internet_status_changed down→up. No-op unless the internet transport is running (respects the enable/disable lifecycle). returns: true once the request reached a live internet transport: this means “accepted”, not “reconnected”: it is also true when the transport is initialized but not currently running/starting, in which case the call is a deliberate no-op. false only when the internet transport was never initialized. Never throws.

Parameter and result types

Import these types from the same SDK package. Event payloads and configuration types are linked below.

TransportType

NetworkTopology

NetworkNode

NodeRole

NetworkStats

BleDiagnostics

TransportMetrics

DedupStats

MeshRelayStats

MeshRelayTunables