Every pre-8.0.0 React Native app must migrate. The npm package name remains
@xmtp/react-native-sdk; version 8.0.0-rc4 uses the generated native v8 API.
Existing method names, option shapes, generic types, hooks, and database files
are not a compatibility contract.
Start with Migrate to a self-hosted backend.
All participants must use the same backend. Keep the other SDK and backend
version pins from that guide. Follow React Native and
Expo to configure Hermes, New Architecture, native
builds, and deployment floors.
This guide lists changes from
xmtp-react-native v5.7.0
to @xmtp/react-native-sdk 8.0.0-rc4, built from sdks/react-native in
xmtp/libxmtp. A call can keep its name and still have different parameters,
results, or behavior. The Before examples use v5.7.0. The After examples
use the v8 declarations and are checked as complete TypeScript programs.
Install iOS pods and rebuild the native app. Expo apps need a rebuilt development
client or prebuilt native project. Expo Go and JavaScript-only updates cannot
install the module. Import the public API from the package root and optional
React helpers from /react. Do not import generated binding paths.
Version 5.7.0 was an Expo module. Version 8 is a Hermes JSI TurboModule with
prebuilt Rust libraries. It requires Hermes and New Architecture. It no longer
needs expo as a peer dependency, and it does not accept a viem WalletClient
as a signer. Remove app imports from @xmtp/proto; v8 has its own
EncodedContent and ContentTypeId records.
Pass backend: { url } or a Backend. Use the chosen deployment; there is no implicit public network.
Signer
Implement async identity(), kind(), and sign(request), or restore a saved LocalSigningKey.
Storage
Pass explicit storage options. Keep the optional 32-byte encryption key, location, and label stable. Default storage uses the native app directory.
Client creation
Use Client.create(signer, options) or reopen a current database with Client.build(identity, options).
Shutdown
Await client.end() before external file operations.
Types
Use Client, Group, Dm, Message, and Conversation without legacy generic parameters.
Values
IDs are strings; bytes are Uint8Array; maps are Map; full-width integers use bigint; times use Timestamp.
Content
Narrow message.content.kind. Standard codecs are built in; register only app custom codecs in ClientOptions.codecs.
Readers
Use SDK message/conversation readers. Await app processing before the next value; close readers when their owner changes.
React
Use XmtpProvider, useXmtp, and useClient from /react. No setClient, message hooks, or conversation hooks are exported.
Attachments
Use client.attachments to create, upload, download, and manage native files. The app owns picking media and OS permissions.
Push
Obtain tokens and OS permissions in the app, then call client.enableNotifications. Rewrite native handlers for the current push payload.
The sections below give the call-by-call changes. The TypeScript shapes match
the Node SDK Upgrade Guide,
with mobile storage and lifecycle integration. Use the React Native API
reference for the exact exported declarations.
new PublicIdentity(address, "ETHEREUM") class that lowercases the identifier
Plain PublicIdentity record { identifier, kind: "ethereum" }. Use "passkey" for a passkey and "handle" for a handle.
Upper-case string values such as "ETHEREUM", "PUBLISHED", and "DESCENDING"
Lower camel case strings such as "ethereum", "published", and "descending".
XMTPEnvironment ("local", "dev", "production")
Removed. Pass the deployment URL in backend. Use storage.label if the app keeps separate databases per deployment.
Branded InboxId, InstallationId, ConversationId, MessageId, and ConversationTopic
IDs remain strings. InstallationId values are hex strings.
Nanosecond number fields such as sentNs, insertedAtNs, and exportedAtNs
Timestamp. Use .ns for a bigint, .date for a Date, and new Timestamp(ns) for an input. Old number nanosecond values lose precision; v8 uses bigint.
Plain objects keyed by string, such as canMessage and getHmacKeys results
Map. Read entries with .get(key).
Generic Client<ContentTypes>, Group<ContentTypes>, Dm<ContentTypes>, Conversation<ContentTypes>, DecodedMessage<T>, and DecodedMessageV2<T>
Classes Client, Group, Dm, and Message. Conversation is the type Group | Dm. Narrow a conversation with instanceof Group or conversation.kind. Narrow content with content.kind.
ConversationVersion.GROUP / .DM and conversation.version
conversation.kind is "group" or "dm".
Public constructors such as new Client(...), new Group(...), and new DecodedMessage(...)
Use Client.create, Client.build, and SDK lookup or creation methods. Public SDK objects have private constructors.
Client.codecRegistry and Client.register(codec)
Removed. Pass custom codecs in ClientOptions.codecs. Standard content types are built in.
emitter, EventTypes, and expo-modules-core subscriptions
Removed. Use stream objects and client.events(...).
A signer has three asynchronous methods: identity(), kind(), and
sign(request). Replace getIdentifier, getChainId, getBlockNumber,
signerType, and signMessage. sign returns signature bytes, not a hex
string, and v8 does not split an ECDSA signature for you.
Before:
Before (xmtp-react-native v5.7.0)
import { PublicIdentity, type Signer } from "@xmtp/react-native-sdk";
export function createSigner(
address: string,
signText: (text: string) => Promise<string>,
): Signer {
return {
getIdentifier: async () => new PublicIdentity(address, "ETHEREUM"),
For a smart contract wallet, replace signerType: () => "SCW", getChainId,
and getBlockNumber with fields in the result of kind(). Return the signature
bytes, address, chain ID, and optional block number from sign(). Chain IDs and
block numbers are unsigned 64-bit bigint values.
Version 5.7.0 accepted a viem WalletClient and converted it. In v8, write a
Signer that calls the wallet and converts its hex signature to bytes. Passkey
signers return a "passkey" signature with signature, publicKey,
authenticatorData, and clientDataJson byte buffers, rather than the old
SignedData strings.
Client.createRandom(options) is removed. Generate a local key, save its bytes in
secure storage, and pass it to Client.create. Restore it with
LocalSigningKey.fromBytes on the next launch:
backend: { url } or a Backend from await Backend.connect({ url, appVersion?, credentials? }). Include the scheme. A device needs a URL it can reach; localhost on a phone is the phone.
Top-level appVersion
backend.appVersion.
Required dbEncryptionKey (32 bytes)
Optional storage.encryptionKey: Uint8Array (32 bytes). Keep the same key when you reopen a database.
dbDirectory omitted
storage: { location: "default" }. The SDK uses the native app directory.
dbDirectory: path
storage.location: { directory }, or { dbPath, attachmentsDir } for explicit files. Both explicit paths are required.
Environment in the database file name
storage.label. Keep the label and storage location stable. A label names a directory; it does not select a network.
forkRecovery: { policy, groups, disableResponses, workerIntervalNs }. The policy is "none", "allowlistedGroups", or "all", rather than "groups". The interval is a bigint.
codecs: [new ReactionCodec(), new ReplyCodec(), ...]
Omit standard codecs. Pass only custom codecs in codecs; see codecs.
No equivalent
registration: { auto, nonce }, allowOffline, workers, and attachments. Automatic registration defaults to true. New identity generation uses nonce 0.
Client.ffiCreateClient(identity, options) then ffiRegisterIdentity()
Client.create with registration: { auto: false }, then the signature request flow, or client.register().
Client.build(identity, options, inboxId?) keeps its form and reopens a client
without a signer. It now requires the v8 options object.
const
constclient:Client
client=await
classClient
An XMTP client. Its inputs and results are public values; the binding
Client and the target transport stay private to the package.
The v5.7.0 database is not an input to this migration. Create a new database
for the deployment. See the database migration rules
before choosing paths.
Configure backend credentials separately from the identity signer:
const
constclient:Client
client=await
classClient
An XMTP client. Its inputs and results are public values; the binding
Client and the target transport stay private to the package.
backend.credentials accepts a Credential or a source with asynchronous
credential(). A credential has value, expiresAtSeconds as a bigint in
Unix seconds, and an optional header name. Use client.setCredential(credential)
to replace a supplied credential. Client.fetchServerConfiguration(backend)
reads deployment limits without a client. client.serverConfiguration is a
property; await client.refreshServerConfiguration() stores configuration for
the next build.
Static calls take a BackendSource as the last argument: { url, appVersion?, credentials? } or a connected Backend. In v5.7.0 the environment was the first
argument.
Returns a specified element from the Map object. If the value that is associated to the provided key is an object, then you will get a reference to that object and any change made to that object will effectively modify it inside the Map.
@returns ― Returns the element associated with the specified key. If no element is associated with the specified key, undefined is returned.
get(
`${
identity: PublicIdentity
identity.
kind: PublicIdentityKind
kind}:${
identity: PublicIdentity
identity.
identifier: string
identifier.
String.toLowerCase(): string
Converts all the alphabetic characters in a string to lowercase.
toLowerCase()}`,
);
const
conststates:InboxState[]
states=await
classClient
An XMTP client. Its inputs and results are public values; the binding
Client and the target transport stay private to the package.
client.storagePath (can be absent for in-memory storage). environment is removed.
client.inboxId, client.installationId
Same properties. client.installationIdBytes, isInMemory, libxmtpVersion, appVersion, and options are new.
Client.canMessage(env, identities)
Client.canMessage(identities, backend): Promise<Map<string, boolean>>. Keys are ethereum:<normalized address> or passkey:<lowercase key hex>.
client.canMessage(identities) plain object
Same name. Returns a Map with the keys above.
Client.getOrCreateInboxId(identity, env)
Client.inboxIdFor(identity, backend): Promise<string>. When no inbox holds the identity, it returns the nonce-0 inbox ID only if that inbox has no identity updates or still holds the identity, and fails with IdentityNotFound otherwise. Use canMessage to test registration.
client.changeRecoveryIdentifier(signer, identity), Client.isAddressAuthorized, Client.isInstallationAuthorized, and Client.newestMessageMetadata. The new recovery identity must already be an identity of the inbox; see Remove an identity.
client.signWithInstallationKey(message)
Same.
client.verifySignature(message, signature)
client.verifySignedWithInstallationKey(text, signature). Client.verifySignedWithPublicKey(text, signature, publicKey) is new.
Client.dropClient(installationId)
await client.end().
client.deleteLocalDatabase()
await client.storage.delete_(). It ends the client, then removes its database.
No separate disconnect; await client.end() releases the database. reconnectLocalDatabase() becomes await client.storage.reconnect(). await client.storage.path() returns the database path.
list(options?) with one ListConversationsOptions object. listGroups(options | undefined) and listDms(options | undefined) require the argument; pass undefined for defaults.
ConversationOptions field selection, such as { lastMessage: true }
Removed. Read await conversation.lastMessage() or await conversation.state().
Removed. A push contains a hint; use conversations.sync(), conversation.sync(), then local message queries.
getHmacKeys() / getAllPushTopics()
conversations.hmacKeys(): Promise<Map<string, HmacKey[]>>. Push topics are removed; see notifications.
Conversation lists return at most 100 conversations when you pass no limit. A limit below 1 or above 1000 fails with InvalidArgument. To read every conversation, order by creation time and pass the last conversation’s createdAt as createdBefore and its ID as beforeId. See Paginate conversations.
Message lists return the 100 newest matching messages, in the requested order, when you pass no limit. A limit below 1 or above 1000 fails with InvalidArgument. To read more, page with messageHistoryPage. See Paginate messages.
Lookups have the same local-only behavior. Sync first when the app needs the
latest network state:
Removed. Use setNotifications for per-conversation overrides.
getDebugInformation(), commitLogForkStatus
debugInfo(), and .common.commitLogForkStatus in state.
updateAppData(value)
updateAppData(value, expected | undefined). Pass undefined for an unguarded write.
updateName, updateImageUrl, updateDescription, addAdmin, removeAdmin,
addSuperAdmin, removeSuperAdmin, sync, and deleteMessage keep their call
forms. Group methods membershipCapabilities() and lastActivityAt(contentTypes)
are new.
const
constsnapshot:GroupState
snapshot=await
group: Group
group.
Group.state(): Promise<GroupState>
state();
var console:Console
console.
Console.log(...data: any[]): void
The console.log() static method outputs a message to the console.
v8 also exposes typed metadata fields for app data and per-inbox values. On a
group or DM, use metadataFields(), metadataField(name), metadataValue(field),
metadataValues(fields), mapValue(field, key), userData(fields, inboxIds),
updateUserData(values), and updateMetadataField(field, operation). Both
userData arguments are required; pass undefined for all fields or inboxes.
Version 5.7.0 sent standard content through send with a native content key,
such as { reaction: ... } or { reply: ... }. Version 8 has a typed helper
for each standard content type: sendText, sendMarkdown, sendReaction,
sendReply, sendReadReceipt, sendAttachment, sendRemoteAttachment,
sendMultiRemoteAttachment, sendTransactionReference, sendWalletSendCalls,
sendActions, and sendIntent. Each returns a message ID.
sendRemoteAttachment(remote), sendMultiRemoteAttachment(value). See attachments.
send(value, { contentType }) with a registered JS codec
send(codec, value, options?). The codec does not need to be registered to send.
SendOptions.contentType, shouldPush
SendOptions has shouldPush?, optimistic?, idempotencyKey?, and compression?: "deflate" | "gzip". Without shouldPush, the content type’s default applies.
prepareMessage(content, opts?, noSend?)
prepareMessage(encoded | codec, ...). There is no noSend flag; see the note below.
publishPreparedMessages()
publishMessages(). publishMessage(id) remains.
deleteMessage(id)
Same, on a conversation or client.conversations. message.delete() and deleteLocally() are new.
Before:
Before (xmtp-react-native v5.7.0)
import type { Group, InboxId, MessageId } from "@xmtp/react-native-sdk";
prepareMessage stores an unpublished message, queues optimistic publication,
and returns its ID. Background processing can publish it before an explicit
publish call. Keep private drafts outside the SDK until the app is ready to send.
Standard codecs are built in. Do not pass ReactionCodec, ReplyCodec,
RemoteAttachmentCodec, or the other v5.7.0 codecs in codecs. The native
NativeContentCodec interface with contentKey is removed, and
StaticAttachmentCodec becomes AttachmentCodec. The exported standard codecs
are TextCodec, MarkdownCodec, ReadReceiptCodec, ReactionV2Codec,
ReplyCodec, DeleteMessageCodec, AttachmentCodec, RemoteAttachmentCodec,
MultiRemoteAttachmentCodec, TransactionReferenceCodec,
WalletSendCallsCodec, ActionsCodec, IntentCodec, GroupUpdatedCodec, and
LeaveRequestCodec.
A v5.7.0 JSContentCodec had contentType, encode, decode, fallback, and
shouldPush. A v8 ContentCodec<T> has type, encode(value), and
decode(encoded), with optional fallback(value) and shouldPush(value).
EncodedContent.parameters is a Map<string, string>.
const
constcodec:ContentCodec<Point>
codec:
interfaceContentCodec<T>
A content codec over public values. The send helpers run its steps before
the send starts: encode, then fallback when the envelope has none, then
shouldPush when the send has no explicit shouldPush option. A step that
throws, rejects, or returns a value of the wrong type fails the send with
XmtpError.CodecEncodeFailed, and the SDK makes no publish attempt. Each
step is a function property, so the value type is checked in both
directions.
ContentCodec<Point>.decode: (encoded:EncodedContent) => Point
decode: ({
content: Uint8Array<ArrayBufferLike>
content }) => {
const
constparts:number[]
parts=new
var TextDecoder:new (label?:string, options?:TextDecoderOptions) =>TextDecoder
The TextDecoder interface represents a decoder for a specific text encoding, such as UTF-8, ISO-8859-2, or GBK. A decoder takes an array of bytes as input and returns a JavaScript string.
Split a string into substrings using the specified separator and return them as an array.
@param ― separator A string that identifies character or characters to use in separating the string. If omitted, a single-element array containing the entire string is returned.
@param ― limit A value used to limit the number of elements returned in the array.
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@param ― callbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.
@param ― thisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map(
var Number:NumberConstructor
An object that represents a number of any kind. All JavaScript numbers are 64-bit floating-point numbers.
Number);
if (
constparts:number[]
parts.
Array<number>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
Determines whether the specified callback function returns true for any element of an array.
@param ― predicate A function that accepts up to three arguments. The some method calls
the predicate function for each element in the array until the predicate returns a value
which is coercible to the Boolean value true, or until the end of the array.
@param ― thisArg An object to which the this keyword can refer in the predicate function.
If thisArg is omitted, undefined is used as the this value.
some((
value: number
value) =>!
var Number:NumberConstructor
An object that represents a number of any kind. All JavaScript numbers are 64-bit floating-point numbers.
Returns true if passed value is finite.
Unlike the global isFinite, Number.isFinite doesn't forcibly convert the parameter to a
number. Only finite values of the type number, result in true.
@param ― number A numeric value.
isFinite(
value: number
value))
) {
thrownew
var Error:ErrorConstructor
new (message?:string, options?:ErrorOptions) =>Error (+1 overload)
Reply with a value of a typed codec. The codec's fallback applies to the
nested envelope; the reply keeps the reply type's push default unless
options.shouldPush is set. A failed codec step is CodecEncodeFailed,
with no publish attempt.
The console.error() static method outputs a message to the console at the "error" log level. The message is only displayed to the user if the console is configured to display error output. In most cases, the log level is configured within the console UI. The message may be formatted as an error, with red colors and call stack information.
messages, messagesWithReactions, and enrichedMessages become one
messages(options?) call. Each Message carries its reactions, reply count, and
reply parent.
Omit the field for all, or use "published", "unpublished", or "failed".
excludeContentTypes: string[]
excludeContentTypes and contentTypes take ContentTypeId[], for example [standardContentType("reaction")]. excludeSenderInboxIds and limit remain. kind is new.
message.content() method and message.nativeContent
message.content property: a MessageContent union. Narrow with content.kind. Text uses .value; replies use .referenceId and .body; reactions use .reaction.
message.contentTypeId string such as "xmtp.org/text:1.0"
Optional contentType: ContentTypeId record. content.kind is usually enough.
reactions: ReactionMessage[], with id, senderInboxId, sentAt, deliveryStatus, and reaction. reactions holds at most the 50 latest; reactionMessageCount counts every reaction message.
No equivalent
replyCount: bigint, inReplyTo, conversationId, kind, rawBytes, and deliveryCursor. await message.parent() reads the current parent.
Decode error thrown from content() for an unregistered type
"custom" content keeps encoded, rawBytes, an optional decoded value, and an optional error. Malformed standard content is "unknown" with rawBytes and an error.
reactions holds at most the 50 latest reaction messages to a message. reactionMessageCount counts every unexpired reaction message to it, removals included, so it is not a per-emoji tally. Read older reactions with messageReactions(messageId, before, limit). See Reactions.
Before:
Before (xmtp-react-native v5.7.0)
import type { Group } from "@xmtp/react-native-sdk";
export async function read(group: Group) {
const messages = await group.enrichedMessages({
limit: 20,
afterNs: 0,
direction: "DESCENDING",
});
for (const message of messages) {
if (message.contentTypeId.typeId === "text") console.log(message.content());
The console.error() static method outputs a message to the console at the "error" log level. The message is only displayed to the user if the console is configured to display error output. In most cases, the log level is configured within the console UI. The message may be formatted as an error, with red colors and call stack information.
New message actions are refresh(), delete(), deleteLocally(), react(...),
reply(...), parent(), conversation(), and client(). A message’s actions
need its originating client to remain open. await client.decodeContent(encoded)
decodes an envelope into the public content union.
Some content records have new fields:
v5.7.0 payload
v8 payload
GroupUpdatedContent.membersAdded, membersRemoved with { inboxId }, and metadataFieldsChanged
GroupUpdated.addedInboxes, removedInboxes, and leftInboxes contain inbox ID strings. metadataFieldChanges and the admin and super-admin arrays are new.
Optional DeleteMessageContent.messageId
Required messageId.
Base64 string attachment data
content: Uint8Array.
RemoteAttachmentContent with string secret, salt, nonce, and contentLength
RemoteAttachment with Uint8Array keys and a numbercontentLength. Build it with client.attachments or remoteAttachmentFromEncrypted.
Stream methods return a stream object at once. Iterate it, or register one
callback with onValue. await stream.ready() waits for the local reader to
open; it does not prove the backend is online. Close a stream with
await stream.end(), rather than a cancelStream* method.
v5.7.0 call
v8 call
conversations.stream(callback, type, onClose)
conversations.stream({ conversationKind?, consentStates?, onClose? }). Omit conversationKind for all conversations.
The console.error() static method outputs a message to the console at the "error" log level. The message is only displayed to the user if the console is configured to display error output. In most cases, the log level is configured within the console UI. The message may be formatted as an error, with red colors and call stack information.
A next-item request acknowledges the previous message. Await all processing
before the next request. return(), end(), and cancellation do not acknowledge
the last item. Callback mode awaits the callback before it requests the next
message. Do not also iterate a callback stream.
Await each callback before the next read. For messages, that read acknowledges
the prior message. Await all processing in the callback. Work sent to an app
queue or an unawaited task can continue after acknowledgement.
onValue(async (
message: Message
message) => {
await
process: (message:Message) =>Promise<void>
process(
message: Message
message);
});
// Later, when the owning screen or service stops:
await
constmessages:MessageStream
messages.
ReaderStream<Message>.end(): Promise<void>
end();
Version 5.7.0 delivered only new traffic. A v8 message reader can deliver
retained messages when it opens, then continue with new messages. Make app
effects safe to repeat. Only one default message reader owns delivery progress
for a database. A second default reader fails with ConsumerOwned. Use
options.from for independent replay. For history followed by live delivery,
use one snapshot boundary:
A live event subscription reports changes caused by sync, streams, workers, or
app calls. It does not fetch messages. await client.startListener(filter, callback) returns a bigint listener ID; await client.stopListener(id) ends
it. Handle "lagged" by reading current state again.
A stream of the client events that filter selects.
events({
kinds: EventKind[]
kinds: [
"consent.changed",
"message.deleted",
"hmac_keys.updated",
"conversation.metadata_changed",
],
});
forawait (const
constevent:ClientEvent
eventof
constevents:EventStream
events) await
process: (event:ClientEvent) =>Promise<void>
process(
constevent:ClientEvent
event);
The SDK suspends and resumes stream work with the native app lifecycle. Do not
add an AppState listener that restarts SDK streams. See Update ownership and
background work.
Pass a path in app-accessible storage, such as the app’s document directory.
Archive keys still require exactly 32 bytes. These APIs do not restore active
conversations on another backend. Follow the history migration
limits.
Version 5.7.0 encrypted a file:// URI and left upload to the app. When the
deployment offers attachment storage, v8 stages, uploads, and downloads native
files through client.attachments:
v5.7.0 helper or result
v8 helper or result
client.encryptAttachment({ fileUri, mimeType, filename }), then app upload
client.attachments.create({ kind: "path", path, filename, mimeType }) returns a PendingAttachment. Await upload(), then send its remoteAttachment.
status(), pending(remote), listPending(), localPath(remote), listLocal(), and deleteLocal(remote). A failed upload or download needs an explicit retry.
Before:
Before (xmtp-react-native v5.7.0)
import type { Client, Group } from "@xmtp/react-native-sdk";
If the app keeps its own file host, encrypt the attachment envelope in the app.
encryptFile(input, output) and decryptFile(input, output, keys) also work on
native file paths.
Replace the push server, topic subscriptions, and HMAC-key filtering with the
SDK’s notification API. The app still obtains OS permission and the APNs or FCM
token:
v5.7.0 push API
v8 push API
XMTPPush.register(server, token)
client.enableNotifications({ channel: { kind: "apns" | "fcm", token } }). The backend delivers pushes; there is no push server URL.
new XMTPPush(client).subscribe(topics) with getAllPushTopics()
Removed. The SDK maintains subscriptions while its task runner runs.
getHmacKeys() for self-push filtering
Not needed for registration. conversations.hmacKeys() and conversation.hmacKeys() still return the keys.
No per-conversation control
conversation.setNotifications("enabled" | "disabled" | "default"). Read notificationsEnabled from group .common or DM state.
No equivalent
client.notificationState() and client.disableNotifications().
The console.error() static method outputs a message to the console at the "error" log level. The message is only displayed to the user if the console is configured to display error output. In most cases, the log level is configured within the console UI. The message may be formatted as an error, with red colors and call stack information.
Call enableNotifications again when the provider token changes. Re-register
after migration; old push-server registrations are not imported. Push payloads
carry a base64 binary topic and decimal-string sequence_id, with no message
bytes. Rewrite native handlers to sync and read local messages. See Push
notifications.
A package update does not open or adopt the old database. Keep a recoverable
copy of the legacy database and its key. Close the legacy SDK before conversion.
Create a new current database for the target backend and identity, then convert
eligible history to an archive and import it:
The native converter accepts legacy databases whose recorded migrations match
the checked legacy migration chain, including known prefixes it can advance.
The pinned chain comes from libxmtp 6a8e969785c62e0923cf3d8531aff4eaac3c91b7:
64 migrations used by Node 6.1.0 and Browser 7.1.0; Android and iOS 4.10.0 have
62, and 4.11.0 have 64. A React Native package version alone does not prove
schema compatibility. Unknown, reordered, or changed migrations fail with
MigrationUnsupportedSchema. Retain the original database when conversion
fails. Do not describe this as support for every old React Native release.
Conversion works on a copy of a closed source and preserves the source. A source
lock produces StorageBusy; close every legacy connection first. The archive
contains eligible messages, conversation metadata, and consent. It excludes
installation keys, MLS secrets, attachment files, and messages with stored expiry
deadlines. Import does not restore the old installation or move its network
identity. Arrange account registration and conversation membership on the new
backend separately.
Supply a separate 32-byte archive key and an output path in app-accessible
storage. Keep the archive key separate from the archive file. Do not overwrite
the source with the output.
Only import archives from a trusted source. Import does not verify message
provenance or sender membership, and anyone with the key can forge history under
another sender. Legacy repeated-nonce archives have weakened confidentiality and
authentication; importing them cannot restore those guarantees.
See Backups and the
migration overview for conversion errors,
archive limits, and restoration behavior.
A typed array of 8-bit unsigned integer values. The contents are initialized to 0. If the
requested number of bytes could not be allocated an exception is raised.
The provider releases clients it creates and preserves caller-owned clients
passed through its client prop. Do not close a borrowed client in a hook
cleanup unless that component is its actual owner. disconnect() cancels a
pending initialization; a late result cannot publish into context. Handle
initialization and cleanup errors explicitly.
Use native lifecycle handling supplied by the SDK. A JavaScript AppState
listener cannot cover native cold starts or work after runtime teardown.
Background push and iOS extensions require native OS integration, bounded sync,
and coordinated access to app storage. See Push
notifications before shipping the receiver.
initLogging(options), setLogSink(sink), and flushTelemetry().
Errors as rejected strings or plain Error values
XmtpError and its subclasses, such as XmtpError.ClientClosed. Inspect details.code, category, retryable, and optional streamFailure. A database written in an older, unsupported format is an XmtpError.Storage whose code is StorageError::PreTransitionDatabase, StorageError::OldStreamDatabase, StorageError::OldEncodingDatabase or StorageError::LegacyGroupDatabase.
No equivalent
suspendStreams() and resumeStreams() act on shared process streams. sdkVersion() returns the library version without a client.
// Read or upload the files in logDirectory from app code.
functionexitDebugWriter():void
exitDebugWriter();
if (
error: unknown
errorinstanceof
classXmtpError
A failure from the XMTP SDK. Its subclass names the failure variant. details.code keeps the Rust cause code.
XmtpError) {
var console:Console
console.
Console.error(...data: any[]): void
The console.error() static method outputs a message to the console at the "error" log level. The message is only displayed to the user if the console is configured to display error output. In most cases, the log level is configured within the console UI. The message may be formatted as an error, with red colors and call stack information.
The console.error() static method outputs a message to the console at the "error" log level. The message is only displayed to the user if the console is configured to display error output. In most cases, the log level is configured within the console UI. The message may be formatted as an error, with red colors and call stack information.
A PublishedButUnconfirmed failure means the backend accepted the publish but
local confirmation did not complete. Sync and inspect the result before you send
again. ConfigurationUnavailable, BackendMismatch, ClientVersionTooOld,
AuthRequired, ConsumerOwned, and InvalidCursor are other new failures.
End the client after its consumers stop:
await
client: Client
client.
Client.end(): Promise<void>
End the client. Messages from it then fail with ClientClosed. Ending a
closed client does nothing, also after its browser worker stopped.