Skip to content

feat!: openapi related clean up - #1870

Merged
szuperaz merged 11 commits into
release-v10from
small-tasks-clean-up
Sep 17, 2026
Merged

szuperaz merged 11 commits into
release-v10from
small-tasks-clean-up

Conversation

@szuperaz

@szuperaz szuperaz commented Sep 16, 2026

Copy link
Copy Markdown
Contributor

Breaking changes

  • Removed public types (no longer needed): QueryFilter, PrimitiveFilter, ExtendedQueryFilter, ExtendedQueryFilters, ExtendedQueryLogicalOperators and Unpacked - generated filter types should be used instead
  • Removed client options: disableCache, wsConnection, enableInsights, warmUp
  • Behavioral: Previously, if we had no connection id and no pending connection request either, but still called queryChannels with watch: true, the client just sent the request with watch set to false. This now throws an error.
  • Behavioral: Previously, if during a reconnect we sent a watch: true request the request was sent with the old connection id (then most likely rejected if we had no internet connection). These requests now will wait for the reconnect to complete and only send the request once the new connection id is ready.

Detailed description below:

This PR contains various openapi-related clean up tasks. Some of them are technically breaking but shouldn't really impact SDK work or QA tests.

  1. _checkInitialized discrepancy

I always thought that _checkInitialized (checking if channel data is fetched already) method is called before all channel API calls. But that's not really the case; it is called in a few places, mostly from this repo's initial commit, and then never applied to newer api calls. Since it doesn't seem to be used, I've consolidated the checks to the necessary places:

  • _checkInitialized is called when we rely on data only available after a channel is initialized; it's only markRead and markUnread where we need to know if read events are enabled. (Although the TS compiler doesn't warn about this, because configController's data is typed as always available, I think in practice it has to be async data we only get once channel data is fetched)
  • In other places, a more relaxed check _ checkHasId is introduced, which checks if channel.id is defined. The use case is that for a distinct channel, we only get the ID after the channel data is fetched. Since channel.id is optional, the TS compiler warns us about these places. Technically, the same is true for channel.cid but since this field isn't typed as optional, the compiler can't warn us here.
  1. Remove dead client options
  • disableCache - was only relevant to server-side SDKs
  • wsConnection - replaced by WebSocketImpl
  • enableInsights - not documented, no chat QA tests either
  • warmUp - not documented, no chat QA tests either
  1. Move await this.wsPromise to ApiClient

We need to call await this.wsPromise before an API call that sets watch/presence/etc flags to true. With the generated API layer this would mean to manually wrap these API calls, and wait for the promise there. Since it's easy to miss a new method when regenerating from open api spec, the logic is moved to ApiClient where it automatically works for new endpoints too. The same method is used in stream-feeds-js already: https://github.com/GetStream/stream-feeds-js/blob/main/packages/feeds-client/src/common/ApiClient.ts#L67

Two behavior changes:

  • Previously, if we had no connection id and no pending connection request either, but still called queryChannels with watch: true, the client just sent the request with watch set to false. This now throws an error.
  • Previously, if during a reconnect we sent a watch: true request the request was sent with the old connection id (then most likely rejected if we had no internet connection). These requests now will wait for the reconnect to complete and only send the request once the new connection id is ready.
  1. Remove type tests + remove any reference to secret

This step was to remove any remaining reference to JS client aceepting API secret, these were mainly docs and unit tests. But it turns out the type tests were also working using the server-side capability of the JS client. Since type tests seem unnecessary with the generated API layer, I removed type tests altogether.

  1. Remove hand-written types related to query filters

These were already unused in client.

Linear tickets:

@szuperaz
szuperaz force-pushed the small-tasks-clean-up branch from 0f52f42 to af03caf Compare September 16, 2026 13:04
@szuperaz szuperaz changed the title fix: openapi related clean up feat!: openapi related clean up Sep 16, 2026
@szuperaz
szuperaz marked this pull request as ready for review September 16, 2026 19:40
Comment thread src/types.ts
/**
* Sets the instance of `StableWSConnection` on the chat client. Intended purely for testing and
* should not be used in production apps.
*/

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is in conflict with this PR: #1859 where wsConnection property is kept.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or is this just about not allowing to provide own StableWSConnection implementation?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will adapt my PR to yours

Comment thread src/client.ts Outdated
Comment thread src/connection_id_manager.ts
Comment thread src/connection.ts
Comment thread src/api-client.ts
Comment thread src/api-client.ts
Comment thread src/api-client.ts
Comment thread src/api-client.ts
MartinCupela added a commit that referenced this pull request Sep 17, 2026
…ealthy

Four changes that could not be separated cleanly, because they overlap in nearly every file
they touch.

**The connection id gets an owner.** `client.connectionIdManager` holds it, and `ApiClient`
holds any request that watches a channel or subscribes to presence until one exists. That
replaces the wait this branch had at two call sites, and it covers requests those never did:
stop-watching and long polling carry no watch flag and are recognised by their declared
`connection_id` parameter instead. A caller's abort signal reaches the wait. Ported from
#1870 so the two branches implement it the same way, with one difference — invalidation
hangs off the status funnel rather than one drop path, so the deliberate close and the two
error paths are covered as well.

