Skip to content

feat: migrate ChannelPaginatorsOrchestrator to ChannelManager - #1813

Open
MartinCupela wants to merge 9 commits into
release-v10from
feat/channel-orchestrator-to-channel-manager
Open

feat: migrate ChannelPaginatorsOrchestrator to ChannelManager#1813
MartinCupela wants to merge 9 commits into
release-v10from
feat/channel-orchestrator-to-channel-manager

Conversation

@MartinCupela

@MartinCupela MartinCupela commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Summary

ChannelPaginatorsOrchestrator becomes ChannelManager, and the legacy src/channel_manager.ts is
deleted. One manager now holds N channel lists — each a ChannelPaginator — keeps them in sync through an
EventHandlerPipeline per event type, and arbitrates ownership when a channel matches several lists.

The rename is the easy half. The bulk of this PR is feature parity: the legacy manager still had
behavior the paginator stack did not, so those gaps were closed first and the deletion comes last.

What was ported

Ported Why it mattered
Predefined-filter response metadataquery() requests withResponse: true and keeps predefined_filter verbatim; it drives local matching (buildMatchFilters) and ordering (effectiveSort) For a list built from a server-stored filter, the client knew none of it. A message.new for an archived channel was ingested into a list the server filters to { archived: false }
Hidden channels — excluded from lists unless the filter constrains hidden; channel.hidden re-evaluates filters Hidden channels stayed visible until a re-query. Legacy removed them outright, which would evict them from a { hidden: true } list — this keeps them
Offline-DB parity — full request as the cache key (read and write), first-page query deferred until the sync manager reports completion, WS-driven reorders persisted Predefined-filter lists shared a wrong cache row; the sync branch was unreachable whenever the cache had data; live reordering never reached the cache
Query retriesretryCount is a paginator option and ChannelPaginator defaults to DEFAULT_QUERY_CHANNELS_RETRY_COUNT Channel queries had silently stopped retrying
Channel identity from events — one getCidFromEvent helper for the cached lookup and the fetch updateLists threw on events whose only identity is event.channel.cid; removeItem ignored them

Deliberately not ported, each with a reason in decisions.md:
state.initialized, pagination.isLoadingNext, abortInFlightQuery, the 10 named handler overrides,
allowNotLoadedChannelPromotionForEvent, members-based channel construction, and the promoteChannel
pinned-ordering rules.

Bugs found while porting

Each of these was pre-existing and is covered by a test that fails without the fix:

  • sort setter dropped the comparator's resolvers — after any paginator.sort = …, last_message_at
    resolved to channel.data.last_message_at (undefined) instead of the message paginator's value, and
    equal sort values ordered non-deterministically. Comparator construction now goes through one
    buildSortComparator().
  • retryCount was off by one3 meant 3 attempts / 2 waits; it now means 3 retries / 4 attempts,
    matching what the legacy manager's own tests asserted.
  • removeItem handler read only event.cid — a channel.deleted whose cid arrives nested in
    event.channel was ignored, so the channel stayed in every list.
  • describe.each(['channel.deleted', 'channel.hidden']) never ran the hidden case — all three cases
    dispatched a hardcoded channel.deleted, which is why the missing handler went unnoticed.
  • Two flaky client.test.js tests — the fixture built ten "channels" sharing one cid with
    same-millisecond timestamps, so ordering hinged on random uuids (~5% failure rate).

Breaking changes

ChannelManager keeps its name but is a different class — code importing it still compiles, which is
the risky part. Full tables (state, methods, options, types, helpers) are in the new ## ChannelManager
section of v9-to-v10-migration-guide-methods.md, including a
worked replacement for promoteChannel and a v10-RC → final rename table. In short:

  • state.channels / pagination / initialized / errorstate.paginators, with list state on
    paginator.state (items, hasMoreTail, isLoading, lastQueryError).
  • queryChannels() / loadNext() / setChannels() / setQueryChannelsRequest() / setOptions() /
    setEventHandlerOverrides() → paginator methods and the pipeline API.
  • lockChannelOrderpaginatorOptions.lockItemOrder; abortInFlightQuery and
    allowNotLoadedChannelPromotionForEvent removed (the latter replaced by inserting the exported
    ignoreEventsForUnknownChannels at index: 0).
  • buildFilters() is gone stack-wide → buildQueryFilters() (request + offline cache key) and
    buildMatchFilters() (local matching). ChannelQueryShape is now the queryChannels request itself.
  • 16 legacy types and 9 utility exports removed (promoteChannel & friends).
  • Behavioral: hidden channels excluded by default, retryCount semantics, offline cache re-keyed,
    sortComparator assignment no longer survives a sort change (use sortComparatorFactory),
    channel.updated / channel.truncated re-emit instead of no-op.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant