💬 React-Native Chat SDK ➜ Stream Chat. Includes a tutorial on building your own chat app experience using React-Native, React-Navigation and Stream
| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
perf: gallery virtualization (#3675) ## 🎯 Goal Our image gallery was never properly virtualized and mounted one slide component per asset for **all** loaded media (`assets.map(...)`), so scroll/swipe jank scaled with the asset count. On a media heavy channel roughly **40% of frames were janky**, driven by `O(N)` animated style worklets rerunning on the UI thread every frame. This bounds that cost so gallery performance no longer degrades as channels accumulate media. This was relatively fine before, when `ChannelDetails` hadn't been introduced yet but now poses an actual challenge. ## 🛠 Implementation details - Extracted the slide list into a windowed `GalleryPager` that mounts only the slides within `PAGER_WINDOW_RADIUS` of the current index, instead of all N. Mounted slides drop from ~N to ~9. - A single **leading spacer** reproduces the flex width of the skipped slides, so the rendered slides keep their exact natural positions. The per slide transforms (`useAnimatedGalleryStyle`) are a pure function of `index` + `flex` position, so windowing the mount should be fine - `GalleryPager` subscribes to `currentIndex` itself, so paging rerenders only the small slide list, never the parent (gesture objects/`GestureDetector` stay stable). - The existing per slide `shouldRender` load gate is retained (image +-3, video +-1) for now so windowing bounds the *mount*; `shouldRender` still bounds *content load* (notably capping live native video players within the mounted set). Measured on a debug `SampleApp` (on a media heavy channel), provided below are the results (naturally, taken from the best 5 runs against baseline and the worst 5 runs against this branch across of many, many runs): | Metric | Before | After | Improvement | |---|---|---|---| | **Janky frames** | 40.4% | **14.1%** | **−65%** (−26 pts) | | **Median frame time** | 42 ms | **21 ms** | **2× faster** (−50%) | | 90th-pct frame time | 79 ms | 46 ms | −42% | | 95th-pct frame time | 95 ms | 67 ms | −29% | | 99th-pct frame time | 150 ms | 133 ms | −11% | | **Missed vsyncs** | 154 | **57** | **2.7× fewer** (−63%) | | Frames rendered (same path) | 856 | 1,039 | +21% throughput | | Mounted slide components | ~165 | **~9** | **~18× fewer** | Jank no longer scales with asset count (after jank is flat across N, where before it rose). ## 🎨 UI Changes <!-- Add relevant screenshots --> <details> <summary>iOS</summary> <table> <thead> <tr> <td>Before</td> <td>After</td> </tr> </thead> <tbody> <tr> <td> <!--<img src="" /> --> </td> <td> <!--<img src="" /> --> </td> </tr> </tbody> </table> </details> <details> <summary>Android</summary> <table> <thead> <tr> <td>Before</td> <td>After</td> </tr> </thead> <tbody> <tr> <td> <!--<img src="" /> --> </td> <td> <!--<img src="" /> --> </td> </tr> </tbody> </table> </details> ## 🧪 Testing <!-- Explain how this change can be tested (or why it can't be tested) --> ## ☑️ Checklist - [ ] I have signed the [Stream CLA](https://docs.google.com/forms/d/e/1FAIpQLScFKsKkAJI7mhCr7K9rEIOpqIDThrWxuvxnwUq2XkHyG154vQ/viewform) (required) - [ ] PR targets the `develop` branch - [ ] Documentation is updated - [ ] New code is tested in main example apps, including all possible scenarios - [ ] SampleApp iOS and Android - [ ] Expo iOS and Android | 2 个月前 | |
chore: upgrade to TypeScript 6.0.3, ES2022 target, and shared ts-config presets (#3663) ## What & why Upgrades every workspace to **TypeScript 6.0.3** with **`target: ES2022`**, and removes tsconfig duplication via a new shared preset package. Enabling type-checking across the previously-unchecked packages also surfaced (and this PR fixes) a pre-existing bug in the core package's published type resolution plus a batch of latent type errors. ## Changes ### Shared config - New **private** `@stream-io/typescript-config` workspace (`configs/typescript-config/`): - `base.json` — cross-cutting policy (ES2022 target, strict, interop, …) - `library.json` — full React Native library config (extends `base`) - Core, the native/expo wrappers, and all 3 example apps extend these instead of duplicating compiler options. Example apps array-extend `["<framework base>", "@stream-io/typescript-config/base.json"]`. ### TypeScript 6.0.3 / ES2022 - TS `6.0.3` in all 7 manifests; `target: ES2022` everywhere. - `lib` kept at `ESNext` — the SDK uses the ES2023 `Array.prototype.toReversed()`. - TS 6.0 no longer auto-includes `@types/jest`, so it's referenced explicitly from a test-only `package/src/__tests__/jest-globals.d.ts` (excluded from the published build). ### Core publishing fix (consumer-facing) - `react-native-builder-bob` emitted declarations under `lib/typescript/src/` while `package.json#types` pointed at `lib/typescript/index.d.ts` — so TS consumers couldn't resolve the SDK's types via `types`. Added `rootDir: "./src"` so declarations emit flat to match `types`. This was also the root cause that blocked the wrappers/examples from resolving core's types. - Exported `PickImageOptions` from the core entrypoint (defined+exported in `native.ts` but never surfaced from `index`). ### Wrappers (`stream-chat-react-native`, `stream-chat-expo`) - Added a `typecheck` script + tsconfig (they had neither). The dynamic optional-`require` shims relax `noImplicitAny`/`strictNullChecks`/unused checks (kept `noImplicitReturns`). - Fixed real bugs: missing `return`s in `shareImage`, missing `resizeMode`/`rate` on the video shim, an inconsistent `startRecording` return shape. ### Example apps - Fixed ~60 pre-existing latent type errors unmasked by enabling typecheck: theme palette typing (the legacy flat `colors` palette, read via a local `AppTheme` cast — behavior-preserving), null-safety guards, and several SDK-API-drift fixes. ### CI - `check-pr.yml` now runs `yarn typecheck` across the whole workspace (core + 2 wrappers + 3 examples) instead of only the core package; the root `typecheck` aggregate includes the wrappers. ## Verification - `yarn build` ✅ - `yarn typecheck` (core + 2 wrappers + 3 examples) ✅ **0 errors** - `yarn lint` ✅ ## Notes for reviewers - **Commit type**: filed as `chore:` (release-neutral). The core changes (flat `types` path + `PickImageOptions` export) are genuinely consumer-facing — if you want them shipped, retype as `fix:` to cut a patch. - **Wrapper strictness**: `strictNullChecks`/`noImplicitAny` are relaxed **only** for the two wrapper packages (dynamic optional-dep shims), not for core. - **Example theming**: the apps' custom `colors` palette was already inert for SDK theming (the SDK reads semantics/primitives, not `theme.colors`); this PR preserves that behavior. Migrating the palette to the token model to restore custom branding would be a separate enhancement. - Did not run the full unit suite locally (the only core source change is the additive `PickImageOptions` export); CI runs `test:coverage`. --------- Co-authored-by: Ivan Sekovanikj <ivan.sekovanikj@getstream.io> | 28 天前 | |
chore(yarn): migrate to Yarn 4 + native workspaces (#3594) ## 🎯 Goal Move us onto Yarn 4 with native workspaces and drop Lerna. The `.yarnrc.yml` was already half-migrated, but `yarnPath` still pointed at the v1 binary — this finishes that off. ## 🛠 Implementation details Tooling only; nothing in `package/src` changes. Roughly: - `.yarn/releases/` swapped to 4.14.1, and all seven `yarn.lock` files migrated v1 → v8 in place — resolutions preserved, no drift. - Single root `workspaces` array now covers `package/`, both native wrapper packages, and all three example apps. `link:../../package/*` becomes `workspace:^`, nested lockfiles are gone, and the install-and-build-sdk composite action collapses to one `yarn install --immutable`. - Shared-native sync + husky setup run from the core SDK workspace's `postinstall` (Yarn 4 doesn't run root-workspace lifecycle scripts on install). - Lerna removed: `release/release.config.js` no longer reads `lerna.json`, and `release` / `release-next` / `extract-changelog` use `yarn workspaces foreach`. - Husky 6 → 9 (the v6 hook boilerplate is on the deprecation path). - `.yarnrc.yml` picks up the conservative hardening tier: `enableHardenedMode`, `npmMinimalAgeGate: 3d`, `enableScripts: false` with a small `dependenciesMeta` allowlist for the packages that genuinely need to build (`@swc/core`, `better-sqlite3`, `react-native-nitro-modules`, `unrs-resolver`). - CI workflows cache `.yarn/` via setup-node; drive-by fix for the deprecated `::set-output` calls in `changelog-preview.yml`. ## 🎨 UI Changes N/A. ## 🧪 Testing Locally: `yarn install --immutable` is clean, `yarn lint` + `yarn build` pass, husky hooks fired on every commit in this PR. Can't verify locally: example apps on real devices, and the release flow itself. The Lerna → `yarn workspaces foreach` rewrite is the riskiest single change — worth a dry-run on a throwaway branch before merging. ## ☑️ Checklist - [x] I have signed the [Stream CLA](https://docs.google.com/forms/d/e/1FAIpQLScFKsKkAJI7mhCr7K9rEIOpqIDThrWxuvxnwUq2XkHyG154vQ/viewform) (required) - [x] PR targets the `develop` branch - [x] Documentation is updated - [ ] New code is tested in main example apps, including all possible scenarios - [ ] SampleApp iOS and Android - [ ] Expo iOS and Android --------- Co-authored-by: Ivan Sekovanikj <ivan.sekovanikj@getstream.io> | 3 个月前 | |
docs: refresh README cover image and remove stale screenshots (#3589) ## 🎯 Goal Refresh the SDK's README cover image and clean up the long-unused `screenshots/` directory. ## 🛠 Implementation details - Added new cover at `.readme-assets/stream-chat-react-native-cover.png`. - Updated `README.md` and `examples/SampleApp/README.md` to reference the new asset via relative paths (also improved alt text). - Deleted the entire `screenshots/` directory (~16 MB, last touched in 2022). References to it from `package/CHANGELOG.md` are historical entries with already-broken relative paths and are intentionally left untouched. ## 🎨 UI Changes No app-side UI changes — README cover image only. ## 🧪 Testing - Verified the new image renders in both READMEs locally. - Confirmed no remaining non-historical references to `screenshots/`. ## ☑️ Checklist - [x] I have signed the [Stream CLA](https://docs.google.com/forms/d/e/1FAIpQLScFKsKkAJI7mhCr7K9rEIOpqIDThrWxuvxnwUq2XkHyG154vQ/viewform) (required) - [x] PR targets the `develop` branch - [x] Documentation is updated - [ ] New code is tested in main example apps, including all possible scenarios - [ ] SampleApp iOS and Android - [ ] Expo iOS and Android | 3 个月前 | |
fix: stop sending typing events when the event is not enabled on dashboard (#2014) * fix: stop sending typing events when the event is not enabled on dashboard * fix: stop sending typing events when the event is not enabled on dashboard * fix: remove forced casting * fix: broken tsc * chore: rename * feat: add ability to switch to rn sdk core typescript version --------- Co-authored-by: Santhosh Vaiyapuri <santhoshvai@gmail.com> | 3 年前 | |
chore: rn 0.86 compatibility (#3741) ## 🎯 Goal This PR adds RN `0.86`/Expo 57 compatibility to the SDK. Since the RN team [fixed `measureInWindow`](https://reactnative.dev/blog/2026/06/11/react-native-0.86#edge-to-edge-on-android) in the latest release, the `insets.top` correction that we applied before is no longer needed and is harming us on these versions. So that we retain backwards compatibility, we'll still keep this behaviour on older versions of React Native while keeping it for anything above `0.86`. Note: I'd like to shed some light on [this change](https://github.com/GetStream/stream-chat-react-native/pull/3741/changes/e8729a4a027cb081aca44102c833c5b28fbe7208), because I just spent the better part of the last 4 hours debugging why all of the offline tests were failing on CI and not locally. So why disable journaling/fsync in the offline-support DB mock? The offline support suite backs its mocked SQLite with a real file based `better-sqlite3` DB and each test does `~2,000 write` ops (the connection sync persists 10 channels' full state, so messages, members, reads, reactions). With `SQLite's` default `synchronous=FULL`, every write does an `fsync: ~1ms` on a local SSD but ~40ms on a CI runner's slower disk. That's `~2,000 × 40ms ≈ 80s` of DB work per test against a 5s Jest timeout, so the suite passed locally but timed out on CI. `journal_mode = MEMORY + synchronous = OFF` keeps writes off the disk (test DBs need no durability, we roll a new DB for each iteration anyway), cutting per write cost to sub millisecond and the suite back to `~1–2s`, comfortably under the timeout. And as to why this happened with this PR ? I have no clue. I assume it's something related to upgrading the testing ecosystem (the jest preset at least) to a higher react version or something else I'm missing triggering this. I've sort of seen it happen once or twice before as well, but it was generally treated as a fluke (whereas now I did about ~30 failed test runs, including reruns of course). Fun times. ## 🛠 Implementation details <!-- Provide a description of the implementation --> ## 🎨 UI Changes <!-- Add relevant screenshots --> <details> <summary>iOS</summary> <table> <thead> <tr> <td>Before</td> <td>After</td> </tr> </thead> <tbody> <tr> <td> <!--<img src="" /> --> </td> <td> <!--<img src="" /> --> </td> </tr> </tbody> </table> </details> <details> <summary>Android</summary> <table> <thead> <tr> <td>Before</td> <td>After</td> </tr> </thead> <tbody> <tr> <td> <!--<img src="" /> --> </td> <td> <!--<img src="" /> --> </td> </tr> </tbody> </table> </details> ## 🧪 Testing <!-- Explain how this change can be tested (or why it can't be tested) --> ## ☑️ Checklist - [ ] I have signed the [Stream CLA](https://docs.google.com/forms/d/e/1FAIpQLScFKsKkAJI7mhCr7K9rEIOpqIDThrWxuvxnwUq2XkHyG154vQ/viewform) (required) - [ ] PR targets the `develop` branch - [ ] Documentation is updated - [ ] New code is tested in main example apps, including all possible scenarios - [ ] SampleApp iOS and Android - [ ] Expo iOS and Android | 1 个月前 | |
feat: enhanced mentions (#3631) ## 🎯 Goal This PR implements the enhanced mentions featureinto the SDK so RN apps can mention not just users but also `@channel`, `@here`, custom roles and user groups - with per type colors in the rendered message and full offline draft round tripping. Bundles the architectural fixes that surfaced while wiring this up (Android `a11y` bounds, cross screen portal teleport leak, composer/list animation sync, iOS multiline regression). ## 🛠 Implementation details Enhanced mentions Consumes the LLC's five variant `MentionSuggestion`/`MentionEntity` union (`user | channel | here | role | user_group`). Composer suggestion rows - `package/src/components/AutoCompleteInput/` - `AutoCompleteSuggestionItem.tsx`'s `MentionSuggestionItem` is now a dispatcher that switches on `item.mentionType` and routes to a per type row. Still overridable via `useComponentsContext().MentionSuggestionItem` so integrators can replace just the mention branch. - New mentionItems/ directory with one component per variant (MentionUserItem, MentionBroadcastItem, MentionRoleItem, MentionUserGroupItem), a shared MentionItem primitive, plus reusable EnhancedMentionContent, EnhancedMentionIcon, TokenizedSuggestionParts — all exported for custom dispatcher composition. - New icons: megaphone.tsx (broadcast), shield.tsx (role). User-group rows reuse the existing PeopleIcon. Rendered message text - `Message/MessageItemView/utils/renderText.tsx` - Builds a `MentionEntity[]` from `mentioned_users` + `mentioned_channel` + `mentioned_here` + `mentioned_roles` + `mentioned_groups` (`mentioned_group_ids` fallback). - Regex alternation built longest-first to avoid prefix collisions (`@here` mustn't shadow `@here-team`). - Per type color via semantic tokens (chatTextMentionUser / …Broadcast / …Role / …Group), each defaulting to the umbrella `chatTextMention` so existing themes look identical. - `onPress` now carries `additionalInfo: { mentionedEntity, user? }`. `user` stays populated for user mentions (for back compatibility reasons). - Markdown cache key extended to all five mention sources so the text rerenders when only non-user mentions change. Memo comparator — MessageItemView/MessageTextContainer.tsx - React.memo comparator extended to diff mentioned_channel, mentioned_here, mentioned_roles, and mentioned_groups/mentioned_group_ids in addition to mentioned_users. Without this, messages differing only in non-user mentions would skip re-render. Offline draft persistence has also been modified to reflect enhanced mentions. **Suggestion list architecture** The mount location of `<AutoCompleteSuggestionList />` is now moved to `MessageList.tsx` and `MessageFlashList.tsx` - not `MessageComposer.tsx`, inside its own `<PortalWhileClosingView portalHostName='overlay-suggestion-list' portalName='autocomplete-suggestion-list'>` wrapper. Why: Android's `getBoundsInScreen()` clamps `a11y` bounds to the parent's measured rect. The composer's wrapping View (~`228` px with safe area padding) was clipping the absolutely positioned suggestion list to inverted/empty bounds - `TalkBack` saw nothing, taps didn't activate. Hoisting into the `flex: 1` `MessageList` container restores valid `a11y` bounds. Verified with `uiautomator` dump. **`PortalWhileClosingView` cross screen leak fix** Removed the early return guard in `syncPortalLayout`: ``` if (!width || !height) { return; } ``` The guard kept unmeasured (0×0) wrappers off the closing portal stack, but as a side effect, wrappers with no children (e.g. autocomplete list before the user types @) never registered. Navigating `Channel` -> `Thread` (both mount such wrappers, as an example) left the previous screen's stale entry as the only thing on the host stack and the closing overlay teleport then stamped `Channel` autocomplete content into the `Thread` screen. Removing the guard lets empty wrappers register; teleport for an empty wrapper renders `null` children so nothing visible. Accessibility - New hook `useAnnounceOnShow(visible, message, { delayMs?, priority? })` - announces on each visible: false -> true transition and resets on hide. Unlike `useAnnounceOnStateChange`, it doesn't dedupe consecutive identical strings, so reshows reannounce. - Applied to `BottomSheetModal` (replaces adhoc `ref` + `useEffect`) and `AutoCompleteSuggestionList` - `ai-docs/accessibility.md` and the team `a11y` skill updated to document `useAnnounceOnShow`, the menu/menuitem iOS only caveat and a new "floating overlays need a tall parent for Android a11y" rule. **ClippingFadeBottom** New `UIComponents/ClippingFadeBottom.tsx` reusable fade primitive used at the bottom edge of the suggestion list so long lists fade out instead of hard clipping at the composer edge. Bundled bug fixes - iOS multiline `TextInput` regression after RN upgrade - caret jumping on newline - `AutoCompleteSuggestionList` animation desync when swithcing between attachment picker and keyboard - Accessibility bugs with the suggestions list ## 🎨 UI Changes <!-- Add relevant screenshots --> <details> <summary>iOS</summary> <table> <thead> <tr> <td>Before</td> <td>After</td> </tr> </thead> <tbody> <tr> <td> <!--<img src="" /> --> </td> <td> <!--<img src="" /> --> </td> </tr> </tbody> </table> </details> <details> <summary>Android</summary> <table> <thead> <tr> <td>Before</td> <td>After</td> </tr> </thead> <tbody> <tr> <td> <!--<img src="" /> --> </td> <td> <!--<img src="" /> --> </td> </tr> </tbody> </table> </details> ## 🧪 Testing <!-- Explain how this change can be tested (or why it can't be tested) --> ## ☑️ Checklist - [ ] I have signed the [Stream CLA](https://docs.google.com/forms/d/e/1FAIpQLScFKsKkAJI7mhCr7K9rEIOpqIDThrWxuvxnwUq2XkHyG154vQ/viewform) (required) - [ ] PR targets the `develop` branch - [ ] Documentation is updated - [ ] New code is tested in main example apps, including all possible scenarios - [ ] SampleApp iOS and Android - [ ] Expo iOS and Android | 2 个月前 | |
feat!: offline support (#1670) * feat: wip jump to a message after using the new around messages api * refactor: scroll to first unread channel * refactor: loading more recent messages should not rely on isUpToDate flag anymore * fix: set noMoreMessages flag to false when we are jumping to a message * fix: scroll to bottom button should not rely on isUpToDate flag * fix: show scroll to bottom button using the new hasNoMoreRecentMessages prop * fix: replace more isUpToDate calls with hasNoMoreRecentMessagesToLoad * feat: add documentation for hasNoMoreRecentMessagesToLoad * feat: update stream-chat-js to 6.3.0 * chore: remove unused import of Text * fix: readd the removed console log of error * feat: add documentation for loadChannelAroundMessage * chore: remove unneeded comment * chore: move scrollToDebounceTimeoutRef to the top of messageList * fix: remove unused variables * fix: update jest snapshot for the new prop addition for messageList * fix: remove unused useEffect in messageList * fix: fix the failing message list test * fix: channel unread indicator was showing up even when marked read * fix: scroll to bottom indicator must not be always shown on open * Revert "fix: fix the failing message list test" This reverts commit d6057445c5a8c48a0e75386f029286103c09dcc6. * fix: sometimes the channel was not loaded to the latest message * feat: add maxToRenderPerBatch prop to the messageList this reduces the scrollToIndex failure rate * fix: when scrolling to a non rendered item, highlight was not shown * fix: update snapshot to fix unit test * fix: scroll to messageId didnt work if scrollToFirstUnreadMsg is set * fix: ensure setTargetedMessage happens after messages array is copied * fix: simplified channel logic of messageId scroll * fix: remove unnecessary console log * docs: create a new version of docs for v5 (#1596) * docs: upgrade helper guide (#1605) * docs: cut a new version of docs for v5 * docs: upgrade helper guide * docs: drop v5 changes from v4 docs * docs: add reason for cameraroll fork replacement * docs: make removing cameraroll to be non-optional Co-authored-by: Santhosh Vaiyapuri <santhoshvai@gmail.com> * feat: offline support (#1527) * feat: offline support * refactor: drop un-used function pragmaUserVersion * refactor: reverting changes to ChannelPreview * fix: fixing migration code issue * refactor: drop limits from queries * refactor: handling of message.read events and reads entity * refactor: added members to separate table * refactor: relative explicit query with left join to enrich users * refactor: cleanup and reorganizing * refactor: added index and foreign key constraints * refactor: changes to be compatible with js client * test: mocking sqlite * refactor: added missing fields on channels table * refactor: changes to be in sync with event from js client * refactor: renaming table and cleanup of columns * refactor: moving all quick-sqlite logic to separate class * test: added simple test for offline support * refactor: handle member related events * refactor: added usage of sync api * refactor: cleaning up un-necessary packages * refactor: fixed issue with update message foreign key constraint failure * refactor: cleanup * refactor: cleanup * tests: writing tests for offline feature * refactor: removed dev-menu package and usage * refactor: remove unused initDevMenu import * refactor: remove un-used flipper packages * docs: adding code comments * refactor: removing unnecessary generics * refactor: cleanup of mapper functions * refactor: renaming offlineChannelsActive to staticChannelsActive * refactor: removed metro config changes * buiild: fixed issue with manual release script * refactor: cleanup of handleEventToSyncDB * refactor: fixing lint issue * fix: removed redundant usage of useStreami18n hook * fix: issue with message not displayed in static state * build: updating stream-chat version * fix: issue with appendWhereClause and undefined value * fix: issue with members state initialization * build: do not format on save * fix: issue mapping memberCount to api response * build: upgrading stream-chat version * fix: reposition image error indicator * refactor: use network error handling to useLoadingImage * fix: image loading issue after network is recovered * fix: logic for sync api and lint issues * feat: point cameraroll dependency to the stream fork version * fix: message.new event handling * refactor: remove unnecessary client as hook dep * refactor: code review changes * refactor: moving offline support logic to Chat component * refactor: fix lint and typescript issues * refactor: handle quick-sqlite not being installed in better way * docs: lint fixes Co-authored-by: Mads Røskar <madshvero@gmail.com> Co-authored-by: stevegalili <galiliziv@gmail.com> Co-authored-by: Santhosh Vaiyapuri <santhoshvai@gmail.com> * build: fix the doc paths * docs: update upgrade helper doc * docs: update upgrade helper doc with logout logic changes * docs: change rc to beta in version label * docs: add pod install command to upgrade helper * build: update target branch name * fix: flipper database plugin setup * fix: handling of createSelectQuery function * build: upgrade better sqlite and quick sqlite dev dep * fix: open the selected image when pressed in the image grid (#1585) * refactor!: rename gallery state objects to match their data * fix: open the selected image when pressed in the image grid * style: reorder object keys to be alphabetic * chore: rename image grid props * fix: rename setters to match new names * test: update snapshots * test: move bettersqlite test utils to src/test-utils * test: gitignore locally generated database files * style: reorder imports * style: remove redundant whitespace * refactor: export store apis * fix: set an initial image index for the ImageGallery (#1639) * docs: update upgrade helper guide * docs: rename setImages and setImage * docs: fix broken mdx imports * docs: remove unintended newline in import * docs: update upgrade helper guide * feat: upgrade stream-chat to 7.0.0-offline-support.4 * docs: update upgrade helper guide * docs: offline support docs * ignore intelliJ files. * Update broken external URLs * Update broken internal links * docs: replace cameraroll to our fork in install steps * docs: upgrading v4 dopcs * build: connection docusaurus gh action to develop and main * feat: remove cameraroll fork and use v5 original cameraroll * feat: upgrade stream-chat to v7 stable Co-authored-by: Santhosh Vaiyapuri <santhoshvai@gmail.com> Co-authored-by: Vishal Narkhede <vishalnarkhede.iitd@gmail.com> Co-authored-by: Mads Røskar <madshvero@gmail.com> Co-authored-by: Mads Røskar <mads.roskar@getstream.io> Co-authored-by: nash0x7e2 <mail@neevash.dev> docs: update upgrade-helper for v5 docs: update stream-chat version in docs docs: make v5 docs stable | 3 年前 | |
chore: upgrade to TypeScript 6.0.3, ES2022 target, and shared ts-config presets (#3663) ## What & why Upgrades every workspace to **TypeScript 6.0.3** with **`target: ES2022`**, and removes tsconfig duplication via a new shared preset package. Enabling type-checking across the previously-unchecked packages also surfaced (and this PR fixes) a pre-existing bug in the core package's published type resolution plus a batch of latent type errors. ## Changes ### Shared config - New **private** `@stream-io/typescript-config` workspace (`configs/typescript-config/`): - `base.json` — cross-cutting policy (ES2022 target, strict, interop, …) - `library.json` — full React Native library config (extends `base`) - Core, the native/expo wrappers, and all 3 example apps extend these instead of duplicating compiler options. Example apps array-extend `["<framework base>", "@stream-io/typescript-config/base.json"]`. ### TypeScript 6.0.3 / ES2022 - TS `6.0.3` in all 7 manifests; `target: ES2022` everywhere. - `lib` kept at `ESNext` — the SDK uses the ES2023 `Array.prototype.toReversed()`. - TS 6.0 no longer auto-includes `@types/jest`, so it's referenced explicitly from a test-only `package/src/__tests__/jest-globals.d.ts` (excluded from the published build). ### Core publishing fix (consumer-facing) - `react-native-builder-bob` emitted declarations under `lib/typescript/src/` while `package.json#types` pointed at `lib/typescript/index.d.ts` — so TS consumers couldn't resolve the SDK's types via `types`. Added `rootDir: "./src"` so declarations emit flat to match `types`. This was also the root cause that blocked the wrappers/examples from resolving core's types. - Exported `PickImageOptions` from the core entrypoint (defined+exported in `native.ts` but never surfaced from `index`). ### Wrappers (`stream-chat-react-native`, `stream-chat-expo`) - Added a `typecheck` script + tsconfig (they had neither). The dynamic optional-`require` shims relax `noImplicitAny`/`strictNullChecks`/unused checks (kept `noImplicitReturns`). - Fixed real bugs: missing `return`s in `shareImage`, missing `resizeMode`/`rate` on the video shim, an inconsistent `startRecording` return shape. ### Example apps - Fixed ~60 pre-existing latent type errors unmasked by enabling typecheck: theme palette typing (the legacy flat `colors` palette, read via a local `AppTheme` cast — behavior-preserving), null-safety guards, and several SDK-API-drift fixes. ### CI - `check-pr.yml` now runs `yarn typecheck` across the whole workspace (core + 2 wrappers + 3 examples) instead of only the core package; the root `typecheck` aggregate includes the wrappers. ## Verification - `yarn build` ✅ - `yarn typecheck` (core + 2 wrappers + 3 examples) ✅ **0 errors** - `yarn lint` ✅ ## Notes for reviewers - **Commit type**: filed as `chore:` (release-neutral). The core changes (flat `types` path + `PickImageOptions` export) are genuinely consumer-facing — if you want them shipped, retype as `fix:` to cut a patch. - **Wrapper strictness**: `strictNullChecks`/`noImplicitAny` are relaxed **only** for the two wrapper packages (dynamic optional-dep shims), not for core. - **Example theming**: the apps' custom `colors` palette was already inert for SDK theming (the SDK reads semantics/primitives, not `theme.colors`); this PR preserves that behavior. Migrating the palette to the token model to restore custom branding would be a separate enhancement. - Did not run the full unit suite locally (the only core source change is the additive `PickImageOptions` export); CI runs `test:coverage`. --------- Co-authored-by: Ivan Sekovanikj <ivan.sekovanikj@getstream.io> | 28 天前 | |
chore(yarn): migrate to Yarn 4 + native workspaces (#3594) ## 🎯 Goal Move us onto Yarn 4 with native workspaces and drop Lerna. The `.yarnrc.yml` was already half-migrated, but `yarnPath` still pointed at the v1 binary — this finishes that off. ## 🛠 Implementation details Tooling only; nothing in `package/src` changes. Roughly: - `.yarn/releases/` swapped to 4.14.1, and all seven `yarn.lock` files migrated v1 → v8 in place — resolutions preserved, no drift. - Single root `workspaces` array now covers `package/`, both native wrapper packages, and all three example apps. `link:../../package/*` becomes `workspace:^`, nested lockfiles are gone, and the install-and-build-sdk composite action collapses to one `yarn install --immutable`. - Shared-native sync + husky setup run from the core SDK workspace's `postinstall` (Yarn 4 doesn't run root-workspace lifecycle scripts on install). - Lerna removed: `release/release.config.js` no longer reads `lerna.json`, and `release` / `release-next` / `extract-changelog` use `yarn workspaces foreach`. - Husky 6 → 9 (the v6 hook boilerplate is on the deprecation path). - `.yarnrc.yml` picks up the conservative hardening tier: `enableHardenedMode`, `npmMinimalAgeGate: 3d`, `enableScripts: false` with a small `dependenciesMeta` allowlist for the packages that genuinely need to build (`@swc/core`, `better-sqlite3`, `react-native-nitro-modules`, `unrs-resolver`). - CI workflows cache `.yarn/` via setup-node; drive-by fix for the deprecated `::set-output` calls in `changelog-preview.yml`. ## 🎨 UI Changes N/A. ## 🧪 Testing Locally: `yarn install --immutable` is clean, `yarn lint` + `yarn build` pass, husky hooks fired on every commit in this PR. Can't verify locally: example apps on real devices, and the release flow itself. The Lerna → `yarn workspaces foreach` rewrite is the riskiest single change — worth a dry-run on a throwaway branch before merging. ## ☑️ Checklist - [x] I have signed the [Stream CLA](https://docs.google.com/forms/d/e/1FAIpQLScFKsKkAJI7mhCr7K9rEIOpqIDThrWxuvxnwUq2XkHyG154vQ/viewform) (required) - [x] PR targets the `develop` branch - [x] Documentation is updated - [ ] New code is tested in main example apps, including all possible scenarios - [ ] SampleApp iOS and Android - [ ] Expo iOS and Android --------- Co-authored-by: Ivan Sekovanikj <ivan.sekovanikj@getstream.io> | 3 个月前 | |
feat: offline db encryption (#3780) ## 🎯 Goal Let integrators encrypt the offline database at rest. The offline cache stores channels, messages, members, drafts and reminders, and right now we write all of it as plaintext `SQLite`. It's opt-in. Apps that don't pass the new prop behave exactly as they do today. One thing to know up front, since it shapes the rest of the PR: `op-sqlite` accepts an `encryptionKey` on a build without `SQLCipher` and then ignores it. You get a plaintext database and no error at any layer. So part of this change is detecting that and refusing to open the database, instead of passing the key along and assuming it was used. Accompanying docs PR: https://github.com/GetStream/docs-content/pull/1521 ## 🛠 Implementation details ### API `Chat` takes one new prop: ```tsx <Chat client={client} enableOfflineSupport getEncryptionKey={getEncryptionKey}> ``` `getEncryptionKey?: () => Promise<string | undefined>` runs once per database open, so once per launch and again after a sign-out. Its result is passed to `SQLCipher` through `op-sqlite`. `SqliteClientError` and `SqliteClientErrorCode` are exported too. ### We throw instead of recovering When the database can't be opened with the encryption that was asked for, `Chat` throws a `SqliteClientError` from render and the integrator's error boundary handles it. We don't fall back to plaintext, we don't switch offline support off, and we don't delete anything. The reason is that all of those recoveries have a security consequence and there's no default that's right for everyone. Falling back to plaintext defeats the point of the feature and nothing tells you it happened. Dropping the cache decides a compliance question for the integrator. Deleting the file throws away offline actions that are still queued. We also can't tell "the Keystore isn't unlocked yet, try again shortly" from "something is wrong here, sign this device out". So we detect the failure and classify it, and the app decides what to do about it. ### Scenarios | Scenario | What it means | What the SDK does | Recommended recovery | | ------------------------------------------------------- | ------------------------------------------------------------ | ---------------------------------------------- | ------------------------------------------------------------------ | | No `getEncryptionKey` passed | Encryption not requested | Opens plaintext, same as today | n/a | | Key supplied, fresh install | Nothing on disk yet | Creates the database encrypted with that key | n/a | | Key supplied, plaintext database already on disk | Integrator is turning encryption on for an existing install | Throws `OFFLINE_DB_UNREADABLE` | Delete the database, remount `Chat` | | Key differs from the one the database was written with | Key rotated, or read from the wrong place | Throws `OFFLINE_DB_UNREADABLE` | Delete the database, remount `Chat` | | `getEncryptionKey` removed, encrypted database on disk | Integrator is turning encryption off again | Throws `OFFLINE_DB_UNREADABLE` | Delete the database, remount `Chat` | | `getEncryptionKey` throws | Key isn't available yet, e.g. Keystore still locked | Throws `ENCRYPTION_KEY_UNAVAILABLE` | Remount to retry, e.g. on next app foreground | | `getEncryptionKey` resolves `undefined` | Same as above | Throws `ENCRYPTION_KEY_UNAVAILABLE` | Remount to retry, e.g. on next app foreground | | Key supplied, native build has no `SQLCipher` | The key would be ignored and the database left plaintext | Throws `SQLCIPHER_BUILD_MISSING`, doesn't open | Not fixable at runtime, remount with `enableOfflineSupport={false}` | | Database file corrupted | Nothing to do with encryption | Throws `OFFLINE_DB_UNREADABLE` | Delete the database, remount `Chat` | Two of those rows need a closer look in review. `OFFLINE_DB_UNREADABLE` is not gated on `getEncryptionKey` being set, and that's on purpose, because of the "turning encryption off again" row. If we only threw it when a key was supplied, an integrator removing the prop would get a blank screen instead of an error they can recover from. I hit that on device. The last row is why the boundary is useful even for apps that never use encryption. A corrupted database gives you the same code, so anything using `enableOfflineSupport` can end up there. ### Where the error comes from `AbstractOfflineDB.init` in the LLC catches whatever `initializeDB` throws and doesn't re-throw it, so a caller can't find out why initialisation failed. I left that alone, because changing it would tie this PR to an LLC release. `OfflineDB` stores the reason on the instance on the way out instead, and the new hook reads it back once `init` has settled. No LLC changes needed for this. - `SqliteClient` resolves the key, opens through `SQLCipher` and maps failures onto the codes above. It also gets `preflightEncryption()`, which runs before `setOfflineDBApi`. Without that ordering the client attaches a database that's already dead, and the unguarded `await this.offlineDb.upsertChannels(...)` inside `queryChannels` rejects. You end up on a loading screen that never resolves. - `useInitializeOfflineDb()` is new and does preflight, attach, init and raise, with the init options behind an `options` param. It's pulled out of `Chat`, which loses 72 lines. - `OfflineDB` records `initializationError` and re-throws, so `init` still marks the database uninitialised. ## 🎨 UI Changes ## 🧪 Testing <!-- Explain how this change can be tested (or why it can't be tested) --> ## ☑️ Checklist - [x] I have signed the [Stream CLA](https://docs.google.com/forms/d/e/1FAIpQLScFKsKkAJI7mhCr7K9rEIOpqIDThrWxuvxnwUq2XkHyG154vQ/viewform) (required) - [x] PR targets the `develop` branch - [x] Documentation is updated - [ ] New code is tested in main example apps, including all possible scenarios - [ ] SampleApp iOS and Android - [ ] Expo iOS and Android | 12 天前 | |
feat: offline db encryption (#3780) ## 🎯 Goal Let integrators encrypt the offline database at rest. The offline cache stores channels, messages, members, drafts and reminders, and right now we write all of it as plaintext `SQLite`. It's opt-in. Apps that don't pass the new prop behave exactly as they do today. One thing to know up front, since it shapes the rest of the PR: `op-sqlite` accepts an `encryptionKey` on a build without `SQLCipher` and then ignores it. You get a plaintext database and no error at any layer. So part of this change is detecting that and refusing to open the database, instead of passing the key along and assuming it was used. Accompanying docs PR: https://github.com/GetStream/docs-content/pull/1521 ## 🛠 Implementation details ### API `Chat` takes one new prop: ```tsx <Chat client={client} enableOfflineSupport getEncryptionKey={getEncryptionKey}> ``` `getEncryptionKey?: () => Promise<string | undefined>` runs once per database open, so once per launch and again after a sign-out. Its result is passed to `SQLCipher` through `op-sqlite`. `SqliteClientError` and `SqliteClientErrorCode` are exported too. ### We throw instead of recovering When the database can't be opened with the encryption that was asked for, `Chat` throws a `SqliteClientError` from render and the integrator's error boundary handles it. We don't fall back to plaintext, we don't switch offline support off, and we don't delete anything. The reason is that all of those recoveries have a security consequence and there's no default that's right for everyone. Falling back to plaintext defeats the point of the feature and nothing tells you it happened. Dropping the cache decides a compliance question for the integrator. Deleting the file throws away offline actions that are still queued. We also can't tell "the Keystore isn't unlocked yet, try again shortly" from "something is wrong here, sign this device out". So we detect the failure and classify it, and the app decides what to do about it. ### Scenarios | Scenario | What it means | What the SDK does | Recommended recovery | | ------------------------------------------------------- | ------------------------------------------------------------ | ---------------------------------------------- | ------------------------------------------------------------------ | | No `getEncryptionKey` passed | Encryption not requested | Opens plaintext, same as today | n/a | | Key supplied, fresh install | Nothing on disk yet | Creates the database encrypted with that key | n/a | | Key supplied, plaintext database already on disk | Integrator is turning encryption on for an existing install | Throws `OFFLINE_DB_UNREADABLE` | Delete the database, remount `Chat` | | Key differs from the one the database was written with | Key rotated, or read from the wrong place | Throws `OFFLINE_DB_UNREADABLE` | Delete the database, remount `Chat` | | `getEncryptionKey` removed, encrypted database on disk | Integrator is turning encryption off again | Throws `OFFLINE_DB_UNREADABLE` | Delete the database, remount `Chat` | | `getEncryptionKey` throws | Key isn't available yet, e.g. Keystore still locked | Throws `ENCRYPTION_KEY_UNAVAILABLE` | Remount to retry, e.g. on next app foreground | | `getEncryptionKey` resolves `undefined` | Same as above | Throws `ENCRYPTION_KEY_UNAVAILABLE` | Remount to retry, e.g. on next app foreground | | Key supplied, native build has no `SQLCipher` | The key would be ignored and the database left plaintext | Throws `SQLCIPHER_BUILD_MISSING`, doesn't open | Not fixable at runtime, remount with `enableOfflineSupport={false}` | | Database file corrupted | Nothing to do with encryption | Throws `OFFLINE_DB_UNREADABLE` | Delete the database, remount `Chat` | Two of those rows need a closer look in review. `OFFLINE_DB_UNREADABLE` is not gated on `getEncryptionKey` being set, and that's on purpose, because of the "turning encryption off again" row. If we only threw it when a key was supplied, an integrator removing the prop would get a blank screen instead of an error they can recover from. I hit that on device. The last row is why the boundary is useful even for apps that never use encryption. A corrupted database gives you the same code, so anything using `enableOfflineSupport` can end up there. ### Where the error comes from `AbstractOfflineDB.init` in the LLC catches whatever `initializeDB` throws and doesn't re-throw it, so a caller can't find out why initialisation failed. I left that alone, because changing it would tie this PR to an LLC release. `OfflineDB` stores the reason on the instance on the way out instead, and the new hook reads it back once `init` has settled. No LLC changes needed for this. - `SqliteClient` resolves the key, opens through `SQLCipher` and maps failures onto the codes above. It also gets `preflightEncryption()`, which runs before `setOfflineDBApi`. Without that ordering the client attaches a database that's already dead, and the unguarded `await this.offlineDb.upsertChannels(...)` inside `queryChannels` rejects. You end up on a loading screen that never resolves. - `useInitializeOfflineDb()` is new and does preflight, attach, init and raise, with the init options behind an `options` param. It's pulled out of `Chat`, which loses 72 lines. - `OfflineDB` records `initializationError` and re-throws, so `init` still marks the database uninitialised. ## 🎨 UI Changes ## 🧪 Testing <!-- Explain how this change can be tested (or why it can't be tested) --> ## ☑️ Checklist - [x] I have signed the [Stream CLA](https://docs.google.com/forms/d/e/1FAIpQLScFKsKkAJI7mhCr7K9rEIOpqIDThrWxuvxnwUq2XkHyG154vQ/viewform) (required) - [x] PR targets the `develop` branch - [x] Documentation is updated - [ ] New code is tested in main example apps, including all possible scenarios - [ ] SampleApp iOS and Android - [ ] Expo iOS and Android | 12 天前 | |
perf: gallery virtualization (#3675) ## 🎯 Goal Our image gallery was never properly virtualized and mounted one slide component per asset for **all** loaded media (`assets.map(...)`), so scroll/swipe jank scaled with the asset count. On a media heavy channel roughly **40% of frames were janky**, driven by `O(N)` animated style worklets rerunning on the UI thread every frame. This bounds that cost so gallery performance no longer degrades as channels accumulate media. This was relatively fine before, when `ChannelDetails` hadn't been introduced yet but now poses an actual challenge. ## 🛠 Implementation details - Extracted the slide list into a windowed `GalleryPager` that mounts only the slides within `PAGER_WINDOW_RADIUS` of the current index, instead of all N. Mounted slides drop from ~N to ~9. - A single **leading spacer** reproduces the flex width of the skipped slides, so the rendered slides keep their exact natural positions. The per slide transforms (`useAnimatedGalleryStyle`) are a pure function of `index` + `flex` position, so windowing the mount should be fine - `GalleryPager` subscribes to `currentIndex` itself, so paging rerenders only the small slide list, never the parent (gesture objects/`GestureDetector` stay stable). - The existing per slide `shouldRender` load gate is retained (image +-3, video +-1) for now so windowing bounds the *mount*; `shouldRender` still bounds *content load* (notably capping live native video players within the mounted set). Measured on a debug `SampleApp` (on a media heavy channel), provided below are the results (naturally, taken from the best 5 runs against baseline and the worst 5 runs against this branch across of many, many runs): | Metric | Before | After | Improvement | |---|---|---|---| | **Janky frames** | 40.4% | **14.1%** | **−65%** (−26 pts) | | **Median frame time** | 42 ms | **21 ms** | **2× faster** (−50%) | | 90th-pct frame time | 79 ms | 46 ms | −42% | | 95th-pct frame time | 95 ms | 67 ms | −29% | | 99th-pct frame time | 150 ms | 133 ms | −11% | | **Missed vsyncs** | 154 | **57** | **2.7× fewer** (−63%) | | Frames rendered (same path) | 856 | 1,039 | +21% throughput | | Mounted slide components | ~165 | **~9** | **~18× fewer** | Jank no longer scales with asset count (after jank is flat across N, where before it rose). ## 🎨 UI Changes <!-- Add relevant screenshots --> <details> <summary>iOS</summary> <table> <thead> <tr> <td>Before</td> <td>After</td> </tr> </thead> <tbody> <tr> <td> <!--<img src="" /> --> </td> <td> <!--<img src="" /> --> </td> </tr> </tbody> </table> </details> <details> <summary>Android</summary> <table> <thead> <tr> <td>Before</td> <td>After</td> </tr> </thead> <tbody> <tr> <td> <!--<img src="" /> --> </td> <td> <!--<img src="" /> --> </td> </tr> </tbody> </table> </details> ## 🧪 Testing <!-- Explain how this change can be tested (or why it can't be tested) --> ## ☑️ Checklist - [ ] I have signed the [Stream CLA](https://docs.google.com/forms/d/e/1FAIpQLScFKsKkAJI7mhCr7K9rEIOpqIDThrWxuvxnwUq2XkHyG154vQ/viewform) (required) - [ ] PR targets the `develop` branch - [ ] Documentation is updated - [ ] New code is tested in main example apps, including all possible scenarios - [ ] SampleApp iOS and Android - [ ] Expo iOS and Android | 2 个月前 | |
fix: switch to `npm` actions with `--no-workspaces` (#3622) ## 🎯 Goal This PR should address the release process issues we introduced with the Yarn Berry implementation. ## 🛠 Implementation details <!-- Provide a description of the implementation --> ## 🎨 UI Changes <!-- Add relevant screenshots --> <details> <summary>iOS</summary> <table> <thead> <tr> <td>Before</td> <td>After</td> </tr> </thead> <tbody> <tr> <td> <!--<img src="" /> --> </td> <td> <!--<img src="" /> --> </td> </tr> </tbody> </table> </details> <details> <summary>Android</summary> <table> <thead> <tr> <td>Before</td> <td>After</td> </tr> </thead> <tbody> <tr> <td> <!--<img src="" /> --> </td> <td> <!--<img src="" /> --> </td> </tr> </tbody> </table> </details> ## 🧪 Testing <!-- Explain how this change can be tested (or why it can't be tested) --> ## ☑️ Checklist - [ ] I have signed the [Stream CLA](https://docs.google.com/forms/d/e/1FAIpQLScFKsKkAJI7mhCr7K9rEIOpqIDThrWxuvxnwUq2XkHyG154vQ/viewform) (required) - [ ] PR targets the `develop` branch - [ ] Documentation is updated - [ ] New code is tested in main example apps, including all possible scenarios - [ ] SampleApp iOS and Android - [ ] Expo iOS and Android | 3 个月前 | |
chore(yarn): migrate to Yarn 4 + native workspaces (#3594) ## 🎯 Goal Move us onto Yarn 4 with native workspaces and drop Lerna. The `.yarnrc.yml` was already half-migrated, but `yarnPath` still pointed at the v1 binary — this finishes that off. ## 🛠 Implementation details Tooling only; nothing in `package/src` changes. Roughly: - `.yarn/releases/` swapped to 4.14.1, and all seven `yarn.lock` files migrated v1 → v8 in place — resolutions preserved, no drift. - Single root `workspaces` array now covers `package/`, both native wrapper packages, and all three example apps. `link:../../package/*` becomes `workspace:^`, nested lockfiles are gone, and the install-and-build-sdk composite action collapses to one `yarn install --immutable`. - Shared-native sync + husky setup run from the core SDK workspace's `postinstall` (Yarn 4 doesn't run root-workspace lifecycle scripts on install). - Lerna removed: `release/release.config.js` no longer reads `lerna.json`, and `release` / `release-next` / `extract-changelog` use `yarn workspaces foreach`. - Husky 6 → 9 (the v6 hook boilerplate is on the deprecation path). - `.yarnrc.yml` picks up the conservative hardening tier: `enableHardenedMode`, `npmMinimalAgeGate: 3d`, `enableScripts: false` with a small `dependenciesMeta` allowlist for the packages that genuinely need to build (`@swc/core`, `better-sqlite3`, `react-native-nitro-modules`, `unrs-resolver`). - CI workflows cache `.yarn/` via setup-node; drive-by fix for the deprecated `::set-output` calls in `changelog-preview.yml`. ## 🎨 UI Changes N/A. ## 🧪 Testing Locally: `yarn install --immutable` is clean, `yarn lint` + `yarn build` pass, husky hooks fired on every commit in this PR. Can't verify locally: example apps on real devices, and the release flow itself. The Lerna → `yarn workspaces foreach` rewrite is the riskiest single change — worth a dry-run on a throwaway branch before merging. ## ☑️ Checklist - [x] I have signed the [Stream CLA](https://docs.google.com/forms/d/e/1FAIpQLScFKsKkAJI7mhCr7K9rEIOpqIDThrWxuvxnwUq2XkHyG154vQ/viewform) (required) - [x] PR targets the `develop` branch - [x] Documentation is updated - [ ] New code is tested in main example apps, including all possible scenarios - [ ] SampleApp iOS and Android - [ ] Expo iOS and Android --------- Co-authored-by: Ivan Sekovanikj <ivan.sekovanikj@getstream.io> | 3 个月前 | |
chore(yarn): migrate to Yarn 4 + native workspaces (#3594) ## 🎯 Goal Move us onto Yarn 4 with native workspaces and drop Lerna. The `.yarnrc.yml` was already half-migrated, but `yarnPath` still pointed at the v1 binary — this finishes that off. ## 🛠 Implementation details Tooling only; nothing in `package/src` changes. Roughly: - `.yarn/releases/` swapped to 4.14.1, and all seven `yarn.lock` files migrated v1 → v8 in place — resolutions preserved, no drift. - Single root `workspaces` array now covers `package/`, both native wrapper packages, and all three example apps. `link:../../package/*` becomes `workspace:^`, nested lockfiles are gone, and the install-and-build-sdk composite action collapses to one `yarn install --immutable`. - Shared-native sync + husky setup run from the core SDK workspace's `postinstall` (Yarn 4 doesn't run root-workspace lifecycle scripts on install). - Lerna removed: `release/release.config.js` no longer reads `lerna.json`, and `release` / `release-next` / `extract-changelog` use `yarn workspaces foreach`. - Husky 6 → 9 (the v6 hook boilerplate is on the deprecation path). - `.yarnrc.yml` picks up the conservative hardening tier: `enableHardenedMode`, `npmMinimalAgeGate: 3d`, `enableScripts: false` with a small `dependenciesMeta` allowlist for the packages that genuinely need to build (`@swc/core`, `better-sqlite3`, `react-native-nitro-modules`, `unrs-resolver`). - CI workflows cache `.yarn/` via setup-node; drive-by fix for the deprecated `::set-output` calls in `changelog-preview.yml`. ## 🎨 UI Changes N/A. ## 🧪 Testing Locally: `yarn install --immutable` is clean, `yarn lint` + `yarn build` pass, husky hooks fired on every commit in this PR. Can't verify locally: example apps on real devices, and the release flow itself. The Lerna → `yarn workspaces foreach` rewrite is the riskiest single change — worth a dry-run on a throwaway branch before merging. ## ☑️ Checklist - [x] I have signed the [Stream CLA](https://docs.google.com/forms/d/e/1FAIpQLScFKsKkAJI7mhCr7K9rEIOpqIDThrWxuvxnwUq2XkHyG154vQ/viewform) (required) - [x] PR targets the `develop` branch - [x] Documentation is updated - [ ] New code is tested in main example apps, including all possible scenarios - [ ] SampleApp iOS and Android - [ ] Expo iOS and Android --------- Co-authored-by: Ivan Sekovanikj <ivan.sekovanikj@getstream.io> | 3 个月前 | |
chore(yarn): migrate to Yarn 4 + native workspaces (#3594) ## 🎯 Goal Move us onto Yarn 4 with native workspaces and drop Lerna. The `.yarnrc.yml` was already half-migrated, but `yarnPath` still pointed at the v1 binary — this finishes that off. ## 🛠 Implementation details Tooling only; nothing in `package/src` changes. Roughly: - `.yarn/releases/` swapped to 4.14.1, and all seven `yarn.lock` files migrated v1 → v8 in place — resolutions preserved, no drift. - Single root `workspaces` array now covers `package/`, both native wrapper packages, and all three example apps. `link:../../package/*` becomes `workspace:^`, nested lockfiles are gone, and the install-and-build-sdk composite action collapses to one `yarn install --immutable`. - Shared-native sync + husky setup run from the core SDK workspace's `postinstall` (Yarn 4 doesn't run root-workspace lifecycle scripts on install). - Lerna removed: `release/release.config.js` no longer reads `lerna.json`, and `release` / `release-next` / `extract-changelog` use `yarn workspaces foreach`. - Husky 6 → 9 (the v6 hook boilerplate is on the deprecation path). - `.yarnrc.yml` picks up the conservative hardening tier: `enableHardenedMode`, `npmMinimalAgeGate: 3d`, `enableScripts: false` with a small `dependenciesMeta` allowlist for the packages that genuinely need to build (`@swc/core`, `better-sqlite3`, `react-native-nitro-modules`, `unrs-resolver`). - CI workflows cache `.yarn/` via setup-node; drive-by fix for the deprecated `::set-output` calls in `changelog-preview.yml`. ## 🎨 UI Changes N/A. ## 🧪 Testing Locally: `yarn install --immutable` is clean, `yarn lint` + `yarn build` pass, husky hooks fired on every commit in this PR. Can't verify locally: example apps on real devices, and the release flow itself. The Lerna → `yarn workspaces foreach` rewrite is the riskiest single change — worth a dry-run on a throwaway branch before merging. ## ☑️ Checklist - [x] I have signed the [Stream CLA](https://docs.google.com/forms/d/e/1FAIpQLScFKsKkAJI7mhCr7K9rEIOpqIDThrWxuvxnwUq2XkHyG154vQ/viewform) (required) - [x] PR targets the `develop` branch - [x] Documentation is updated - [ ] New code is tested in main example apps, including all possible scenarios - [ ] SampleApp iOS and Android - [ ] Expo iOS and Android --------- Co-authored-by: Ivan Sekovanikj <ivan.sekovanikj@getstream.io> | 3 个月前 | |
chore(yarn): migrate to Yarn 4 + native workspaces (#3594) ## 🎯 Goal Move us onto Yarn 4 with native workspaces and drop Lerna. The `.yarnrc.yml` was already half-migrated, but `yarnPath` still pointed at the v1 binary — this finishes that off. ## 🛠 Implementation details Tooling only; nothing in `package/src` changes. Roughly: - `.yarn/releases/` swapped to 4.14.1, and all seven `yarn.lock` files migrated v1 → v8 in place — resolutions preserved, no drift. - Single root `workspaces` array now covers `package/`, both native wrapper packages, and all three example apps. `link:../../package/*` becomes `workspace:^`, nested lockfiles are gone, and the install-and-build-sdk composite action collapses to one `yarn install --immutable`. - Shared-native sync + husky setup run from the core SDK workspace's `postinstall` (Yarn 4 doesn't run root-workspace lifecycle scripts on install). - Lerna removed: `release/release.config.js` no longer reads `lerna.json`, and `release` / `release-next` / `extract-changelog` use `yarn workspaces foreach`. - Husky 6 → 9 (the v6 hook boilerplate is on the deprecation path). - `.yarnrc.yml` picks up the conservative hardening tier: `enableHardenedMode`, `npmMinimalAgeGate: 3d`, `enableScripts: false` with a small `dependenciesMeta` allowlist for the packages that genuinely need to build (`@swc/core`, `better-sqlite3`, `react-native-nitro-modules`, `unrs-resolver`). - CI workflows cache `.yarn/` via setup-node; drive-by fix for the deprecated `::set-output` calls in `changelog-preview.yml`. ## 🎨 UI Changes N/A. ## 🧪 Testing Locally: `yarn install --immutable` is clean, `yarn lint` + `yarn build` pass, husky hooks fired on every commit in this PR. Can't verify locally: example apps on real devices, and the release flow itself. The Lerna → `yarn workspaces foreach` rewrite is the riskiest single change — worth a dry-run on a throwaway branch before merging. ## ☑️ Checklist - [x] I have signed the [Stream CLA](https://docs.google.com/forms/d/e/1FAIpQLScFKsKkAJI7mhCr7K9rEIOpqIDThrWxuvxnwUq2XkHyG154vQ/viewform) (required) - [x] PR targets the `develop` branch - [x] Documentation is updated - [ ] New code is tested in main example apps, including all possible scenarios - [ ] SampleApp iOS and Android - [ ] Expo iOS and Android --------- Co-authored-by: Ivan Sekovanikj <ivan.sekovanikj@getstream.io> | 3 个月前 | |
troubleshooting docs | 5 年前 | |
fix: bump nitro-sound to latest on SampleApp (#3757) ## 🎯 Goal This PR bumps the `react-native-nitro-sound` version to latest as a new version's been released which should resolve the iOS release only build issues. It's basically a continuation of [this PR](https://github.com/GetStream/stream-chat-react-native/pull/3650), where the details and the reference ticket should be explained. Since the issue was only happening with Testflight builds specifically for our `SampleApp`, we can test on the actual one when it comes out. ## 🛠 Implementation details <!-- Provide a description of the implementation --> ## 🎨 UI Changes <!-- Add relevant screenshots --> <details> <summary>iOS</summary> <table> <thead> <tr> <td>Before</td> <td>After</td> </tr> </thead> <tbody> <tr> <td> <!--<img src="" /> --> </td> <td> <!--<img src="" /> --> </td> </tr> </tbody> </table> </details> <details> <summary>Android</summary> <table> <thead> <tr> <td>Before</td> <td>After</td> </tr> </thead> <tbody> <tr> <td> <!--<img src="" /> --> </td> <td> <!--<img src="" /> --> </td> </tr> </tbody> </table> </details> ## 🧪 Testing <!-- Explain how this change can be tested (or why it can't be tested) --> ## ☑️ Checklist - [ ] I have signed the [Stream CLA](https://docs.google.com/forms/d/e/1FAIpQLScFKsKkAJI7mhCr7K9rEIOpqIDThrWxuvxnwUq2XkHyG154vQ/viewform) (required) - [ ] PR targets the `develop` branch - [ ] Documentation is updated - [ ] New code is tested in main example apps, including all possible scenarios - [ ] SampleApp iOS and Android - [ ] Expo iOS and Android | 26 天前 | |
chore: remove typescript messaging app (#3756) ## 🎯 Goal This is something long overdue, since we aren't really spending too much time updating or really taking care of housekeeping for the `TypescriptMessagingApp`. Especially since `SampleApp` is pretty much the same, but with a bunch extra features. Hence, I'm removing it so that it stops cluttering everything. ## 🛠 Implementation details <!-- Provide a description of the implementation --> ## 🎨 UI Changes <!-- Add relevant screenshots --> <details> <summary>iOS</summary> <table> <thead> <tr> <td>Before</td> <td>After</td> </tr> </thead> <tbody> <tr> <td> <!--<img src="" /> --> </td> <td> <!--<img src="" /> --> </td> </tr> </tbody> </table> </details> <details> <summary>Android</summary> <table> <thead> <tr> <td>Before</td> <td>After</td> </tr> </thead> <tbody> <tr> <td> <!--<img src="" /> --> </td> <td> <!--<img src="" /> --> </td> </tr> </tbody> </table> </details> ## 🧪 Testing <!-- Explain how this change can be tested (or why it can't be tested) --> ## ☑️ Checklist - [ ] I have signed the [Stream CLA](https://docs.google.com/forms/d/e/1FAIpQLScFKsKkAJI7mhCr7K9rEIOpqIDThrWxuvxnwUq2XkHyG154vQ/viewform) (required) - [ ] PR targets the `develop` branch - [ ] Documentation is updated - [ ] New code is tested in main example apps, including all possible scenarios - [ ] SampleApp iOS and Android - [ ] Expo iOS and Android | 27 天前 | |
docs: consolidate AGENTS.md; reference skills from README.md (#3751) ## 🎯 Goal - Consolidate `AGENTS.ms` and `CLAUDE.md` -> `CLAUDE.md` will stay only as a reference - Add skill reference to `README.md` file - Remove stale references/info ## 🛠 Implementation details <!-- Provide a description of the implementation --> ## 🎨 UI Changes <!-- Add relevant screenshots --> <details> <summary>iOS</summary> <table> <thead> <tr> <td>Before</td> <td>After</td> </tr> </thead> <tbody> <tr> <td> <!--<img src="" /> --> </td> <td> <!--<img src="" /> --> </td> </tr> </tbody> </table> </details> <details> <summary>Android</summary> <table> <thead> <tr> <td>Before</td> <td>After</td> </tr> </thead> <tbody> <tr> <td> <!--<img src="" /> --> </td> <td> <!--<img src="" /> --> </td> </tr> </tbody> </table> </details> ## 🧪 Testing <!-- Explain how this change can be tested (or why it can't be tested) --> ## ☑️ Checklist - [ ] I have signed the [Stream CLA](https://docs.google.com/forms/d/e/1FAIpQLScFKsKkAJI7mhCr7K9rEIOpqIDThrWxuvxnwUq2XkHyG154vQ/viewform) (required) - [ ] PR targets the `develop` branch - [ ] Documentation is updated - [ ] New code is tested in main example apps, including all possible scenarios - [ ] SampleApp iOS and Android - [ ] Expo iOS and Android | 28 天前 | |
Create CONTRIBUTING.md | 6 年前 | |
Initial commit | 7 年前 | |
chore: updating PR template | 4 年前 | |
chore: remove typescript messaging app (#3756) ## 🎯 Goal This is something long overdue, since we aren't really spending too much time updating or really taking care of housekeeping for the `TypescriptMessagingApp`. Especially since `SampleApp` is pretty much the same, but with a bunch extra features. Hence, I'm removing it so that it stops cluttering everything. ## 🛠 Implementation details <!-- Provide a description of the implementation --> ## 🎨 UI Changes <!-- Add relevant screenshots --> <details> <summary>iOS</summary> <table> <thead> <tr> <td>Before</td> <td>After</td> </tr> </thead> <tbody> <tr> <td> <!--<img src="" /> --> </td> <td> <!--<img src="" /> --> </td> </tr> </tbody> </table> </details> <details> <summary>Android</summary> <table> <thead> <tr> <td>Before</td> <td>After</td> </tr> </thead> <tbody> <tr> <td> <!--<img src="" /> --> </td> <td> <!--<img src="" /> --> </td> </tr> </tbody> </table> </details> ## 🧪 Testing <!-- Explain how this change can be tested (or why it can't be tested) --> ## ☑️ Checklist - [ ] I have signed the [Stream CLA](https://docs.google.com/forms/d/e/1FAIpQLScFKsKkAJI7mhCr7K9rEIOpqIDThrWxuvxnwUq2XkHyG154vQ/viewform) (required) - [ ] PR targets the `develop` branch - [ ] Documentation is updated - [ ] New code is tested in main example apps, including all possible scenarios - [ ] SampleApp iOS and Android - [ ] Expo iOS and Android | 27 天前 | |
chore: rename master to main (#1364) | 4 年前 | |
Create SECURITY.md | 3 年前 | |
chore: lerna & projects setup for conventional commits | 5 年前 | |
chore(yarn): migrate to Yarn 4 + native workspaces (#3594) ## 🎯 Goal Move us onto Yarn 4 with native workspaces and drop Lerna. The `.yarnrc.yml` was already half-migrated, but `yarnPath` still pointed at the v1 binary — this finishes that off. ## 🛠 Implementation details Tooling only; nothing in `package/src` changes. Roughly: - `.yarn/releases/` swapped to 4.14.1, and all seven `yarn.lock` files migrated v1 → v8 in place — resolutions preserved, no drift. - Single root `workspaces` array now covers `package/`, both native wrapper packages, and all three example apps. `link:../../package/*` becomes `workspace:^`, nested lockfiles are gone, and the install-and-build-sdk composite action collapses to one `yarn install --immutable`. - Shared-native sync + husky setup run from the core SDK workspace's `postinstall` (Yarn 4 doesn't run root-workspace lifecycle scripts on install). - Lerna removed: `release/release.config.js` no longer reads `lerna.json`, and `release` / `release-next` / `extract-changelog` use `yarn workspaces foreach`. - Husky 6 → 9 (the v6 hook boilerplate is on the deprecation path). - `.yarnrc.yml` picks up the conservative hardening tier: `enableHardenedMode`, `npmMinimalAgeGate: 3d`, `enableScripts: false` with a small `dependenciesMeta` allowlist for the packages that genuinely need to build (`@swc/core`, `better-sqlite3`, `react-native-nitro-modules`, `unrs-resolver`). - CI workflows cache `.yarn/` via setup-node; drive-by fix for the deprecated `::set-output` calls in `changelog-preview.yml`. ## 🎨 UI Changes N/A. ## 🧪 Testing Locally: `yarn install --immutable` is clean, `yarn lint` + `yarn build` pass, husky hooks fired on every commit in this PR. Can't verify locally: example apps on real devices, and the release flow itself. The Lerna → `yarn workspaces foreach` rewrite is the riskiest single change — worth a dry-run on a throwaway branch before merging. ## ☑️ Checklist - [x] I have signed the [Stream CLA](https://docs.google.com/forms/d/e/1FAIpQLScFKsKkAJI7mhCr7K9rEIOpqIDThrWxuvxnwUq2XkHyG154vQ/viewform) (required) - [x] PR targets the `develop` branch - [x] Documentation is updated - [ ] New code is tested in main example apps, including all possible scenarios - [ ] SampleApp iOS and Android - [ ] Expo iOS and Android --------- Co-authored-by: Ivan Sekovanikj <ivan.sekovanikj@getstream.io> | 3 个月前 | |
chore: remove typescript messaging app (#3756) ## 🎯 Goal This is something long overdue, since we aren't really spending too much time updating or really taking care of housekeeping for the `TypescriptMessagingApp`. Especially since `SampleApp` is pretty much the same, but with a bunch extra features. Hence, I'm removing it so that it stops cluttering everything. ## 🛠 Implementation details <!-- Provide a description of the implementation --> ## 🎨 UI Changes <!-- Add relevant screenshots --> <details> <summary>iOS</summary> <table> <thead> <tr> <td>Before</td> <td>After</td> </tr> </thead> <tbody> <tr> <td> <!--<img src="" /> --> </td> <td> <!--<img src="" /> --> </td> </tr> </tbody> </table> </details> <details> <summary>Android</summary> <table> <thead> <tr> <td>Before</td> <td>After</td> </tr> </thead> <tbody> <tr> <td> <!--<img src="" /> --> </td> <td> <!--<img src="" /> --> </td> </tr> </tbody> </table> </details> ## 🧪 Testing <!-- Explain how this change can be tested (or why it can't be tested) --> ## ☑️ Checklist - [ ] I have signed the [Stream CLA](https://docs.google.com/forms/d/e/1FAIpQLScFKsKkAJI7mhCr7K9rEIOpqIDThrWxuvxnwUq2XkHyG154vQ/viewform) (required) - [ ] PR targets the `develop` branch - [ ] Documentation is updated - [ ] New code is tested in main example apps, including all possible scenarios - [ ] SampleApp iOS and Android - [ ] Expo iOS and Android | 27 天前 | |
perf: introduce offline sync event limit (#3773) ## 🎯 Goal Implements [this spec](https://app.notion.com/p/stream-wiki/Sync-events-limit-3666a5d7f9f6801f97ecc1461fc62049). Since most other stuff is already supported by the SDK, here we introduce: - A way to limit the number of sync events we want to go through (regardless of what number the server returns) - We anyway still do `queryChannels` so this just prevents additional DB pressure if we get many, many events - The default stays at 250 ## 🛠 Implementation details <!-- Provide a description of the implementation --> ## 🎨 UI Changes <!-- Add relevant screenshots --> <details> <summary>iOS</summary> <table> <thead> <tr> <td>Before</td> <td>After</td> </tr> </thead> <tbody> <tr> <td> <!--<img src="" /> --> </td> <td> <!--<img src="" /> --> </td> </tr> </tbody> </table> </details> <details> <summary>Android</summary> <table> <thead> <tr> <td>Before</td> <td>After</td> </tr> </thead> <tbody> <tr> <td> <!--<img src="" /> --> </td> <td> <!--<img src="" /> --> </td> </tr> </tbody> </table> </details> ## 🧪 Testing <!-- Explain how this change can be tested (or why it can't be tested) --> ## ☑️ Checklist - [ ] I have signed the [Stream CLA](https://docs.google.com/forms/d/e/1FAIpQLScFKsKkAJI7mhCr7K9rEIOpqIDThrWxuvxnwUq2XkHyG154vQ/viewform) (required) - [ ] PR targets the `develop` branch - [ ] Documentation is updated - [ ] New code is tested in main example apps, including all possible scenarios - [ ] SampleApp iOS and Android - [ ] Expo iOS and Android | 18 天前 |
适用于 Stream Chat 的官方 React Native SDK
Stream Chat 官方 React Native 与 Expo 组件,为构建聊天应用提供后端服务。

快速链接
- Stream Chat API 产品概览
- 注册 获取 Stream Chat API 密钥
- React Native Chat 教程
- AI Agent 技能,适用于 Claude Code、Cursor 与 Codex
- Chat UI Kit
- 官方文档
- 版本发布说明
目录
📖 React Native 聊天教程
最佳起点是 React Native 聊天教程。它教你如何使用此 SDK,并展示如何进行常见的必要修改。
🤖 使用 AI 智能体构建
如果你使用 AI 编码智能体进行开发,我们的 智能体技能 将教它如何正确使用此 SDK。只需安装一次:
curl -fsSL https://getstream.io/cli.sh | bash
getstream init
然后使用 /stream-react-native 技能即可:
/stream-react-native create a new Expo chat app
/stream-react-native upgrade stream-chat-react-native to v9
它可以快速搭建一个全新的 Expo 或 React Native CLI 应用并预置好 SDK,也可以将 Stream 集成到你现有的应用中,还能审计已有的集成方案,或协助在不同 SDK 主版本之间进行迁移(包括从 Sendbird 迁移过来)。该工具兼容 Claude Code、Cursor、Codex,以及任何能读取通用 .agents 位置的智能代理。
如果你打算通过智能代理为本仓库贡献代码,请参阅 AGENTS.md 了解仓库结构、命令和约定。
面向创作者的免费计划
Stream 对大多数副业和个人项目完全免费。只要你的项目/公司团队成员少于 5 人,且月收入低于 1 万美元,即可享受免费计划。 完整的定价详情请访问我们的 聊天定价页面
🔮 示例应用
本仓库包含 2 个示例应用:一个基于 Expo 构建,另一个是使用 React Native CLI 开发的功能更完整的应用示例。
此外,我们的团队在 GetStream/react-native-samples 维护了一个专门存放完整示例应用和演示项目的仓库。欢迎查看以下示例应用:
💬 请注意
-
不同组件之间的导航逻辑需要由开发者自行实现。你可以参考本仓库中提供的示例代码。
-
小版本更新可能包含破坏性变更,因此在升级小版本之前,请务必查看发布说明。
关于各组件的详细文档,请访问 https://getstream.io/chat/docs/sdk/reactnative/
👏 参与贡献
我们欢迎一切能够改进此库或修复问题的代码变更,请务必遵循所有最佳实践,并对所有更改进行测试。请查阅我们的开发环境搭建文档以快速上手。我们很乐意将你的代码合并到官方仓库中。在提交之前,请务必先签署我们的贡献者许可协议(CLA)。更多详细信息,请参阅我们的许可证文件。
Git 工作流与发布流程
我们强制执行约定式提交,并通过工作区与 semantic-release 实现自动化发布流程。请阅读我们的 Git 工作流与发布流程指南 了解更多信息。
我们正在招贤纳士
我们近期完成了 3800 万美元的 B 轮融资,并且团队仍在持续壮大中。 我们的 API 服务于超过十亿的最终用户,你将有机会与来自全球顶尖的工程师团队一起,对产品产生深远的影响。
项目介绍
💬 React-Native 聊天 SDK ➜ Stream 聊天。包含使用 React-Native、React-Navigation 以及 Stream 构建自有聊天应用体验的教程。【此简介由AI生成】
