Skip to content

fix: v10 in depth review hotfixes - #1920

Merged
isekovanic merged 19 commits into
release-v10from
fix/v10-hotfixes
Oct 20, 2026
Merged

isekovanic merged 19 commits into
release-v10from
fix/v10-hotfixes

Conversation

@isekovanic

Copy link
Copy Markdown
Contributor

CLA

  • I have signed the Stream CLA (required).
  • Code changes are tested

Description of the changes, What, Why and How?

Fixes the "must fix" of the issues in section 1 of ai-docs/v10-followups.md. Each item is its own commit, linked below. Two parts of that list are not in this PR: the channel.query() message-set parameter is being fixed separately and the breaking removals listed at the end of section 1 get their own PR (probably tomorrow).

Behaviour fixes

  • Typing indicators went stale after a composer reset (send, clear(), edit init, snapshot restore), because the text composer kept its own copy of the typing map. The copy is gone and channel.state is the only owner. Thread typing indicators that read the thread composer's copy, which was always empty, work once they read channel.state. (f97ddd8)
  • One mark-read throttle was shared by every channel and thread, so channel → thread → channel inside one second dropped the thread's mark-read. Each channel and thread instance now has its own throttle. (312e2e5)
  • When retries ran out, the rejection was a RetryError with no code or status, and offline operations queued it as transient. The last attempt's error is rethrown instead, so callers get the StreamAPIError. A 429 is no longer retried, as in v9; it used to hold the caller for about 100 s. (e295664)
  • An expired static token was reloaded and retried 10 times. It fails on the first attempt again, as in v9. (eef8868)
  • The channel skipped edits and undeletes of show_in_channel replies, so the channel list kept the old text unless a Thread for the parent was held. The channel applies them now, and leaves them to the thread when client.threads routes the edit to a held one, so each collection still publishes once. (dd1b8c7)
  • user.messages.deleted only processed the active window, so after a jump to an older message the banned user's newest messages stayed visible. Every loaded interval is processed now. (45290f4)
  • connectionRecovery.recover() did nothing when connectionRecovery.enabled was false. The flag now only switches off the automatic recovery on reconnect, and recover() always runs. With recovery disabled, connection.recovered is still not dispatched on reconnect, since it means a recovery finished; the JSDoc says so now. (311c28a)
  • The reminder list published items: undefined on every load more, because the page cursor was part of the query shape. The cursor is applied per request instead. (73a8775)
  • lastQueryError was published on every failed attempt, before the retries ran out, so React showed error toasts and RN flashed its error screen for a query that recovered. It is published once, after the last attempt. (9cc208f)
  • messageSearchSort was appended after a fixed created_at: -1, so [{ field: 'created_at', direction: 1 }] sent a contradictory duplicate key. It is merged the v9 way: created_at stays the primary key and takes the caller's direction. (e32c8d5)

Type fixes

  • on('all', cb) typed the event as never, while undeclared names (typos, connection.changed) compiled and never fired. 'all' now gets the full Event union, and on() / off() accept only an EventType, so custom events are declared through CustomEventTypes. off(type, handler) takes EventHandler<type>, so a typed handler can be removed again. (c103da0)
  • client.on('*') type-checked but never fired. The spec's { type: '*' } & CustomEvent placeholder is dropped from the generated event unions. (79477d2)
  • The created_at_* filters of QueryMembersPayload, QueryBannedUsersPayload and QueryFutureChannelBansPayload were typed TimestampNS, which the API rejects with Time.UnmarshalJSON: input is not a JSON string (checked against a live app). They are Date | string now, matching the spec's date-time. (202e690, which also rewrites the time.ts note from 8bc711c)

The generated-model changes are made by scripts/apply-custom-data-types.mts and a new scripts/drop-placeholder-request-params.mts, both run by generate-client.sh, so a regen keeps them.

Signature changes (breaking)

These are in be73434 unless noted:

  • client.pinMessage({ id }, { pin_expires?, pinned_at? }) and client.unpinMessage({ id }) take the message (or { id }) and absolute dates. The relative-seconds number and the bare id string are gone.
  • client.getThreadAndHydrate({ message_id }, options?), like getThread.
  • channel.addMembers, inviteMembers and removeMembers take { members, message?, ...options }; addFilterTags and removeFilterTags take { tags, message?, ...options }.
  • channel.deleteImage({ url }) and channel.deleteFile({ url }), like the client methods.
  • client.polls.queryPolls(request?) takes the same request as client.queryPolls.
  • client.moderation.flagMessage({ message_id, reason?, ...options }) and flagUser({ user_id, reason?, ...options }).
  • PollComposer.updateFields({ data, injectedFieldErrors? }). (4f8f95c)
  • The 26 body-less endpoints drop the unused _request?: Record<string, never> parameter, so requestOptions follows the path params directly (channel.pin({ signal }), client.getApp(requestOptions?)). (51fa769)

Every change is recorded in ai-docs/v10-breaking-changes.md with a migration line. The docs snippet tests use the new signatures; the matching getstream.io pages still need updating, and yarn test-docs-sync reports those regions until they are.

