stream-chat-react-native v8 → v9 — Agent Migration Guide
Machine-oriented migration reference for AI coding agents. The prose-heavy human version lives at https://getstream.io/chat/docs/sdk/react-native/basics/upgrading-from-v8/ — do not load it for agent-driven migrations; this file supersedes it.
0. For the agent (read first)
-
Your training data predates v9. Do not rely on memory for v9 symbols, prop shapes, or export paths. Always verify against the installed SDK source.
-
Package name in
node_modules/isstream-chat-react-native-core. The published packages are:stream-chat-react-native-core— the actual SDK; shipssrc/+lib/.stream-chat-react-native— bare-RN wrapper; peer-deps on core.stream-chat-expo— Expo wrapper; peer-deps on core.
Every source path below is rooted at
node_modules/stream-chat-react-native-core/src/. Do not look undernode_modules/stream-chat-react-native/src/for SDK source — that's the wrapper, not the SDK. -
Order of work. Do §2 (prereqs) → §3 (big-3 structural moves) → §4/§5 (leaf renames + replacements) → §6 (behavior changes) → §9 (verify). Many leaf renames disappear automatically once §3.1 (
WithComponents) lands, so doing §3 first saves churn. -
Detect before editing. Run §1 first. Skip any section whose patterns don't match the customer codebase.
-
When uncertain, read source. §8 lists the files to consult. If a symbol is not in this guide, read the public barrel (
node_modules/stream-chat-react-native-core/src/index.ts) — do not guess.
1. Detection (run first)
Run each ripgrep against the customer's app source directory (replace src/
with their source root). Zero hits = skip the corresponding section.
# §3.1 — WithComponents migration needed?
rg '<(Channel|ChannelList|Chat|Thread)\s[^>]*\b([A-Z]\w+)=\{' src/
# §3.2 — five breaking component renames
rg '\b(MessageSimple|MessageAvatar|ChannelListMessenger|ChannelPreviewMessenger)\b' src/
# MessageInput is special: the component was renamed, but MessageInputContext,
# useMessageInputContext, and the MessageInput*View helpers were NOT. Filter
# the noise so only real component usages remain:
rg '\bMessageInput\b' src/ | rg -v 'MessageInputContext|MessageInputHeaderView|MessageInputFooterView|MessageInputLeadingView|MessageInputTrailingView|useMessageInputContext|MessageInputContextValue'
# §3.3 — inverted audio semantics
rg '\basyncMessagesMultiSendEnabled\b' src/
# §4.2 — hook renames
rg '\buseAudioController\b' src/
# useMutedUsers is scope-split: only rename Chat-level uses (ones that take a
# StreamChat client arg). Review each match against §4.2 before editing.
rg '\buseMutedUsers\b' src/
# §5 — removed components with replacements
rg '\b(AttachmentActions|AttachmentUploadProgressIndicator|Card|CardCover|CardFooter|CardHeader|ImageReloadIndicator|MessagePreview|imageGalleryCustomComponents)\b' src/
rg '\b(CameraSelectorIcon|FileSelectorIcon|ImageSelectorIcon|VideoRecorderSelectorIcon)\b' src/
# §6 — behavior / contract changes
rg '\b(latestMessagePreview|deletedMessagesVisibilityType|messageContentWidth|setMessageContentWidth|legacyImageViewerSwipeBehaviour)\b' src/
# Custom MessageMenu override is silently dead in v9 — flag any.
rg '\boverrides=\{[^}]*\bMessageMenu\b' src/
rg '\bMessageMenu=\{' src/
# Theme — v8 namespace names that moved
rg "\b(messageInput|messageSimple|channelListMessenger)\s*:" src/
# Semantic token renames
rg '\b(backgroundCoreSurface|badgeTextInverse|textInverse|backgroundCoreElevation4)\b' src/
# Icon removals / renames
rg '\b(CircleStop|Refresh|Close|User|MessageIcon|ArrowRight|ArrowLeft|Attach|ChatIcon|CheckSend|Folder|MenuPointVertical|Notification|PinHeader|LOLReaction|LoveReaction|ThumbsUpReaction|ThumbsDownReaction|WutReaction)\b' src/
2. Prerequisites (hard blockers — fail fast)
- React Native New Architecture is required. RN 0.76+ or an Expo SDK that defaults to the new arch. If the app is on the old architecture, stop and tell the user to migrate the arch first.
- New required peer dependency. Run
yarn add react-native-teleport(or the npm equivalent). Minimum version0.5.4. - Keyboard handling cleanup. Remove every one of these v8 workarounds
before running the app:
- Negative
keyboardVerticalOffsetvalues (e.g.-300) on any screen that rendersMessageComposer. Set it to the navigation header height instead (same value on iOS and Android). SafeAreaViewwrappers placed aroundMessageComposerpurely to fix bottom spacing.MessageComposerhandles its own safe-area in v9.- Manual Android IME padding hacks that pushed the composer above the keyboard.
- Negative
3. The big 3 structural migrations (do these first, in order)
3.1 Component override props → <WithComponents overrides={{...}}>
Every ComponentType prop on Channel, ChannelList, Chat, and Thread
was removed. They are now provided via a single <WithComponents> wrapper and
read with useComponentsContext().
Before (v8):
<Chat client={client} LoadingIndicator={CustomChatLoading}>
<ChannelList Preview={CustomPreview} />
<Channel channel={channel} Message={CustomMessage} SendButton={CustomSendButton} DateHeader={CustomDateHeader}>
<MessageList />
<MessageComposer />
<Thread MessageComposer={CustomThreadComposer} />
</Channel>
</Chat>
After (v9):
<WithComponents
overrides={{
ChatLoadingIndicator: CustomChatLoading, // renamed: see below
Preview: CustomPreview,
Message: CustomMessage,
SendButton: CustomSendButton,
DateHeader: CustomDateHeader,
ThreadMessageComposer: CustomThreadComposer, // renamed: see below
}}
>
<Chat client={client}>
<ChannelList />
<Channel channel={channel}>
<MessageList />
<MessageComposer />
<Thread />
</Channel>
</Chat>
</WithComponents>
Key rules:
-
WithComponentsnests. Inner overrides merge over outer ones (closest wins). -
Two prop keys were renamed when moving into
overrides:ChatpropLoadingIndicator-> overrides keyChatLoadingIndicatorThreadpropMessageComposer-> overrides keyThreadMessageComposer
-
If a custom component used to read other components from a specific context, switch to
useComponentsContext():// v8 const { MessageItemView } = useMessagesContext(); const { SendButton } = useMessageInputContext(); const { Preview } = useChannelsContext(); // v9 const { MessageItemView, SendButton, Preview } = useComponentsContext(); -
For the full list of overridable keys, read
node_modules/stream-chat-react-native-core/src/contexts/componentsContext/defaultComponents.ts. TheDEFAULT_COMPONENTSmap is the source of truth;ComponentOverridesis derived from it. Do not use a hardcoded list from your training data.
3.2 Five breaking component renames
Pure symbol renames. Apply with find-and-replace (whole-word, case-sensitive). Each rename also carries a prop-type rename and, in some cases, a theme namespace rename.
Components + props:
MessageSimple->MessageItemViewMessageSimpleProps->MessageItemViewPropsMessageSimplePropsWithContext->MessageItemViewPropsWithContext- Theme namespace:
messageSimple->messageItemView - Test ID:
message-simple-wrapper->message-item-view-wrapper
MessageAvatar->MessageAuthorMessageAvatarProps->MessageAuthorPropsMessageAvatarPropsWithContext->MessageAuthorPropsWithContext- Theme sub-key:
messageItemView.avatarWrapper->messageItemView.authorWrapper - Test ID:
message-avatar->message-author
MessageInput->MessageComposerMessageInputProps->MessageComposerProps- Theme namespace:
messageInput->messageComposer additionalMessageInputProps->additionalMessageComposerPropsThreadpropMessageInput-> overrides keyThreadMessageComposer(see §3.1)
ChannelListMessenger->ChannelListViewChannelListMessengerProps->ChannelListViewProps- Theme namespace:
channelListMessenger->channelListView - Test ID:
channel-list-messenger->channel-list-view
ChannelPreviewMessenger->ChannelPreviewViewChannelPreviewMessengerProps->ChannelPreviewViewProps- Theme namespace for
channelPreviewis unchanged (stayschannelPreview). - Test ID
channel-preview-buttonis unchanged. <ChannelList Preview={ChannelPreviewMessenger}/>becomes theChannelPreviewoverrides key on<WithComponents>.
Do NOT rename these (common over-migration traps):
MessageInputContext,useMessageInputContext,MessageInputContextValue— the component was renamed, the context was not.- The
MessageInput/source folder name. Stays asMessageInput/. MessageInputHeaderView,MessageInputFooterView,MessageInputLeadingView,MessageInputTrailingView— these helpers keep their names.channelPreviewtheme namespace andchannel-preview-buttontest ID.MessagePinnedHeader— still exists; just now rendered inside the consolidatedMessageHeaderflow.
3.3 Audio recording: semantics inverted
asyncMessagesMultiSendEnabled was removed and replaced with
audioRecordingSendOnComplete. This is not a rename — the boolean meaning
is inverted and the default changed.
Rewrite rule:
- v8
asyncMessagesMultiSendEnabled={true}≡ v9audioRecordingSendOnComplete={false} - v8
asyncMessagesMultiSendEnabled={false}≡ v9audioRecordingSendOnComplete={true} - Default behavior flipped. Both defaults are the literal boolean
true, but the semantics are inverted — so the runtime behavior changed:- v8 default
asyncMessagesMultiSendEnabled=true→ recordings stayed in the composer. - v9 default
audioRecordingSendOnComplete=true→ recordings send immediately. - If v8 code omitted the prop (relying on the default), pass
audioRecordingSendOnComplete={false}in v9 to preserve the old UX.
- v8 default
Semantics in plain terms:
- v9
audioRecordingSendOnComplete={true}— upload completes → send immediately. - v9
audioRecordingSendOnComplete={false}— upload completes → stays in composer so the user can add text or more attachments before sending.
Apply on Channel, MessageComposer, and any direct
useMessageInputContext() consumer. Also update direct
uploadVoiceRecording(sendOnComplete) callsites: the boolean now carries
sendOnComplete semantics, not the old multiSendEnabled semantics.
4. Rename lists (bullets, not tables)
4.1 Components (rename or removed-with-1:1-replacement)
MessageSimple->MessageItemViewMessageAvatar->MessageAuthorMessageInput->MessageComposerChannelListMessenger->ChannelListViewChannelPreviewMessenger->ChannelPreviewViewAudioAttachment— not renamed. Source folder moved fromAttachment/AudioAttachment/toAttachment/Audio/, but the public export name and theComponentOverrideskey are both stillAudioAttachment. Do not rename import sites or override keys.Card->UrlPreview(new props typeURLPreviewProps; see §5)Avatar(numericsize) ->Avatar(string enum'xs'..'2xl'); propimage->imageUrl;name->placeholder;online/presenceIndicator-> separateOnlineIndicatorcomponentGroupAvatar->AvatarGroup/AvatarStackCameraSelectorIcon->AttachmentTypePickerButtonFileSelectorIcon->AttachmentTypePickerButtonImageSelectorIcon->AttachmentTypePickerButtonVideoRecorderSelectorIcon->AttachmentTypePickerButtonCreatePollIcon-> (no replacement; poll creation is internal now)MessageMenu-> split intoMessageReactionPicker+MessageActionList+MessageActionListItem+MessageUserReactions(see §6)MessageMenuProps-> no direct replacement (customize the four components above individually)ChannelAvatar(legacy) ->ChannelAvatarfromui/Avatar/(different API;size='xl'default)PreviewAvatar->ChannelAvatarwithsize='xl'
4.2 Hooks
useAudioController->useAudioRecorderuseMutedUsers(Chat-level, called with aStreamChatclient) ->useClientMutedUsers. Scope-split rename. A separateuseMutedUsersfromChannelList/hooks/still exists in v9 and was not renamed — if the call site uses it inside a channel-list context (noclientarg), leave it alone. To decide: read the import path or the argument. If it takes aStreamChatclient, rename. Otherwise keep.useAudioPlayerControl->useAudioPlayer(also rename typeUseAudioPlayerControlProps->UseAudioPlayerProps). The v9 barrel exportsuseAudioPlayer;useAudioPlayerControlis removed.- New hooks that replace removed components/values:
useMessageDeliveryStatus,useGroupedAttachments,useMessagePreviewIcon,useMessagePreviewText(replace the removedMessagePreviewcomponent)useMessageComposer(direct access to composer state — replaces reading fromuseMessageInputContext()for most composer needs)useAttachmentPickerState(replaces context-basedselectedPicker/toggleAttachmentPicker)useImageGalleryVideoPlayer,useHasOwnReaction,useChannelPreviewDraftMessage,useChannelPreviewPollLabel,useChannelTypingState
4.3 Props (breaking only)
On Channel / MessageComposer / MessageInputContext:
asyncMessagesMultiSendEnabled->audioRecordingSendOnComplete(SEMANTICS INVERTED — see §3.3)toggleAttachmentPicker->openAttachmentPicker/closeAttachmentPickerselectedPicker->useAttachmentPickerState()hookcooldownEndsAt-> (removed; cooldown managed internally byOutputButtons)getMessagesGroupStyles-> (removed; grouping handled internally)legacyImageViewerSwipeBehaviour-> (removed; legacy viewer gone)deletedMessagesVisibilityType-> (removed; deleted messages always shown — see §6)isAttachmentEqual-> (removed)additionalMessageInputProps->additionalMessageComposerProps
On ChannelPreviewContext (and ChannelList):
latestMessagePreview(pre-formatted) ->lastMessage(raw). Text access goes fromlatestMessagePreview.messageObject.texttolastMessage.text.<ChannelList Preview={...}/>-><WithComponents overrides={{ ChannelPreview: ... }}>(the prop is onChannelList, but migrates to theChannelPreviewkey.)
On MessageList:
isListActive-> (removed)setMessages-> (removed; use centralized state store)channelUnreadState->channelUnreadStateStoreadditionalFlatListPropstype:FlatListProps<LocalMessage>->FlatListProps<MessageListItemWithNeighbours>setFlatListReftype:FlatListType<LocalMessage>->FlatListType<MessageListItemWithNeighbours>
On OverlayProvider:
imageGalleryCustomComponents(nested) -> flat keys on<WithComponents>(see §5)MessageOverlayBackground,ImageGalleryHeader,ImageGalleryFooter,ImageGalleryGrid,ImageGalleryVideoControls-> moved fromOverlayProviderprops to<WithComponents>overridesimageGalleryGridHandleHeight-> (removed)imageGalleryGridSnapPoints-> (removed)
On AudioAttachment:
onLoad/onPlayPause/onProgress->useAudioPlayerhooktitleMaxLength->showTitleboolean
4.4 Theme namespaces
messageInput->messageComposermessageSimple->messageItemViewmessageItemView.avatarWrapper->messageItemView.authorWrapperchannelListMessenger->channelListViewmessageItemView.card— still exists but restructured. Inner keysauthorName,authorNameContainer,authorNameFooter,noURI,playButtonStyle,playIconwere removed;linkPreview+linkPreviewTextwere added. A sibling keymessageItemView.compactUrlPreviewwas added for the new compact URL preview. Diff the full shape againsttheme.ts.channelPreviewnamespace: unchanged (internal structure changed heavily; if the app had customchannelPreviewoverrides, diff againstnode_modules/stream-chat-react-native-core/src/contexts/themeContext/utils/theme.ts)
For every other theme change: read the current Theme type at
node_modules/stream-chat-react-native-core/src/contexts/themeContext/utils/theme.ts
and let TypeScript report the mismatches. Do not try to remember the full
sub-key restructuring.
4.5 Icons (breaking only)
Renamed (public):
CircleStop->StopRefresh->Reload
Removed with no SDK replacement (supply your own):
- Navigation / UI:
ArrowRight,ArrowLeft,Close,User,MessageIcon,Attach,Back,AtMentions,ChatIcon,CheckSend,CircleClose,CirclePlus,CircleRight,DownloadArrow,DownloadCloud,DragHandle,Error,Eye,Folder,GenericFile,GiphyLightning,Grid,Group,Logo,MailOpen,MenuPointVertical,MessageBubble,Notification,PinHeader,SendCheck,SendPoll,SendUp,ShareRightArrow,UserAdmin,UserMinus - Reactions:
LOLReaction,LoveReaction,ThumbsDownReaction,ThumbsUpReaction,WutReaction - File-type icons:
CSV,DOCX,HTML,MD,ODT,PPT,PPTX,RAR,RTF,SEVEN_Z,TAR,TXT,XLS,XLSX
Visually updated but keep the same import name (no code change needed; flag if
the app has pixel-precise snapshots): Archive, ArrowUp, Audio, Camera,
Check, CheckAll, Copy, Delete, Down, Edit, Flag, GiphyIcon,
Imgur, Lightning, Link, Loading, Lock, MenuPointHorizontal, Mic,
Mute, PDF, Pause, Picture, Pin, Play, Recorder, Reload,
Resend, Search, SendRight, Share, Smile, Sound, ThreadReply,
Time, Unpin, UserAdd, UserDelete, Video, Warning, ZIP.
5. Removed-with-structural-replacement
Not simple renames — require a code shape change.
5.1 AttachmentUploadProgressIndicator → six granular indicators
One component split into six. Pick the right one per upload type × state:
FileUploadInProgressIndicatorFileUploadRetryIndicatorFileUploadNotSupportedIndicatorImageUploadInProgressIndicatorImageUploadRetryIndicatorImageUploadNotSupportedIndicator
Provide any custom ones as <WithComponents> overrides using the matching key.
5.2 Card / CardCover / CardFooter / CardHeader → UrlPreview + URLPreviewCompact
- Old type
CardProps-> new typeURLPreviewProps. - Choose rendering style via the new
urlPreviewTypeprop onChannel:'full'(default) or'compact'. - Customize via
<WithComponents overrides={{ UrlPreview, URLPreviewCompact }}>.
5.3 AttachmentActions → inline
Removed with no standalone replacement — actions now render inline on
attachments. Delete any custom AttachmentActions override.
5.4 MessagePreview → four hooks
Component removed. Replace with composable hooks:
useMessageDeliveryStatususeGroupedAttachmentsuseMessagePreviewIconuseMessagePreviewText
5.5 imageGalleryCustomComponents → flat WithComponents keys
- v8: nested object on
OverlayProvider(imageGalleryCustomComponents={{ header: { Component: ... }, footer: {...}, grid: {...}, gridHandle: {...} }}). - v9: flat
<WithComponents overrides={{ ImageGalleryHeader, ImageGalleryFooter, ImageGalleryVideoControls, ImageGalleryGrid }}>. Note the v8gridHandlehas no replacement (useImageGalleryGridinstead).
5.6 Individual attachment-picker selector icons → AttachmentTypePickerButton
CameraSelectorIcon, FileSelectorIcon, ImageSelectorIcon, and
VideoRecorderSelectorIcon are all replaced by the unified
AttachmentTypePickerButton. AttachmentPickerBottomSheetHandle,
AttachmentPickerError, and AttachmentPickerErrorImage are removed with no
replacement.
6. Behavior changes (runtime semantics, not grep renames)
messageContentOrderdefault swapped'text'/'attachments'. If the v8 app depended on text rendering before attachments, pass the old order explicitly:messageContentOrder={['quoted_reply','gallery','files','poll','ai_text','text','attachments','location']}.deletedMessagesVisibilityTyperemoved. Deleted messages are always shown now. The'sender' | 'receiver' | 'never'modes are gone; delete the prop.- Swipe-to-reply boundary moved. Was
MessageBubble, now the fullMessageItemView. Gesture behavior (messageSwipeToReplyHitSlop, thresholds, haptics,MessageSwipeContent, spring-back) is unchanged. messageContentWidth/setMessageContentWidthremoved. Strip any customMessageContent,MessageBubble, orReactionListTopthat read or called them (and the matching test mocks).MessagesContextno longer carries any UI component keys. The v9 design is that all component overrides live inComponentsContext(provided via<WithComponents>; see §3.1). If an app wraps its ownMessagesContextprovider directly, stop passingMessage,MessageItemView,MessageHeader,Attachment, etc. into the value — those fields are gone. Move them to<WithComponents overrides={{ ... }}>.- Known intentional exception:
FlatList(typed astypeof NativeHandlers.FlatList | undefined) is still a key onMessagesContextValue. It's not a user-overridableComponentType; it's injected byregisterNativeHandlers()at module load from the native-package or expo-package. Don't flag it as a leak; don't try to route it through<WithComponents>.
- Known intentional exception:
- Audio recording defaults changed. See §3.3.
- Semantic token renames:
backgroundCoreSurface->backgroundCoreSurfaceDefaultbadgeTextInverse->badgeTextOnInversetextInverse->textOnInversebackgroundCoreElevation4-> removed, no replacement. Remove any dependency on it.
- Reaction-list default changed.
reactionListTypedefault is now'clustered'. If the app relied on the v8 segmented style, setreactionListType='default'explicitly onChannel. MessageMenucomponent removed. The v9 overlay path does not renderMessageMenu; the component and itsMessageMenuPropstype are removed from the public barrel. Any v8 customMessageMenuoverride becomes a type error on v9 — migrate that logic to the four components that actually render in v9:MessageReactionPicker,MessageActionList,MessageActionListItem, andMessageUserReactions. Provide them via<WithComponents overrides={{ MessageReactionPicker, MessageActionList, MessageActionListItem, MessageUserReactions }}>.MessageActionTypeshape changed. Two breaking changes for apps with custom message actions:- New required field
type: 'standard' | 'destructive'on everyMessageActionTypeobject. Destructive entries render in a visually separated group in the action list. Addtypeto every entry in any custommessageActionsarray. - The
ActionTypeunion gained'blockUser'. If the app has an exhaustive switch overActionType, add a case for'blockUser'or the TypeScript compiler will flag the switch as non-exhaustive.
- New required field
- Hook exports flattened. Subpath imports like
'stream-chat-react-native/ChannelPreview/hooks/useChannelPreviewDisplayName'no longer resolve. Import from the package root:import { useChannelPreviewDisplayName } from 'stream-chat-react-native'. - Attachment-picker defaults.
attachmentPickerBottomSheetHeightis now fixed pixels (disableAttachmentPicker ? 72 : 333), not viewport-relative.attachmentSelectionBarHeightdefault is72(was52).numberOfAttachmentImagesToLoadPerCalldefault is25(was60).
7. Machine-readable rename block
Parseable JSON for deterministic find-and-replace. Keys are v8 symbols;
values are v9 replacements. null = removed with no in-SDK replacement.
{
"components": {
"MessageSimple": "MessageItemView",
"MessageAvatar": "MessageAuthor",
"MessageInput": "MessageComposer",
"ChannelListMessenger": "ChannelListView",
"ChannelPreviewMessenger": "ChannelPreviewView",
"Card": "UrlPreview",
"CardCover": "UrlPreview",
"CardFooter": "UrlPreview",
"CardHeader": "UrlPreview",
"GroupAvatar": "AvatarGroup",
"CameraSelectorIcon": "AttachmentTypePickerButton",
"FileSelectorIcon": "AttachmentTypePickerButton",
"ImageSelectorIcon": "AttachmentTypePickerButton",
"VideoRecorderSelectorIcon": "AttachmentTypePickerButton",
"PreviewAvatar": "ChannelAvatar",
"AttachmentActions": null,
"ImageReloadIndicator": null,
"AttachmentPickerBottomSheetHandle": null,
"AttachmentPickerError": null,
"AttachmentPickerErrorImage": null,
"MessagePreview": null,
"MessageEditedTimestamp": null,
"MessageMenu": "MessageReactionPicker + MessageActionList + MessageActionListItem + MessageUserReactions",
"CreatePollIcon": null,
"CommandsButton": null,
"MoreOptionsButton": null,
"InputEditingStateHeader": "MessageInputHeaderView",
"InputReplyStateHeader": "MessageInputHeaderView",
"CommandInput": null
},
"componentProps": {
"MessageSimpleProps": "MessageItemViewProps",
"MessageAvatarProps": "MessageAuthorProps",
"MessageInputProps": "MessageComposerProps",
"ChannelListMessengerProps": "ChannelListViewProps",
"ChannelPreviewMessengerProps": "ChannelPreviewViewProps",
"CardProps": "URLPreviewProps",
"MessageMenuProps": null
},
"hooks": {
"useAudioController": "useAudioRecorder",
"useAudioPlayerControl": "useAudioPlayer",
"useMutedUsers (Chat-level)": "useClientMutedUsers"
},
"props": {
"asyncMessagesMultiSendEnabled": "audioRecordingSendOnComplete",
"toggleAttachmentPicker": "openAttachmentPicker|closeAttachmentPicker",
"additionalMessageInputProps": "additionalMessageComposerProps",
"latestMessagePreview": "lastMessage",
"imageGalleryCustomComponents": "WithComponents overrides",
"deletedMessagesVisibilityType": null,
"legacyImageViewerSwipeBehaviour": null,
"isAttachmentEqual": null,
"cooldownEndsAt": null,
"getMessagesGroupStyles": null,
"messageContentWidth": null,
"setMessageContentWidth": null,
"imageGalleryGridSnapPoints": null,
"imageGalleryGridHandleHeight": null,
"titleMaxLength": "showTitle",
"onLoad": "useAudioPlayer",
"onPlayPause": "useAudioPlayer",
"onProgress": "useAudioPlayer"
},
"overridesKeyRenames": {
"LoadingIndicator (on Chat)": "ChatLoadingIndicator",
"MessageComposer (on Thread)": "ThreadMessageComposer"
},
"themeNamespaces": {
"messageInput": "messageComposer",
"messageSimple": "messageItemView",
"channelListMessenger": "channelListView"
},
"themeSubKeys": {
"messageItemView.avatarWrapper": "messageItemView.authorWrapper"
},
"semanticTokens": {
"backgroundCoreSurface": "backgroundCoreSurfaceDefault",
"badgeTextInverse": "badgeTextOnInverse",
"textInverse": "textOnInverse",
"backgroundCoreElevation4": null
},
"icons": {
"CircleStop": "Stop",
"Refresh": "Reload",
"ArrowRight": null,
"ArrowLeft": null,
"Close": null,
"User": null,
"MessageIcon": null,
"Attach": null,
"Back": null,
"ChatIcon": null,
"LOLReaction": null,
"LoveReaction": null,
"ThumbsUpReaction": null,
"ThumbsDownReaction": null,
"WutReaction": null,
"CSV": null,
"DOCX": null,
"HTML": null,
"MD": null,
"ODT": null,
"PPT": null,
"PPTX": null,
"RAR": null,
"RTF": null,
"SEVEN_Z": null,
"TAR": null,
"TXT": null,
"XLS": null,
"XLSX": null
}
}
8. When to read source (not training data)
All paths are under node_modules/stream-chat-react-native-core/src/. Read the
file directly — do not attempt to reconstruct its contents from memory.
- Public exports barrel:
index.ts - Components barrel:
components/index.ts - Hooks barrel:
hooks/index.ts - Contexts barrel:
contexts/index.ts WithComponents+useComponentsContext+ComponentOverridestype:contexts/componentsContext/ComponentsContext.tsx- Full overridable component list (source of truth):
contexts/componentsContext/defaultComponents.ts— theDEFAULT_COMPONENTSmap. - Theme type (source of truth for every theme key):
contexts/themeContext/utils/theme.ts useAudioRecorder:components/MessageInput/hooks/useAudioRecorder.tsxuseAudioPlayer:hooks/useAudioPlayer.tsuseMessageComposer:contexts/messageInputContext/hooks/useMessageComposer.tsuseAttachmentPickerState:hooks/useAttachmentPickerState.ts- Message item stack:
components/Message/MessageItemView/(MessageItemView.tsx,MessageAuthor.tsx,MessageHeader.tsx, etc.) - Composer:
components/MessageInput/MessageComposer.tsx(folder stays namedMessageInput/) - Channel preview:
components/ChannelPreview/ChannelPreviewView.tsx - Channel list view:
components/ChannelList/ChannelListView.tsx - Attachment-picker redesign:
components/AttachmentPicker/components/AttachmentPickerContent.tsx
Rule of thumb for anything not in this guide: open index.ts, grep for the
symbol you think you need, and follow the re-export path to the definition.
If it's not in index.ts, it's not a public API — do not rely on it.
9. Verification workflow
An agent MUST run all of these before declaring the migration complete. Every bullet is a hard gate; none are optional.
# 1. No v8 symbols remain in source.
rg '\b(MessageSimple|MessageAvatar|ChannelPreviewMessenger|ChannelListMessenger)\b' src/
rg '\buseAudioController\b' src/
# useMutedUsers is scope-split (§4.2). Any remaining matches must be verified by
# hand — Chat-level usage is a bug, ChannelList-level usage is fine.
rg '\buseMutedUsers\b' src/
rg '\basyncMessagesMultiSendEnabled\b' src/
rg '\b(latestMessagePreview|deletedMessagesVisibilityType|messageContentWidth|setMessageContentWidth|legacyImageViewerSwipeBehaviour)\b' src/
rg '\b(AttachmentActions|AttachmentUploadProgressIndicator|Card|CardCover|CardFooter|CardHeader|ImageReloadIndicator|MessagePreview)\b' src/
rg '\b(CameraSelectorIcon|FileSelectorIcon|ImageSelectorIcon|VideoRecorderSelectorIcon)\b' src/
rg '\b(backgroundCoreSurface|badgeTextInverse|textInverse|backgroundCoreElevation4)\b' src/
# 2. Component override props no longer appear on Channel/ChannelList/Chat/Thread.
# This regex matches JSX like `<Channel Message={...}` — expect 0 hits when §3.1 is done.
rg '<(Channel|ChannelList|Chat|Thread)\s[^>]*\b([A-Z]\w+)=\{' src/
# 3. `MessageInput` as a component reference is gone (component renamed to MessageComposer).
# The context name, hook name, and helper-view names are allowed — filter them out:
rg '\bMessageInput\b' src/ | rg -v 'MessageInputContext|MessageInputHeaderView|MessageInputFooterView|MessageInputLeadingView|MessageInputTrailingView|useMessageInputContext|MessageInputContextValue'
# 4. New required peer dep present in package.json.
rg '"react-native-teleport"' package.json
# 5. TypeScript passes.
yarn tsc --noEmit # or: npx tsc --noEmit
# 6. Lint + tests if the project has them.
yarn lint
yarn test
If any rg above returns hits (except #4 which should return a hit), either
finish migrating the matches or verify each match against §3–§6 and explain in
the agent's final report why the match is legitimate (e.g. a test string or a
comment referencing the v8 name).
Smoke-test the running app at minimum:
- Render
<Chat>→<Channel>→<MessageList>+<MessageComposer>. - Send a text message; long-press it → confirm reactions and action list appear via the new overlay.
- Swipe a message right → confirm reply preview appears (whole
MessageItemViewrow is the hit area now, not just the bubble). - Attach an image; confirm upload indicators render.
- Start an audio recording; confirm send behavior matches §3.3 intent.
- Open the image gallery from a message with media.
If anything renders but looks wrong, the theme likely has stale keys — diff
against contexts/themeContext/utils/theme.ts (§8) and let TypeScript
highlight every mismatch.