**`isHealthy` comes back.** The socket's status is a different fact from the device's
network, and calling both `isOnline` forced every reader of the pair to alias one of them.
`isHealthy` was the name before this branch renamed it; it keeps that name and moves to a
getter on `client.wsConnection`, which is not replaced per connect. The store's timestamps
follow it to `lastHealthyAt` and `lastUnhealthyAt`, so each store now reads in one
vocabulary and no field name is shared between them.

**Recovery cannot re-enter.** A reload that moves the socket's status called straight back
into the pass that triggered it, recursing until the stack gave out. A reconnect arriving
mid-pass is now deferred to the end of that pass and run once, rather than dropped, which
would strand it, or stacked, which would reload every active channel twice.

**`connection.recovered` loses its discriminator.** One possible value forever, which every
consumer had to narrow on, and an omitted field silently skipped the thread list reload.

Also: the socket's parent is required rather than optional, since construction-time
injection is the one path that needed it and #1870 removes that capability; `channel.watch()`
takes an abort signal like `queryChannels`; and the repository documentation is updated
throughout.

BREAKING CHANGE: `client.wsConnection.state` carries `isHealthy`, `lastHealthyAt` and
`lastUnhealthyAt` rather than `isOnline`, `lastOnlineAt` and `lastOfflineAt`, and no longer
carries `connectionId` — read `client.connectionIdManager.connectionId`. `connection.recovered`
carries no payload. `new StableWSConnection()` requires its `wsConnection` parent.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@szuperaz
szuperaz merged commit b3fa906 into release-v10 Sep 17, 2026
4 checks passed
@szuperaz
szuperaz deleted the small-tasks-clean-up branch September 17, 2026 21:33
github-actions Bot pushed a commit that referenced this pull request Sep 18, 2026
## [10.0.0-rc.12](v10.0.0-rc.11...v10.0.0-rc.12) (2026-09-18)

### ⚠ BREAKING CHANGES

* `connection.changed` is removed. Connectivity is published as two state stores
and nothing else: `client.networkConnection.state` for the device and `client.wsConnection.state`
for this client's socket. The event was silent on `closeConnection()` and two error paths, and
held a drop for five seconds; the stores are written on every transition and publish immediately.
* `client.wsConnection` is now a `WSConnection` wrapper rather than the
`StableWSConnection` itself, and is never null. The live socket is `client.wsConnection.connection`,
replaced on every connect; read `isHealthy`, `isConnecting`, `connect()` and `disconnect()` from the
wrapper. `StableWSConnection` is constructed with `{ wsConnection }` instead of `{ client }`.
* `client.defaultWSTimeout` is removed, along with the `WebSocketImpl` and
`wsUrlParams` client options. They move to the socket's configuration as `connectTimeoutMs`,
`webSocketImpl` and `urlParams`, set with `client.config.set({ client: { wsConnection: { … } } })`.
Unlike the fields and options they replace, these survive a reconnect.
* `ThreadManagerState.lastConnectionDropAt` is removed. Read
`client.wsConnection.state.lastUnhealthyAt`, which is written on every status transition,
including the `disconnect()` path the old event was silent about.
* requests that watch a channel or subscribe to presence now wait for a WebSocket
connection id instead of silently returning unwatched data. The gate is in `ApiClient._doRequest`,
so it covers every endpoint carrying `watch` or `presence`, plus `stopWatchingChannel` and
`longPoll`. With no socket open and none being established the request rejects with "No connection
id is available"; an explicit `watch: false` is still honoured, and a caller's `AbortSignal`
abandons the wait. Test fixtures that fake a connected user without a live socket will now throw.
* a UI that renders a "connection lost" banner must hold the drop itself. The
socket's store publishes drops the moment they happen, where the old event delayed them by five
seconds. `client.wsConnection.config.offlineNotificationDisplayDelayMs` (5s) is the shared value to
wait for; nothing in this package acts on it.
* `connection.recovered` is no longer dispatched when the socket drops while a
recovery is running, because every reload in it can have failed. Work keyed off that event will
correctly stop running for recoveries that recovered nothing.
* openapi related clean up (#1870)

### Bug Fixes

* add missing app config fields to AppSettingsAPIResponse ([#1854](#1854)) ([18bc3cf](18bc3cf))
* do not reset channel unread count on thread read ([#1835](#1835)) ([79fbf54](79fbf54))
* hanging wsPromise after closeConnection ([#1868](#1868)) ([b4e7a89](b4e7a89)), closes [#1122](#1122) [#1863](#1863)
* isolate event listener errors from the dispatch loop ([#1850](#1850)) ([dc56e57](dc56e57))
* reconnect past connection timeout ([#1874](#1874)) ([2004a83](2004a83)), closes [#1760](#1760)
* send the read request regardless of read receipt privacy settings ([#1853](#1853)) ([59d8f31](59d8f31))

### Features

* **client:** support custom_set and custom_unset in batch channel update ([#1856](#1856)) ([d05c2f5](d05c2f5))
* establish network connection observer services ([#1859](#1859)) ([4c46949](4c46949))
* message pruning ([696f56f](696f56f))
* message pruning ([#1875](#1875)) ([d4d2c6c](d4d2c6c))
* **MessageComposer:** add composition middleware for pending attachment uploads ([#1845](#1845)) ([68e5d69](68e5d69))
* openapi related clean up ([#1870](#1870)) ([b3fa906](b3fa906))
@stream-ci-bot

Copy link
Copy Markdown

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

The release is available on:

Your semantic-release bot 📦🚀

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.

4 participants