Testing

Each fix comes with unit or type tests that fail on the previous code. yarn test, yarn types, yarn lint and yarn types-docs pass. The two unhandled rejections the suite reports (from optimisticRouting.test.ts and poll.test.js) predate this branch.

Changelog

  • fix: typing indicators no longer go stale after the composer resets; channel.state owns the typing map (f97ddd8)
  • fix: throttle mark-read per channel and thread (312e2e5)
  • fix: on('all') gets the full Event type; on() / off() accept only declared event names (c103da0)
  • fix: remove the '*' placeholder from the event types (79477d2)
  • fix: rethrow the API error when retries run out; stop retrying 429 (e295664)
  • fix: fail expired static tokens immediately (eef8868)
  • fix: apply edits of show_in_channel replies to the channel list (dd1b8c7)
  • fix: user.messages.deleted processes every loaded message (45290f4)
  • fix: connectionRecovery.recover() works when automatic recovery is disabled (311c28a)
  • fix: reminder list no longer blanks on load more (73a8775)
  • fix: publish lastQueryError only after the retries run out (9cc208f)
  • fix: merge messageSearchSort under created_at like v9 (e32c8d5)
  • fix: type member and ban query date filters as Date | string (202e690)
  • refactor!: request objects for pinMessage, getThreadAndHydrate, channel member and filter-tag helpers, channel.deleteImage / deleteFile, polls.queryPolls, flagMessage / flagUser (be73434)
  • refactor!: PollComposer.updateFields takes one object (4f8f95c)
  • refactor!: drop the unused request parameter from body-less endpoints (51fa769)

@oliverlaz
oliverlaz added this pull request to stack #1925 October 20, 2026 08:12
Comment thread src/messageComposer/textComposer.ts Resolved
@MartinCupela
MartinCupela self-requested a review October 20, 2026 09:18
@oliverlaz oliverlaz mentioned this pull request Oct 20, 2026
2 tasks
@isekovanic
isekovanic merged commit 98a298d into release-v10 Oct 20, 2026
4 checks passed
@isekovanic
isekovanic deleted the fix/v10-hotfixes branch October 20, 2026 11:46
isekovanic pushed a commit that referenced this pull request Oct 20, 2026
## CLA

