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
getActiveTransportsenableTransportdisableTransportisBluetoothEnabledrequestEnableBluetoothgetTopologysetBatteryLevelsetBatteryStategetBatteryLevelgetIsChargingsetRelayPrioritygetRelayPriorityupdateRelayConfiggetRelayConfigisRelaygetBLePeerCountgetBleDiagnosticsgetTransportMetricsforceTransportreleaseTransportLockupdateDorsConfiggetDorsConfigupdateAckConfigupdateRetryConfigupdateDedupConfiggetDedupStatsgetMeshRelayStatsgetMeshRelayTunablesgetPendingAckCountgetRetryQueueSizeshouldEscalateToWifiwifiDirectStatusChangedwifiDirectMessageReceivedwifiDirectGetNextMessagewifiDirectPeerConnectedwifiDirectPeerDisconnectedinternetStatusChangedinternetMessageReceivedinternetGetNextMessageinternetConfirmSentinternetSendFailedsendRawServerCommandisInternetReadyisInternetSupersededforceInternetReconnect
getActiveTransports
Gets the list of active transports returns: Array of active transport type namesenableTransport
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 disableisBluetoothEnabled
Checks if Bluetooth is enabled on the device returns: True if Bluetooth is enabled, false otherwiserequestEnableBluetooth
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 otherwisegetTopology
Gets the current network topology returns: Network topology snapshot including nodes, links, and stats throws: Error if topology retrieval failssetBatteryLevel
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. SeesetBatteryLevel 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 onegetIsCharging
Gets the last reported charging state (false if none reported).setRelayPriority
Sets the relay priority. A shorthand for updating onlyrelayPriority; 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 priorityupdateRelayConfig
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: seesetBatteryState.
getRelayConfig
Gets the current relay configuration.isRelay
Checks if this device is currently acting as a relay returns: True if device is a relaygetBLePeerCount
Gets the current number of discovered BLE peers returns: Number of BLE peers currently trackedgetBleDiagnostics
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.
getTransportMetrics
Gets detailed metrics for a specific transport returns: Transport metrics or null if not availableforceTransport
Forces the protocol to use a specific transport (overrides DORS) throws: Error if forcing failsreleaseTransportLock
Releases the transport lock and lets DORS make decisions againupdateDorsConfig
Updates DORS configuration at runtime. Omitted fields keep their current values: the same partial-update contract asupdateRelayConfig. 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 configurationupdateAckConfig
Updates ACK configuration at runtime throws: Error if update failsupdateRetryConfig
Updates retry configuration at runtime throws: Error if update failsupdateDedupConfig
Updates deduplication configuration at runtime throws: Error if update failsgetDedupStats
Gets deduplicator statistics for monitoring returns: Deduplication statisticsgetMeshRelayStats
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 isawaitingTransmission, 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 tocreate(): 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 ACKsgetRetryQueueSize
Gets the current retry queue size returns: Number of messages in retry queueshouldEscalateToWifi
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 recommendedwifiDirectStatusChanged
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 provedsenderId.
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 provedrecipientId; 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 unprovenpeerId 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 forpeerId 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 eitherinternetConfirmSent(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 WebSocketsend() 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 WebSocketsend() 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 gatesendRawServerCommand 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 questionisInternetReady 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:
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.

