Skip to content
Meshline
SDK 0.1.0-alpha.2 · GuideView source on GitHub

Events and troubleshooting

Use on(name, listener) for domain events and onLifecycle(name, listener) for component state and background failures. Both return an unsubscribe function.

The observeClient function in workflows.ts subscribes to conversation changes and to background errors on the client and all six managers. Failures belong to the emitting component; observing only the client does not replace subscriptions to its managers.

Event behavior

Listeners run in registration order without awaiting returned promises. A pending listener does not defer later listeners. Keep synchronous work short; handlers may stop or dispose their component or owning client.

Observer failures are reported through that component's backgroundError and retained in lastBackgroundError. They do not undo a committed operation or change its foreground result. If an error observer also fails, diagnostics retain both errors. SDK shutdown does not drain asynchronous application callback work; track any work that must finish separately.

Emitter Event Payload
Client conversationChanged Conversation ID and created, updated, or removed kind
Account manager accountChanged Current account state and route snapshot
Device manager deviceChanged, deviceStateChanged Device ID or accepted device-state snapshot
Profile manager profileChanged Profile snapshot or undefined
Message manager messageReceived, sendStatusChanged, timelineChanged Message array, send status, or no payload
Message manager contactChanged, contactRequestChanged Identity, committed optional snapshot, and change classification
Channel manager channelChanged, timelineChanged, followChanged Channel snapshot, channel/post changes, or follow status
Group manager groupChanged, timelineChanged Group snapshot with change kinds, or group/sequence with optional decrypted message
Group manager applicationsChanged, keyRecoveryChanged Group reference
Any client component stateChanged, backgroundError via onLifecycle Previous/current state, or operation/resource/error

A group timeline event may have no message; check it before appending chat content. Notifications about verified history need not contain decrypted content.

contactChanged.kinds contains relationship, alias, authorization, or deleted; contact is absent on deletion. Authorization reflects device state cached in the committed transaction. contactRequestChanged includes direction, an added/updated/removed kind, and request when it still exists.

groupChanged preserves ref, group, membership, and role, and adds kinds: properties, members, roles, bans, nickname, or status. Verified management changes produce a combined snapshot per committed history page, even if a later page fails. Nickname and local membership changes have their own committed snapshots. Failed commits do not publish partial changes.

Cancellation and error types

Operations accept optional AbortSignal; some options objects carry signal. Cancellation preserves the signal's reason when the runtime provides it. On legacy React Native controllers that discarded a caller's reason, the SDK returns AbortError; it cannot reconstruct that value and does not replace the global controller. SDK-owned scopes preserve their cancellation reasons.

Error How to handle it
ProtocolError with a code Inspect invalid input, identity, authorization, or protocol state.
TypeError / RangeError Correct argument shape or range.
StateConflictError Refresh/reconcile state before choosing the next operation.
RelayError Inspect retained relay error metadata; distinguish permissions from authentication.
Transport/deadline/cancellation failure Preserve pending state; interruption is not proof of remote rejection.
Local storage/protection failure Restore access to the original store/protector and retry without discarding state.

Troubleshooting

Symptom Likely cause What to do
Client cannot open its database Missing migration, incorrect binding, inaccessible storage, or lost protector Migrate explicitly; check the network/account/database and restore access to the original protection keys. Surface corruption instead of opening a new empty store.
Existing account fails initial establishment This database has no authorized device for the existing route Use the application's explicit account recovery flow with an account signer.
Send returns but the peer has no message yet The return is an outbox status, or background work is stopped Start the client, inspect getSendStatus, and observe sendStatusChanged.
Page does not show a new arrival The reader holds a fixed snapshot Dispose it and open a new reader.
Profile edit or migration reports a conflict An earlier request is uncertain or authoritative state changed Let the original operation reconcile; inspect the current state before choosing another edit or target.
New device cannot decrypt old group messages Historical secrets are unavailable on that device Keep another authorized device running for key synchronization; recovery alone cannot recreate missing historical keys.
Group approval does not complete a pending request Approval does not verify the original candidate, or history/key processing failed Keep the original store/protector, inspect background errors, and verify the correct application's approval.
Expo cannot find MeshlineRelaySocket Expo Go or an old native binary lacks the module Rebuild the native app after installing the adapter.
Android reports a released SQLite object or incomplete HTTP body Pinned Expo native dependencies may be missing compatibility fixes Apply and check the Android fixes, then rebuild. If already applied, retain the error for diagnosis.
Browser relay traffic carries cookies Ambient WebSocket policy or the known Windows WebKit fetch issue Use a cookie-free relay origin and review browser limits.
Authentication stays rejected after a public request succeeds A public request does not reauthorize the device Check route/device authorization and establish a newly authenticated session.

All guides