- [ ] I have signed the [Stream
CLA](https://docs.google.com/forms/d/e/1FAIpQLScFKsKkAJI7mhCr7K9rEIOpqIDThrWxuvxnwUq2XkHyG154vQ/viewform)
(required).
- [ ] Code changes are tested

## Description of the changes, What, Why and How?

**Stacked on #1920:** this PR targets `fix/v10-hotfixes` and should
merge after #1920. Against that base it is comment-only; against
`release-v10` its diff also shows #1920's changes until #1920 lands.

**What:** Rewrites the comments and JSDoc in `src` (excluding the
generated `src/gen`) and updates `JSDOC.md`. 134 `.ts` files change, and
comment lines drop from about 11.4k to 6.3k.

**Why:** The v10 refactorings left long, partly outdated comment prose:
how things used to behave, review ids, method lists that restate
signatures, and boilerplate repeated per class. Comments now describe
the code as it is, only where it is not obvious. Comments that no longer
matched the code were corrected, several of them predating this PR.

**How:** Comment-only. Compiled output is identical for every file apart
from comments (each file was transpiled with comments removed, before
and after, and compared). Exported public API keeps a summary plus
`@param`/`@returns`; internals are documented in prose. Prose uses `ID`
casing and `Defaults to X.`. `JSDOC.md` gains a public API vs internals
section and the content rules this PR follows. `TODO`/`FIXME` lines,
lint directives and commented-out code are untouched. `yarn lint`, `yarn
types` and `yarn test` pass.

**Reviewing:** The diff is large and mostly deletions. The useful
feedback is any comment that is still wrong, and any "why" that should
have stayed.

## Changelog

- Tidy comments and JSDoc in `src`. No behaviour change.

---------

Co-authored-by: martincupela <martin.cupela@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
github-actions Bot pushed a commit that referenced this pull request Oct 20, 2026
## [10.0.0-rc.23](v10.0.0-rc.22...v10.0.0-rc.23) (2026-10-20)

### Bug Fixes

* add docs snippets; fix open api issues ([#1913](#1913)) ([53505e7](53505e7))
* address code issues found while reviewing v10 source comments ([#1922](#1922)) ([2fc319e](2fc319e))
* v10 in depth review hotfixes ([#1920](#1920)) ([98a298d](98a298d))
@stream-ci-bot

Copy link
Copy Markdown

🎉 This PR is included in version 10.0.0-rc.23 🎉

The release is available on:

Your semantic-release bot 📦🚀

isekovanic added a commit to GetStream/stream-chat-react-native that referenced this pull request Oct 20, 2026
## 🎯 Goal

Adapts the SDK to the signature changes in
[GetStream/stream-chat-js#<PR>](GetStream/stream-chat-js#1920),
the stream-chat v10 prerelease fixes. The other fixes in that PR need no
change here as RN already reads typing from `channel.state` and the rest
are LLC-internal.

## 🛠 Implementation details

- `useCreateMessageActionHandlers` calls `client.pinMessage(message)`;
it passed `null` before, which was the default anyway. It also calls
`client.moderation.flagMessage({ message_id: message.id })`. (0d7953e)
- `useChannelActions` calls `channel.addMembers({ members })` and
`channel.removeMembers({ members })`. (0d7953e)
- The 12 `pollComposer.updateFields(...)` calls in `components/Poll`
pass `{ data: ... }`. (dcbb7f6)

This needs the stream-chat release that contains the stream-chat-js PR.
Until `stream-chat` is bumped, `yarn test:typecheck` fails on these call
sites, because the installed rc still has the old signatures.

## 🎨 UI Changes

/

## 🧪 Testing

/

## ☑️ 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
isekovanic pushed a commit that referenced this pull request Oct 20, 2026
## Breaking changes
- The `_request` placeholders are back

Reverts/fixes some open-api related hotfixes from here:
#1920

1. the `_request` placeholders are put back

We need them, reasoning here:
#1896

2. The `created_at*` type issues are solved by regenerating from the
latest API spec, instead of manipulating the generated code

3. Disallowing `client('*')`

This is done by excluding the `*` type from the hand-written `Event`
type, rather than manipulating the generated `WSEvent` type
oliverlaz added a commit that referenced this pull request Oct 29, 2026
Ticket: https://linear.app/stream/issue/REACT-1466

## CLA

- [x] I have signed the [Stream
CLA](https://docs.google.com/forms/d/e/1FAIpQLScFKsKkAJI7mhCr7K9rEIOpqIDThrWxuvxnwUq2XkHyG154vQ/viewform)
(required).
- [x] Code changes are tested

## Description of the changes, What, Why and How?

In v10 `Event` is a discriminated union, but `channel.state.typing` was
still typed `Record<string, Event>`. Any custom typing indicator that
reads `event.user` or `event.parent_id` stopped compiling and needed a
hand-written `(e): e is EventPayload<'typing.start'> => e.type ===
'typing.start'` guard. Found while migrating the stream-chat-react demo
apps to v15 rc (stream-chat 10.0.0-rc.26).

Only `typing.start` events are ever stored in that slice. The one writer
is the `typing.start` case in `Channel._handleChannelEvent` (guarded on
`event.user?.id`), `typing.stop` only removes an entry, and `clean()`
only reads `received_at`. So the type is narrowed to match what is
stored:

- `TypingUsersState.typing` (and so `ChannelStateData['typing']`), the
`channel.state.typing` setter and `setTypingEvent` now use
`Record<string, EventPayload<'typing.start'>>` /
`EventPayload<'typing.start'>`. No new exported alias.
- New compile-time test `test/types/typing-state.ts` (runs in `yarn
types` and `types:dist`):
`Object.values(channel.state.typing)[0].user?.id` and `.parent_id`
compile with no guard, the slice type is pinned, and passing a
`typing.stop` to `setTypingEvent` is rejected. Against the old types it
fails with 6 errors.

`ai-docs/v10-breaking-changes.md`:

- §7 (`ChannelState` is a `StateStore<ChannelStateData>`): the
parenthetical said stream-chat-react's `TypingIndicator` "reads the
composer copy", which contradicted the same sentence (`channel.state` is
the only owner) and the React v15 guide. It now says the indicator reads
`channel.state`, and documents the narrowed type.
- §18: dropped the "`TextComposerState.typing` added as required" entry
and the `typing` / `setTyping` / `setTypingEvent` / `removeTypingEvent`
members from the `TextComposer` row of the added-members table. That
composer copy was removed in #1920, so both described an API that no
longer exists and contradicted §7.

Compatibility: this is narrower than before, so code that assigned
non-`typing.start` events into `channel.state.typing` or
`setTypingEvent` no longer compiles. Nothing in the SDK does that, and
readers only gain.

### Test results

- `yarn types`: pass (includes `types:scripts` and `types:tests`)
- `yarn lint`: clean, zero warnings
- `yarn test`: 135 files, 4820 tests passed

## Changelog

- `channel.state.typing` and `ChannelState.setTypingEvent` are typed as
`typing.start` events, so `event.user` reads without a type guard.
github-actions Bot pushed a commit that referenced this pull request Oct 30, 2026
## [10.0.0-rc.27](v10.0.0-rc.26...v10.0.0-rc.27) (2026-10-30)

### Bug Fixes

* consolidate master and v10 ([#1957](#1957)) ([802a956](802a956))
* handle tokenProvider rejection during reconnect token refresh ([#1963](#1963)) ([e22d218](e22d218))
* narrow channel.state.typing to typing.start events ([#1960](#1960)) ([acb2345](acb2345)), closes [#1920](#1920)
* odd edge cases for channel list recovery ([#1966](#1966)) ([dbc2468](dbc2468))
* pass full request options to hydration query ([#1959](#1959)) ([489774b](489774b))

### Features

* regenerate from latest api spec; docs sync ([#1969](#1969)) ([ae1e86a](ae1e86a))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants