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.

Methods on this page

initializeMlsWithSecureStorage

Initializes MLS with built-in secure storage. Uses iOS Keychain or Android EncryptedSharedPreferences. Note: This is called automatically by start() when encryption.enabled is true (default). You only need to call this manually if you disabled encryption initially and want to enable it later. throws: Error if initialization fails

isMlsInitialized

Checks if MLS is initialized. returns: True if MLS is ready for use

getIdentityPublicKey

Gets the identity public key (Ed25519, 32 bytes). This is the public key derived from the MLS credential and can be shared with others for identity verification and secure communication. returns: The public key as an array of bytes throws: Error if MLS is not initialized

deriveAddress

Derives the canonical self-certifying address of an Ed25519 identity key: off1… (44 characters), the bech32m encoding of 0x01 || SHA-256(publicKey)[0:20]. The address is a hash of the key, so it authenticates itself: a peer claiming an address is checked by re-deriving it from the key they present. The same key always yields the same address, and every address has exactly one valid string form. Needs no protocol instance: safe to call before create(), e.g. to verify an invite or QR code. returns: The derived off1… address throws: If publicKey is not 32 bytes

parseInvite

Decodes and verifies an invite blob. Needs no protocol instance: safe to call before create(), which is the whole point: a scanner verifies a QR code before deciding to act on it. Verification is mandatory and total. The address must be the one its public key derives to, and any signature present must verify under that key, so a resolved InviteInfo is always self-certified. What it does not prove: that the invite came from who you think. An attacker’s own correctly-signed invite is indistinguishable from a legitimate stranger’s: only the out-of-band context (this QR was on this person’s screen) carries that. returns: The verified invite throws: If the blob is malformed, the address is not the key’s, or a signature does not verify. Every case means refuse, not warn.

createInvite

Builds an invite blob for this identity. The result is opaque base64url. Apps own the container; the recommended form is one parameter, <app-scheme>://connect?c=<blob>, so it composes with an existing scheme and route. Sign it when the invite may travel without its issuer, a link forwarded through a third party, because the signature binds the petname to the key, so a forwarded invite cannot save Alice’s key under the name “Bob”. Leave it unsigned for a QR shown phone to phone: the physical channel already authenticates it, and an app that lets the user confirm the name has made the user the authority over it. Signing costs about 90 characters. Carries no key package by design (an MLS init key is single-use and a QR code is static, so pairing them guarantees a collision as soon as two people scan the same code) and no expiry (a printed QR that stops working is a bug).

resolveUsername

Returns true if this call started the lookup, false if one was already running; exactly one username_resolved follows either way. Requires transports.nostr.usernameDiscoveryEnabled. Resolves true if this call started the lookup and false if it joined one already in flight. Both mean an answer is coming: exactly one username_resolved event follows either way, so awaiting that event after either result is safe. Every case where no event will ever arrive rejects instead, so a false can never leave a spinner running forever. The rejection code says which, and they call for different handling:
  • InvalidConfiguration: discovery is off (it also requires coldContactEnabled). Retrying unchanged can never succeed.
  • InvalidState: too many lookups in flight. Transient; retry shortly.
  • NotStarted: the protocol is not running, so nothing would pump relay traffic or sweep the deadline for this lookup. Transient; retry after start().
  • InvalidArgument: not a claimable username (empty, over 64 bytes once normalized, carrying a control or format character, or address-shaped).
Subscribe to username_resolved before calling this. The answer is a single event with no replay, so a listener attached afterwards can miss it. The answer carries every verified claim. There is deliberately no “best” claim and no ordering: anyone may publish any name, so what comes back is a set of assertions for a human to arbitrate, not a lookup result. Do not auto-select. Taking the first entry turns a non-authoritative directory into an authoritative-looking one: the user then believes the name was verified when only a key ever was. Present the claims, have the user confirm out of band, and store the address, never the name: a name can be re-claimed by anyone tomorrow, an address is self-certifying. returns: true if this call started the lookup, false if it joined one throws: InvalidConfiguration if discovery is off, InvalidState if too many lookups are in flight, NotStarted if the protocol is not running, InvalidArgument if the name is not claimable

localAddress

This device’s own address (off1…), or null before startup completes. Derived from the identity key held in this profile’s storage: the app does not choose it, and it is stable across restarts of the same profile. This is the string to show the user, put in an invite or QR code, and what peers pass as the recipient to reach this device. null until MLS is initialized (which start() does), because the key that defines it lives in storage that is not open before then. The identity_ready event carries the same value at the moment it is known.

deriveUserIdFromPublicKey

Derives a deterministic user ID from a public key. deprecated: Use deriveAddress. This returns the same off1… address, but requires an initialized protocol instance and accepts any input length rather than rejecting keys that are not 32 bytes. returns: The derived address string

signData

Signs arbitrary data with the identity private key (Ed25519). Use this to prove ownership of your identity or to sign messages. returns: The signature as an array of bytes (64 bytes) throws: Error if MLS is not initialized

verifySignature

Verifies a signature against a public key. Use this to verify that data was signed by the owner of a public key. returns: True if the signature is valid throws: Error if verification fails due to invalid input

mlsGenerateKeyPackage

Generates a new MLS key package. Key packages are used by others to establish encrypted sessions with you. returns: Generated key package throws: Error if generation fails

mlsGetOrCreateKeyPackage

Gets an existing key package or creates a new one. returns: Key package throws: Error if operation fails

mlsGetPendingKeyPackages

Gets pending key packages that haven’t been synced yet. returns: Array of pending key packages

mlsMarkKeyPackageSynced

Marks a key package as synced. throws: Error if operation fails

mlsImportKeyPackage

Imports another user’s key package. Required before you can send encrypted messages to them. throws: Error if import fails

mlsHasSession

Checks if an MLS session exists with another user. returns: True if session exists

hasPendingKeyPackage

Checks if a pending key package is available for a peer. Key packages are received automatically when peers are discovered (if auto_key_exchange is enabled). This method checks if we have received the peer’s key package and can establish a session. returns: True if key package is available

getEstablishmentState

Returns the current secure-session establishment state for a peer. Useful for retry/UI flows when operations fail with SessionNotReady.

establishSecureSession

Establishes a secure MLS session with a peer (high-level API). This method handles the complete session establishment flow:
  • If session already exists, returns null
  • If a pending key package is available, imports it, creates session, sends Welcome
  • If no key package is available, throws an error
This is the recommended method for establishing secure sessions as it handles the key package exchange flow automatically. returns: Welcome message if session was created, null if session already exists throws: Error if no key package is available (peer hasn’t completed key exchange)

rekeySession

Rotate the 1:1 session with a peer, advancing post-compromise security. Post-compromise security arrives when a commit rotates a member’s leaf in the ratchet tree, and the SDK originates one on a re-key. Nothing drives a re-key on its own except an epoch desync, so a pair that never forks never rotates unless the application asks. That bites hardest against a leaf node, a lock, a sensor, which never commits at all, so every rotation in such a pair is this side’s to originate. The cadence is yours on purpose: a rotation costs a teardown, a key-package exchange and a re-establish, and what that is worth depends on the deployment rather than on anything the wire says. The peer sees exactly what a desync-driven re-key sends. Queued messages survive, because they are sealed at flush time against whatever session is current then. A rotation that fails changes nothing. The reset is advertised before the local session is torn down, so a rejection leaves the session intact, still usable, and the rate-limit window unspent. Rotate while the peer is reachable and treat a failure as “try again later” rather than as a session to rebuild. returns: true when the rotation was driven; false when the per-peer rate-limit window has not lapsed. False is not a failure: call again later. throws: Error if encryption is not initialized, the peer is blocked, there is no session to rotate (establish one first), or no transport carried the reset.

mlsCreateSession

Creates an MLS session with another user. Returns a Welcome message that must be sent to the other user. Note: Prefer using establishSecureSession which handles the key package flow automatically. This lower-level method requires the peer’s key package to already be imported via mlsImportKeyPackage. returns: Welcome message to send to the other user throws: Error if session creation fails

mlsJoinSession

Joins an MLS session from a Welcome message. returns: Session info throws: Error if joining fails

mlsEncryptForUser

Encrypts a message for another user. Creates a session automatically if one doesn’t exist. returns: Encrypted message throws: Error if encryption fails

mlsDecryptFromUser

Decrypts a message from another user. returns: Decrypted plaintext as bytes, or null if decryption fails

mlsDecrypt

Decrypts any MLS message (1:1 or group). returns: Decrypted plaintext as bytes, or null if decryption fails

mlsListSessions

Lists all active MLS sessions. returns: Array of user IDs with active sessions

mlsDeleteSession

Deletes an MLS session with another user. throws: Error if deletion fails

mlsProcessWelcome

Processes a Welcome message (auto-detects session vs group). returns: Session or group info throws: Error if processing fails

Parameter and result types

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

InviteInfo

MlsKeyPackage

EstablishmentState

MlsWelcome

MlsSessionInfo

MlsEncryptedMessage

MlsGroupInfo