@@ -6,7 +6,10 @@ import {
66 EventTypes ,
77 type StreamChat ,
88} from '../../src' ;
9- import { ChannelPaginatorsOrchestrator } from '../../src/ChannelPaginatorsOrchestrator' ;
9+ import {
10+ ChannelPaginatorsOrchestrator ,
11+ createPriorityOwnershipResolver ,
12+ } from '../../src/ChannelPaginatorsOrchestrator' ;
1013vi . mock ( '../../src/pagination/utility.queryChannel' , async ( ) => {
1114 return {
1215 getChannel : vi . fn ( async ( { client, id, type } ) => {
@@ -24,6 +27,146 @@ describe('ChannelPaginatorsOrchestrator', () => {
2427 vi . clearAllMocks ( ) ;
2528 } ) ;
2629
30+ describe ( 'ownershipResolver' , ( ) => {
31+ it ( 'keeps channel in all matching paginators by default' , async ( ) => {
32+ const ch = makeChannel ( 'messaging:100' ) ;
33+ client . activeChannels [ ch . cid ] = ch ;
34+
35+ const p1 = new ChannelPaginator ( { client, filters : { type : 'messaging' } } ) ;
36+ const p2 = new ChannelPaginator ( { client, filters : { type : 'messaging' } } ) ;
37+
38+ const orchestrator = new ChannelPaginatorsOrchestrator ( {
39+ client,
40+ paginators : [ p1 , p2 ] ,
41+ } ) ;
42+ orchestrator . registerSubscriptions ( ) ;
43+
44+ client . dispatchEvent ( { type : 'message.new' , cid : ch . cid } ) ;
45+ await vi . waitFor ( ( ) => {
46+ expect ( orchestrator . getPaginatorById ( p1 . id ) ) . toStrictEqual ( p1 ) ;
47+ expect ( orchestrator . getPaginatorById ( p2 . id ) ) . toStrictEqual ( p2 ) ;
48+ expect ( p1 . items ) . toHaveLength ( 1 ) ;
49+ expect ( p1 . items ! [ 0 ] ) . toStrictEqual ( ch ) ;
50+ expect ( p2 . items ) . toHaveLength ( 1 ) ;
51+ expect ( p2 . items ! [ 0 ] ) . toStrictEqual ( ch ) ;
52+ } ) ;
53+ } ) ;
54+
55+ it ( 'keeps channel only in highest-priority matching paginator when resolver provided' , async ( ) => {
56+ const pHigh = new ChannelPaginator ( { client, filters : { type : 'messaging' } } ) ;
57+ const pLow = new ChannelPaginator ( { client, filters : { type : 'messaging' } } ) ;
58+ const orchestrator = new ChannelPaginatorsOrchestrator ( {
59+ client,
60+ paginators : [ pLow , pHigh ] ,
61+ ownershipResolver : createPriorityOwnershipResolver ( [ pHigh . id , pLow . id ] ) ,
62+ } ) ;
63+
64+ const ch = makeChannel ( 'messaging:101' ) ;
65+ client . activeChannels [ ch . cid ] = ch ;
66+
67+ orchestrator . registerSubscriptions ( ) ;
68+ client . dispatchEvent ( { type : 'message.new' , cid : ch . cid } ) ;
69+
70+ await vi . waitFor ( ( ) => {
71+ expect ( pHigh . items ) . toHaveLength ( 1 ) ;
72+ expect ( pHigh . items ! [ 0 ] ) . toStrictEqual ( ch ) ;
73+ expect ( pLow . items ) . toBeUndefined ( ) ;
74+ } ) ;
75+ } ) ;
76+
77+ it ( 'keeps item in all priority ownership paginators when resolver returns multiple ids' , async ( ) => {
78+ const pHigh = new ChannelPaginator ( { client, filters : { type : 'messaging' } } ) ;
79+ const pLow = new ChannelPaginator ( { client, filters : { type : 'messaging' } } ) ;
80+ const orchestrator = new ChannelPaginatorsOrchestrator ( {
81+ client,
82+ paginators : [ pLow , pHigh ] ,
83+ ownershipResolver : ( ) => [ pHigh . id , pLow . id ] ,
84+ } ) ;
85+
86+ const ch = makeChannel ( 'messaging:101' ) ;
87+ client . activeChannels [ ch . cid ] = ch ;
88+
89+ orchestrator . registerSubscriptions ( ) ;
90+ client . dispatchEvent ( { type : 'message.new' , cid : ch . cid } ) ;
91+
92+ await vi . waitFor ( ( ) => {
93+ expect ( pHigh . items ) . toHaveLength ( 1 ) ;
94+ expect ( pHigh . items ! [ 0 ] ) . toStrictEqual ( ch ) ;
95+ expect ( pLow . items ) . toHaveLength ( 1 ) ;
96+ expect ( pLow . items ! [ 0 ] ) . toStrictEqual ( ch ) ;
97+ } ) ;
98+ } ) ;
99+
100+ it ( 'accepts ownershipResolver as array of ids and applies priority' , async ( ) => {
101+ const pLow = new ChannelPaginator ( { client, filters : { type : 'messaging' } } ) ;
102+ const pHigh = new ChannelPaginator ( { client, filters : { type : 'messaging' } } ) ;
103+ const orchestrator = new ChannelPaginatorsOrchestrator ( {
104+ client,
105+ paginators : [ pLow , pHigh ] ,
106+ ownershipResolver : [ pHigh . id , pLow . id ] ,
107+ } ) ;
108+
109+ const ch = makeChannel ( 'messaging:102' ) ;
110+ client . activeChannels [ ch . cid ] = ch ;
111+
112+ orchestrator . registerSubscriptions ( ) ;
113+ client . dispatchEvent ( { type : 'message.new' , cid : ch . cid } ) ;
114+
115+ await vi . waitFor ( ( ) => {
116+ expect ( pHigh . items ) . toHaveLength ( 1 ) ;
117+ expect ( pHigh . items ! [ 0 ] ) . toStrictEqual ( ch ) ;
118+ expect ( pLow . items ) . toBeUndefined ( ) ;
119+ } ) ;
120+ } ) ;
121+
122+ it ( 'keeps items only in owner paginators if some matching paginators are not listed in ownershipResolver array' , async ( ) => {
123+ const pLow = new ChannelPaginator ( { client, filters : { type : 'messaging' } } ) ;
124+ const pHigh = new ChannelPaginator ( { client, filters : { type : 'messaging' } } ) ;
125+ const orchestrator = new ChannelPaginatorsOrchestrator ( {
126+ client,
127+ paginators : [ pLow , pHigh ] ,
128+ ownershipResolver : [ pHigh . id ] ,
129+ } ) ;
130+
131+ const ch = makeChannel ( 'messaging:102' ) ;
132+ client . activeChannels [ ch . cid ] = ch ;
133+
134+ orchestrator . registerSubscriptions ( ) ;
135+ client . dispatchEvent ( { type : 'message.new' , cid : ch . cid } ) ;
136+
137+ await vi . waitFor ( ( ) => {
138+ expect ( pHigh . items ) . toHaveLength ( 1 ) ;
139+ expect ( pHigh . items ! [ 0 ] ) . toStrictEqual ( ch ) ;
140+ expect ( pLow . items ) . toBeUndefined ( ) ;
141+ } ) ;
142+ } ) ;
143+
144+ it ( 'keeps items only in matching paginators if owner paginators are not matching' , async ( ) => {
145+ const p1 = new ChannelPaginator ( { client, filters : { type : 'messaging' } } ) ;
146+ const p2 = new ChannelPaginator ( { client, filters : { type : 'messaging' } } ) ;
147+ const p3 = new ChannelPaginator ( { client, filters : { type : 'messagingX' } } ) ;
148+ const orchestrator = new ChannelPaginatorsOrchestrator ( {
149+ client,
150+ paginators : [ p1 , p2 , p3 ] ,
151+ ownershipResolver : [ p3 . id ] ,
152+ } ) ;
153+
154+ const ch = makeChannel ( 'messaging:102' ) ;
155+ client . activeChannels [ ch . cid ] = ch ;
156+
157+ orchestrator . registerSubscriptions ( ) ;
158+ client . dispatchEvent ( { type : 'message.new' , cid : ch . cid } ) ;
159+
160+ await vi . waitFor ( ( ) => {
161+ expect ( p1 . items ) . toHaveLength ( 1 ) ;
162+ expect ( p1 . items ! [ 0 ] ) . toStrictEqual ( ch ) ;
163+ expect ( p2 . items ) . toHaveLength ( 1 ) ;
164+ expect ( p2 . items ! [ 0 ] ) . toStrictEqual ( ch ) ;
165+ expect ( p3 . items ) . toBeUndefined ( ) ;
166+ } ) ;
167+ } ) ;
168+ } ) ;
169+
27170 describe ( 'constructor' , ( ) => {
28171 it ( 'initiates with default options' , ( ) => {
29172 // @ts -expect-error accessing protected property
@@ -381,7 +524,10 @@ describe('ChannelPaginatorsOrchestrator', () => {
381524 // Helper to create a minimal channel with needed state
382525 function makeChannel ( cid : string ) {
383526 const [ type , id ] = cid . split ( ':' ) ;
384- return client . channel ( type , id ) ;
527+ const channel = client . channel ( type , id ) ;
528+ channel . data ! . type = type ;
529+ channel . data ! . id = id ;
530+ return channel ;
385531 }
386532
387533 describe . each ( [ 'channel.deleted' , 'channel.hidden' ] as EventTypes [ ] ) (
0 commit comments