stream-chat 9.50.3 → 10.0.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.browser.js +19798 -14472
- package/dist/cjs/index.browser.js.map +4 -4
- package/dist/cjs/index.node.js +19817 -14482
- package/dist/cjs/index.node.js.map +4 -4
- package/dist/esm/index.mjs +19795 -14469
- package/dist/esm/index.mjs.map +4 -4
- package/dist/types/ChannelManager.d.ts +221 -0
- package/dist/types/EventHandlerPipeline.d.ts +104 -0
- package/dist/types/api-client.d.ts +26 -0
- package/dist/types/campaign.d.ts +0 -44
- package/dist/types/channel.d.ts +454 -479
- package/dist/types/channel_batch_updater.d.ts +0 -93
- package/dist/types/channel_state.d.ts +53 -201
- package/dist/types/client.d.ts +451 -1920
- package/dist/types/client_state.d.ts +4 -4
- package/dist/types/configuration/InstanceConfigurationService.d.ts +26 -0
- package/dist/types/configuration/index.d.ts +1 -0
- package/dist/types/configuration/types.d.ts +53 -0
- package/dist/types/connection.d.ts +49 -41
- package/dist/types/connection_fallback.d.ts +6 -4
- package/dist/types/constants.d.ts +0 -4
- package/dist/types/custom_types.d.ts +2 -0
- package/dist/types/entityStore/EntityStore.d.ts +111 -0
- package/dist/types/entityStore/StoreBackedItemIndex.d.ts +60 -0
- package/dist/types/entityStore/applyReactionLocally.d.ts +26 -0
- package/dist/types/entityStore/index.d.ts +2 -0
- package/dist/types/errors.d.ts +10 -2
- package/dist/types/gen/chat/ChannelApi.d.ts +45 -0
- package/dist/types/gen/chat/ChatApi.d.ts +334 -0
- package/dist/types/gen/model-decoders/decoders.d.ts +3 -0
- package/dist/types/gen/model-decoders/event-decoder-mapping.d.ts +6 -0
- package/dist/types/gen/models/index.d.ts +8836 -0
- package/dist/types/gen/moderation/ModerationApi.d.ts +50 -0
- package/dist/types/gen-imports.d.ts +3 -0
- package/dist/types/index.d.ts +8 -7
- package/dist/types/insights.d.ts +9 -8
- package/dist/types/logger.d.ts +9 -0
- package/dist/types/messageComposer/LocationComposer.d.ts +7 -4
- package/dist/types/messageComposer/attachmentIdentity.d.ts +2 -2
- package/dist/types/messageComposer/attachmentManager.d.ts +8 -4
- package/dist/types/messageComposer/configuration/types.d.ts +11 -11
- package/dist/types/messageComposer/linkPreviewsManager.d.ts +25 -13
- package/dist/types/messageComposer/messageComposer.d.ts +10 -10
- package/dist/types/messageComposer/middleware/messageComposer/types.d.ts +3 -3
- package/dist/types/messageComposer/middleware/pollComposer/types.d.ts +4 -7
- package/dist/types/messageComposer/middleware/textComposer/commandUtils.d.ts +3 -3
- package/dist/types/messageComposer/middleware/textComposer/commands.d.ts +7 -7
- package/dist/types/messageComposer/middleware/textComposer/mentions.d.ts +218 -4
- package/dist/types/messageComposer/middleware/textComposer/types.d.ts +9 -4
- package/dist/types/messageComposer/pollComposer.d.ts +5 -4
- package/dist/types/messageComposer/textComposer.d.ts +8 -3
- package/dist/types/messageComposer/types.d.ts +6 -28
- package/dist/types/messageDelivery/MessageDeliveryReporter.d.ts +40 -25
- package/dist/types/messageDelivery/MessageReceiptsTracker.d.ts +53 -12
- package/dist/types/messageOperations/MessageOperationStatePolicy.d.ts +19 -0
- package/dist/types/messageOperations/MessageOperations.d.ts +17 -0
- package/dist/types/messageOperations/index.d.ts +3 -0
- package/dist/types/messageOperations/types.d.ts +49 -0
- package/dist/types/moderation.d.ts +21 -203
- package/dist/types/notifications/types.d.ts +8 -7
- package/dist/types/offline-support/offline_support_api.d.ts +111 -87
- package/dist/types/offline-support/offline_sync_manager.d.ts +0 -7
- package/dist/types/offline-support/types.d.ts +19 -23
- package/dist/types/offline-support/util.d.ts +4 -2
- package/dist/types/pagination/FilterBuilder.d.ts +1 -1
- package/dist/types/pagination/ItemIndex.d.ts +25 -0
- package/dist/types/pagination/cursorDerivation/createdAtAroundPaginationFlags.d.ts +9 -0
- package/dist/types/pagination/cursorDerivation/idAroundPaginationFlags.d.ts +6 -0
- package/dist/types/pagination/cursorDerivation/index.d.ts +1 -0
- package/dist/types/pagination/cursorDerivation/linearPaginationFlags.d.ts +6 -0
- package/dist/types/pagination/filterCompiler.d.ts +7 -0
- package/dist/types/pagination/index.d.ts +1 -3
- package/dist/types/pagination/paginators/BasePaginator.d.ts +848 -0
- package/dist/types/pagination/paginators/ChannelPaginator.d.ts +212 -0
- package/dist/types/pagination/paginators/MessageIntervalPaginator.d.ts +282 -0
- package/dist/types/pagination/paginators/MessagePaginator.d.ts +208 -0
- package/dist/types/pagination/paginators/PinnedMessagePaginator.d.ts +39 -0
- package/dist/types/pagination/paginators/ReminderPaginator.d.ts +19 -0
- package/dist/types/pagination/paginators/UserGroupPaginator.d.ts +24 -0
- package/dist/types/pagination/paginators/index.d.ts +7 -0
- package/dist/types/pagination/paginators/stateThrottling.d.ts +2 -0
- package/dist/types/pagination/sortCompiler.d.ts +49 -0
- package/dist/types/pagination/types.normalization.d.ts +11 -0
- package/dist/types/pagination/utility.normalization.d.ts +18 -0
- package/dist/types/pagination/utility.queryChannel.d.ts +26 -0
- package/dist/types/pagination/utility.search.d.ts +13 -0
- package/dist/types/permissions.d.ts +1 -1
- package/dist/types/poll.d.ts +29 -32
- package/dist/types/poll_manager.d.ts +2 -2
- package/dist/types/reminders/Reminder.d.ts +2 -5
- package/dist/types/reminders/ReminderManager.d.ts +2 -9
- package/dist/types/search/MessageSearchSource.d.ts +4 -4
- package/dist/types/search/UserSearchSource.d.ts +1 -1
- package/dist/types/search/types.d.ts +3 -3
- package/dist/types/segment.d.ts +0 -34
- package/dist/types/signing.d.ts +105 -65
- package/dist/types/store.d.ts +1 -0
- package/dist/types/thread.d.ts +70 -34
- package/dist/types/thread_manager.d.ts +3 -3
- package/dist/types/token_manager.d.ts +15 -10
- package/dist/types/types.d.ts +197 -3404
- package/dist/types/utils/FixedSizeQueueCache.d.ts +12 -6
- package/dist/types/utils/WithSubscriptions.d.ts +2 -1
- package/dist/types/utils/concurrency.d.ts +4 -4
- package/dist/types/utils/mergeWith/mergeWith.d.ts +3 -3
- package/dist/types/utils/mergeWith/mergeWithCore.d.ts +8 -3
- package/dist/types/utils/retryable.d.ts +34 -0
- package/dist/types/utils/throttling/throttle.d.ts +36 -0
- package/dist/types/utils.d.ts +100 -194
- package/package.json +7 -3
- package/src/ChannelManager.ts +724 -0
- package/src/CooldownTimer.ts +2 -2
- package/src/EventHandlerPipeline.ts +228 -0
- package/src/LiveLocationManager.ts +12 -11
- package/src/api-client.ts +275 -0
- package/src/campaign.ts +1 -77
- package/src/channel.ts +1344 -1282
- package/src/channel_batch_updater.ts +1 -211
- package/src/channel_state.ts +144 -1013
- package/src/client.ts +936 -3995
- package/src/client_state.ts +4 -4
- package/src/configuration/InstanceConfigurationService.ts +73 -0
- package/src/configuration/index.ts +1 -0
- package/src/configuration/types.ts +81 -0
- package/src/connection.ts +145 -94
- package/src/connection_fallback.ts +29 -27
- package/src/constants.ts +1 -5
- package/src/custom_types.ts +4 -1
- package/src/entityStore/EntityStore.ts +208 -0
- package/src/entityStore/StoreBackedItemIndex.ts +115 -0
- package/src/entityStore/applyReactionLocally.ts +113 -0
- package/src/entityStore/index.ts +2 -0
- package/src/errors.ts +14 -2
- package/src/gen/chat/ChannelApi.ts +275 -0
- package/src/gen/chat/ChatApi.ts +2554 -0
- package/src/gen/model-decoders/decoders.ts +2680 -0
- package/src/gen/model-decoders/event-decoder-mapping.ts +198 -0
- package/src/gen/models/index.ts +12673 -0
- package/src/gen/moderation/ModerationApi.ts +607 -0
- package/src/gen-imports.ts +3 -0
- package/src/index.ts +11 -12
- package/src/insights.ts +6 -5
- package/src/logger.ts +28 -0
- package/src/messageComposer/LocationComposer.ts +9 -5
- package/src/messageComposer/MessageComposerEffectHandlers.ts +1 -0
- package/src/messageComposer/attachmentIdentity.ts +16 -9
- package/src/messageComposer/attachmentManager.ts +13 -8
- package/src/messageComposer/configuration/types.ts +11 -11
- package/src/messageComposer/linkPreviewsManager.ts +9 -10
- package/src/messageComposer/messageComposer.ts +57 -53
- package/src/messageComposer/middleware/messageComposer/attachments.ts +1 -2
- package/src/messageComposer/middleware/messageComposer/cleanData.ts +1 -1
- package/src/messageComposer/middleware/messageComposer/compositionValidation.ts +2 -2
- package/src/messageComposer/middleware/messageComposer/messageComposerState.ts +2 -2
- package/src/messageComposer/middleware/messageComposer/sharedLocation.ts +4 -3
- package/src/messageComposer/middleware/messageComposer/textComposer.ts +2 -2
- package/src/messageComposer/middleware/messageComposer/types.ts +3 -4
- package/src/messageComposer/middleware/messageComposer/userDataInjection.ts +9 -5
- package/src/messageComposer/middleware/pollComposer/state.ts +0 -2
- package/src/messageComposer/middleware/pollComposer/types.ts +4 -7
- package/src/messageComposer/middleware/textComposer/TextComposerMiddlewareExecutor.ts +10 -1
- package/src/messageComposer/middleware/textComposer/commandEffects.ts +4 -4
- package/src/messageComposer/middleware/textComposer/commandUtils.ts +3 -6
- package/src/messageComposer/middleware/textComposer/commands.ts +3 -3
- package/src/messageComposer/middleware/textComposer/mentionUtils.ts +1 -1
- package/src/messageComposer/middleware/textComposer/mentions.ts +31 -15
- package/src/messageComposer/middleware/textComposer/types.ts +9 -4
- package/src/messageComposer/pollComposer.ts +6 -8
- package/src/messageComposer/textComposer.ts +27 -2
- package/src/messageComposer/types.ts +6 -28
- package/src/messageDelivery/MessageDeliveryReporter.ts +101 -45
- package/src/messageDelivery/MessageReceiptsTracker.ts +294 -21
- package/src/messageOperations/MessageOperationStatePolicy.ts +77 -0
- package/src/messageOperations/MessageOperations.ts +212 -0
- package/src/messageOperations/index.ts +10 -0
- package/src/messageOperations/types.ts +64 -0
- package/src/moderation.ts +38 -431
- package/src/notifications/types.ts +8 -7
- package/src/offline-support/offline_support_api.ts +200 -133
- package/src/offline-support/offline_sync_manager.ts +23 -44
- package/src/offline-support/types.ts +23 -26
- package/src/offline-support/util.ts +5 -4
- package/src/pagination/FilterBuilder.ts +4 -1
- package/src/pagination/ItemIndex.ts +25 -0
- package/src/pagination/cursorDerivation/createdAtAroundPaginationFlags.ts +73 -0
- package/src/pagination/cursorDerivation/idAroundPaginationFlags.ts +53 -0
- package/src/pagination/cursorDerivation/index.ts +1 -0
- package/src/pagination/cursorDerivation/linearPaginationFlags.ts +86 -0
- package/src/pagination/filterCompiler.ts +196 -0
- package/src/pagination/index.ts +1 -3
- package/src/pagination/paginators/BasePaginator.ts +2859 -0
- package/src/pagination/paginators/ChannelPaginator.ts +729 -0
- package/src/pagination/paginators/MessageIntervalPaginator.ts +1116 -0
- package/src/pagination/paginators/MessagePaginator.ts +508 -0
- package/src/pagination/paginators/PinnedMessagePaginator.ts +108 -0
- package/src/pagination/paginators/ReminderPaginator.ts +107 -0
- package/src/pagination/paginators/UserGroupPaginator.ts +127 -0
- package/src/pagination/paginators/index.ts +7 -0
- package/src/pagination/paginators/stateThrottling.ts +31 -0
- package/src/pagination/sortCompiler.ts +193 -0
- package/src/pagination/types.normalization.ts +14 -0
- package/src/pagination/utility.normalization.ts +106 -0
- package/src/pagination/utility.queryChannel.ts +84 -0
- package/src/pagination/utility.search.ts +80 -0
- package/src/permissions.ts +7 -8
- package/src/poll.ts +101 -110
- package/src/poll_manager.ts +14 -8
- package/src/reminders/Reminder.ts +2 -5
- package/src/reminders/ReminderManager.ts +19 -21
- package/src/search/BaseSearchSource.ts +0 -3
- package/src/search/ChannelMemberSearchSource.ts +7 -1
- package/src/search/ChannelSearchSource.ts +10 -3
- package/src/search/MessageSearchSource.ts +29 -30
- package/src/search/UserSearchSource.ts +12 -8
- package/src/search/types.ts +3 -4
- package/src/segment.ts +1 -95
- package/src/signing.ts +107 -67
- package/src/store.ts +2 -1
- package/src/thread.ts +562 -238
- package/src/thread_manager.ts +37 -16
- package/src/token_manager.ts +21 -10
- package/src/types.ts +364 -4533
- package/src/uploadManager.ts +8 -0
- package/src/utils/FixedSizeQueueCache.ts +12 -6
- package/src/utils/WithSubscriptions.ts +2 -1
- package/src/utils/concurrency.ts +4 -4
- package/src/utils/mergeWith/mergeWith.ts +3 -3
- package/src/utils/mergeWith/mergeWithCore.ts +140 -164
- package/src/utils/mergeWith/mergeWithDiff.ts +3 -3
- package/src/utils/retryable.ts +117 -0
- package/src/utils/throttling/throttle.ts +130 -0
- package/src/utils.ts +208 -754
- package/dist/types/channel_manager.d.ts +0 -122
- package/dist/types/events.d.ts +0 -72
- package/dist/types/pagination/BasePaginator.d.ts +0 -69
- package/dist/types/pagination/ReminderPaginator.d.ts +0 -16
- package/dist/types/pagination/UserGroupPaginator.d.ts +0 -21
- package/src/channel_manager.ts +0 -830
- package/src/events.ts +0 -75
- package/src/pagination/BasePaginator.ts +0 -184
- package/src/pagination/ReminderPaginator.ts +0 -56
- package/src/pagination/UserGroupPaginator.ts +0 -93
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import type { ItemCoordinates, PaginationQueryParams, PaginationQueryReturnValue, PaginatorOptions, PaginatorState, PostQueryReconcileParams, SetPaginatorItemsParams } from './BasePaginator';
|
|
2
|
+
import { BasePaginator } from './BasePaginator';
|
|
3
|
+
import type { FilterBuilderOptions } from '../FilterBuilder';
|
|
4
|
+
import { FilterBuilder } from '../FilterBuilder';
|
|
5
|
+
import type { StreamChat } from '../../client';
|
|
6
|
+
import type { Channel } from '../../channel';
|
|
7
|
+
import type { ChannelFilters, ChannelOptions, ChannelSort, ChannelStateOptions, ParsedPredefinedFilterResponse, QueryChannelsRequest } from '../../types';
|
|
8
|
+
/**
|
|
9
|
+
* The `queryChannels` request this paginator will send, plus the client-only `stateOptions`.
|
|
10
|
+
*
|
|
11
|
+
* Deliberately the request's own shape (`filter_conditions`, `sort`, `limit`, `predefined_filter`, …)
|
|
12
|
+
* rather than a `{ filters, sort, options }` wrapper: the same object goes on the wire, keys the
|
|
13
|
+
* offline-db cache and is compared for query-shape changes, so any field mapping in between would be a
|
|
14
|
+
* place for those three to drift apart. `MessageQueryShape` is likewise the request params themselves.
|
|
15
|
+
*/
|
|
16
|
+
export type ChannelQueryShape = QueryChannelsRequest & {
|
|
17
|
+
/** Not part of the request — controls how the response is applied to client state. */
|
|
18
|
+
stateOptions?: ChannelStateOptions;
|
|
19
|
+
};
|
|
20
|
+
export type ChannelPaginatorState = PaginatorState<Channel>;
|
|
21
|
+
export type ChannelPaginatorRequestOptions = Partial<Omit<ChannelOptions, 'offset' | 'limit'>>;
|
|
22
|
+
export type ChannelSortComparatorFactoryParams = {
|
|
23
|
+
/** Sort the comparator is being built for — the effective sort, so a backend-resolved sort template. */
|
|
24
|
+
sort: ChannelSort;
|
|
25
|
+
/**
|
|
26
|
+
* The comparator `ChannelPaginator` would use for this sort. Delegate to it for the fields you do not
|
|
27
|
+
* want to handle yourself instead of reimplementing channel field resolution and the cid tiebreaker.
|
|
28
|
+
*/
|
|
29
|
+
defaultComparator: (a: Channel, b: Channel) => number;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Produces the comparator that orders this paginator's channels. Consulted on **every** comparator
|
|
33
|
+
* rebuild (construction, `sort` change, backend-resolved predefined sort), so unlike assigning
|
|
34
|
+
* `sortComparator` directly, a factory is not overwritten by later sort changes.
|
|
35
|
+
*/
|
|
36
|
+
export type ChannelSortComparatorFactory = (params: ChannelSortComparatorFactoryParams) => (a: Channel, b: Channel) => number;
|
|
37
|
+
export type ChannelPaginatorOptions = {
|
|
38
|
+
client: StreamChat;
|
|
39
|
+
channelStateOptions?: ChannelStateOptions;
|
|
40
|
+
filterBuilderOptions?: FilterBuilderOptions<ChannelFilters>;
|
|
41
|
+
filters?: ChannelFilters;
|
|
42
|
+
id?: string;
|
|
43
|
+
paginatorOptions?: PaginatorOptions<Channel, ChannelQueryShape>;
|
|
44
|
+
requestOptions?: ChannelPaginatorRequestOptions;
|
|
45
|
+
sort?: ChannelSort;
|
|
46
|
+
sortComparatorFactory?: ChannelSortComparatorFactory;
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* A paginated channel list. Filters are described along three independent axes — the names follow them:
|
|
50
|
+
*
|
|
51
|
+
* - origin: `staticFilters` are supplied at construction and fixed; `filterBuilder` generates the
|
|
52
|
+
* dynamic ones from its reactive context on every build. Every build merges dynamic over static.
|
|
53
|
+
* - authority: `staticFilters` are what this client asked for; `predefinedFilter` is what the backend
|
|
54
|
+
* reports it actually applied for a `predefined_filter` query. `effectiveFilters` is the winner of the
|
|
55
|
+
* two (and `effectiveSort` likewise for ordering).
|
|
56
|
+
* - purpose: `buildQueryFilters()` produces the filters sent to the server (and the offline-db query
|
|
57
|
+
* key), built from the local filters only; `buildMatchFilters()` produces the filters items are
|
|
58
|
+
* matched against locally, built from `effectiveFilters`. They are not interchangeable: sending the
|
|
59
|
+
* resolved filter back changes the query shape mid-pagination, and matching against the local filter
|
|
60
|
+
* admits channels the queried list excludes.
|
|
61
|
+
*
|
|
62
|
+
* Ordering follows the same authority rule: `sortComparator` is derived from `effectiveSort` and is
|
|
63
|
+
* rebuilt whenever that changes, so it must not be assigned to. Customize it through
|
|
64
|
+
* `sortComparatorFactory` (constructor option or setter, consulted on every rebuild) or by overriding
|
|
65
|
+
* `buildSortComparator` in a subclass.
|
|
66
|
+
*/
|
|
67
|
+
export declare class ChannelPaginator extends BasePaginator<Channel, ChannelQueryShape> {
|
|
68
|
+
private readonly _id;
|
|
69
|
+
private client;
|
|
70
|
+
protected _staticFilters: ChannelFilters | undefined;
|
|
71
|
+
protected _sort: ChannelSort | undefined;
|
|
72
|
+
protected _options: ChannelPaginatorRequestOptions | undefined;
|
|
73
|
+
protected _channelStateOptions: ChannelStateOptions | undefined;
|
|
74
|
+
protected _nextQueryShape: ChannelQueryShape | undefined;
|
|
75
|
+
/** Backend-reported metadata of the last `predefined_filter` query (see `predefinedFilter`). */
|
|
76
|
+
protected _predefinedFilter: ParsedPredefinedFilterResponse | undefined;
|
|
77
|
+
/**
|
|
78
|
+
* Predefined-filter metadata from the response of the query currently in flight. Held until
|
|
79
|
+
* `postQueryReconcile` decides whether it should be committed (first page only).
|
|
80
|
+
*/
|
|
81
|
+
private _pendingPredefinedFilter;
|
|
82
|
+
protected _sortComparatorFactory: ChannelSortComparatorFactory | undefined;
|
|
83
|
+
sortComparator: (a: Channel, b: Channel) => number;
|
|
84
|
+
filterBuilder: FilterBuilder<ChannelFilters>;
|
|
85
|
+
constructor({ channelStateOptions, client, id, filterBuilderOptions, filters, paginatorOptions, requestOptions, sort, sortComparatorFactory, }: ChannelPaginatorOptions);
|
|
86
|
+
/**
|
|
87
|
+
* Builds the comparator for the given sort — the single construction point, so every rebuild (the
|
|
88
|
+
* `sort` setter, a backend-resolved predefined sort) keeps the channel-specific path resolver and the
|
|
89
|
+
* cid tiebreaker; omitting either makes ordering fall back to raw `channel.data` lookups and become
|
|
90
|
+
* non-deterministic for equal sort values.
|
|
91
|
+
*
|
|
92
|
+
* `sortComparator` is derived state and is therefore reassigned on every rebuild — assigning to it
|
|
93
|
+
* directly does not survive a sort change or a predefined-filter response. To customize ordering,
|
|
94
|
+
* supply `sortComparatorFactory` (it is consulted on every rebuild and may delegate to
|
|
95
|
+
* `defaultComparator`), or override this method in a subclass.
|
|
96
|
+
*/
|
|
97
|
+
protected buildSortComparator(sort: ChannelSort): (a: Channel, b: Channel) => number;
|
|
98
|
+
get id(): string;
|
|
99
|
+
get isOfflineSupportEnabled(): boolean;
|
|
100
|
+
get staticFilters(): ChannelFilters | undefined;
|
|
101
|
+
get sort(): ChannelSort;
|
|
102
|
+
/**
|
|
103
|
+
* What the backend reported it actually filtered and sorted by for the last first-page query —
|
|
104
|
+
* `QueryChannelsResponse.predefined_filter` (`name`, `filter`, and `sort` when the stored filter
|
|
105
|
+
* carries its own sort template). Set only for `predefined_filter` queries: the raw `filter_conditions`
|
|
106
|
+
* of a normal query are not echoed back.
|
|
107
|
+
*/
|
|
108
|
+
get predefinedFilter(): ParsedPredefinedFilterResponse | undefined;
|
|
109
|
+
/**
|
|
110
|
+
* Filters this paginator matches items against client-side. A predefined filter resolved by the backend
|
|
111
|
+
* wins over the locally configured one: for such a query the local `filters` are not what the server
|
|
112
|
+
* applied, so matching against them would admit items the queried list excludes.
|
|
113
|
+
*/
|
|
114
|
+
get effectiveFilters(): ChannelFilters | undefined;
|
|
115
|
+
/**
|
|
116
|
+
* Sort this paginator orders items by. Mirrors `effectiveFilters`: a sort template carried by a
|
|
117
|
+
* backend-resolved predefined filter takes precedence over the requested sort, matching backend
|
|
118
|
+
* precedence rules.
|
|
119
|
+
*/
|
|
120
|
+
get effectiveSort(): ChannelSort;
|
|
121
|
+
get options(): ChannelOptions | undefined;
|
|
122
|
+
get channelStateOptions(): ChannelStateOptions | undefined;
|
|
123
|
+
set staticFilters(filters: ChannelFilters | undefined);
|
|
124
|
+
set sort(sort: ChannelSort | undefined);
|
|
125
|
+
set options(options: ChannelPaginatorRequestOptions | undefined);
|
|
126
|
+
set channelStateOptions(options: ChannelStateOptions | undefined);
|
|
127
|
+
get sortComparatorFactory(): ChannelSortComparatorFactory | undefined;
|
|
128
|
+
/**
|
|
129
|
+
* Take over channel ordering at any point in the paginator's life. The comparator is rebuilt
|
|
130
|
+
* immediately and the factory is consulted again on every later rebuild, so — unlike assigning
|
|
131
|
+
* `sortComparator` — a sort change or a backend-resolved predefined sort will not discard it. Set to
|
|
132
|
+
* `undefined` to go back to the built-in ordering.
|
|
133
|
+
*/
|
|
134
|
+
set sortComparatorFactory(factory: ChannelSortComparatorFactory | undefined);
|
|
135
|
+
getItemId(item: Channel): string;
|
|
136
|
+
/**
|
|
137
|
+
* Filters sent to the server with the next query (and used as the offline-db query key). Deliberately
|
|
138
|
+
* built from the locally configured filters only — feeding the backend-resolved filter back in would
|
|
139
|
+
* change the query shape after the first response and make the following page look like a new first
|
|
140
|
+
* page to `hasPaginationQueryShapeChanged`.
|
|
141
|
+
*/
|
|
142
|
+
buildQueryFilters: () => ChannelFilters;
|
|
143
|
+
/**
|
|
144
|
+
* Filters items are matched against locally — the `BasePaginator.buildMatchFilters` hook consumed by
|
|
145
|
+
* `matchesFilter`. Built from `effectiveFilters`, so a `predefined_filter` list matches what the
|
|
146
|
+
* backend applied rather than the local filters, which are not what produced the list.
|
|
147
|
+
*/
|
|
148
|
+
buildMatchFilters: () => ChannelFilters;
|
|
149
|
+
matchesFilter(channel: Channel): boolean;
|
|
150
|
+
/**
|
|
151
|
+
* Commits the `predefined_filter` metadata of the response, or clears it when the response carried
|
|
152
|
+
* none (a plain `filter_conditions` query), so a switch away from a predefined filter cannot leave
|
|
153
|
+
* stale matching/ordering semantics behind.
|
|
154
|
+
*/
|
|
155
|
+
protected applyPredefinedFilterResponse(predefinedFilter: ParsedPredefinedFilterResponse | undefined): void;
|
|
156
|
+
/**
|
|
157
|
+
* The response metadata describes the query as a whole, so it is (re)committed only when a first page
|
|
158
|
+
* lands — matching the legacy `ChannelManager`, which kept it untouched while paginating. A failed
|
|
159
|
+
* query (`results === null`) must not drop the metadata of the already loaded list either.
|
|
160
|
+
*
|
|
161
|
+
* Committing before `super` matters: the base implementation filters and ingests the page using
|
|
162
|
+
* `matchesFilter` and the comparators this metadata feeds.
|
|
163
|
+
*/
|
|
164
|
+
postQueryReconcile(params: PostQueryReconcileParams<Channel, ChannelQueryShape>): import("./BasePaginator").ExecuteQueryReturnValue<Channel>;
|
|
165
|
+
protected getNextQueryShape(): ChannelQueryShape;
|
|
166
|
+
/** The query that produced the currently loaded list, i.e. the cache key its cids belong under. */
|
|
167
|
+
protected get loadedQueryRequest(): QueryChannelsRequest;
|
|
168
|
+
/**
|
|
169
|
+
* Writes a cid order into the offline cache under the query that produced it.
|
|
170
|
+
*
|
|
171
|
+
* `filters` and `sort` are passed separately even though `options` already contains them: the concrete
|
|
172
|
+
* (RN) DB implementation derives the cache row key from those two top-level arguments in
|
|
173
|
+
* `convertFilterSortToQuery`, while `options` carries the full request — the only place
|
|
174
|
+
* `predefined_filter` / `filter_values` / `sort_values` appear, without which two predefined-filter
|
|
175
|
+
* lists cannot be told apart. The duplication goes away once `convertFilterSortToQuery` derives the
|
|
176
|
+
* key from `options` (a change in that implementation plus a schema-version bump to flush stale rows).
|
|
177
|
+
*/
|
|
178
|
+
protected cacheCidsForQuery({ cids, request, }: {
|
|
179
|
+
cids: string[];
|
|
180
|
+
request: QueryChannelsRequest;
|
|
181
|
+
}): void;
|
|
182
|
+
/**
|
|
183
|
+
* Persists the current cid order under the query that produced it. Called after every mutation of the
|
|
184
|
+
* loaded list — including live WS-driven inserts/removals, which reorder the list without any query
|
|
185
|
+
* running; skipping those would leave the cached order stale until the next full re-query.
|
|
186
|
+
*/
|
|
187
|
+
protected persistLoadedCids(): void;
|
|
188
|
+
preloadFirstPageFromOfflineDb: ({ queryShape, }: PaginationQueryParams<ChannelQueryShape>) => Promise<Channel[] | undefined>;
|
|
189
|
+
populateOfflineDbAfterQuery: ({ items, queryShape, }: {
|
|
190
|
+
items?: Channel[];
|
|
191
|
+
queryShape?: ChannelQueryShape;
|
|
192
|
+
}) => undefined;
|
|
193
|
+
/**
|
|
194
|
+
* Postpones a first-page query while the offline sync is still in progress: the cached page is
|
|
195
|
+
* surfaced right away and the network query is handed to the sync manager, which re-runs it once
|
|
196
|
+
* reconciliation finished — querying (and persisting cids) against unsynced local state would race
|
|
197
|
+
* with the replay of pending local mutations. Mirrors `ChannelManager.queryChannels`, which deferred
|
|
198
|
+
* on every unsynced call and read the cache only when it had nothing loaded yet.
|
|
199
|
+
*
|
|
200
|
+
* Only first-page queries defer; paginating an already loaded list is unaffected (as was the legacy
|
|
201
|
+
* `loadNext`).
|
|
202
|
+
*/
|
|
203
|
+
executeQuery(params?: PaginationQueryParams<ChannelQueryShape>): Promise<void | import("./BasePaginator").ExecuteQueryReturnValue<Channel>>;
|
|
204
|
+
query: () => Promise<PaginationQueryReturnValue<Channel>>;
|
|
205
|
+
filterQueryResults: (items: Channel[]) => Channel[];
|
|
206
|
+
setItems(params: SetPaginatorItemsParams<Channel>): void;
|
|
207
|
+
ingestItem(channel: Channel): boolean;
|
|
208
|
+
removeItem(params: {
|
|
209
|
+
id?: string;
|
|
210
|
+
item?: Channel;
|
|
211
|
+
}): ItemCoordinates;
|
|
212
|
+
}
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import type { PaginationDirection, PaginationQueryParams, PaginatorState } from './BasePaginator';
|
|
2
|
+
import { BasePaginator, type PaginationQueryReturnValue, type PaginatorOptions } from './BasePaginator';
|
|
3
|
+
import type { LocalMessage, MessagePaginationOptions, MessageResponse, PinnedMessagePaginationOptions, ReactionResponse, SortParamRequest, UserResponse } from '../../types';
|
|
4
|
+
import type { Channel } from '../../channel';
|
|
5
|
+
import { StateStore } from '../../store';
|
|
6
|
+
import type { ItemIndexApi } from '../ItemIndex';
|
|
7
|
+
import type { EntityStoreChangeBatch } from '../../entityStore/EntityStore';
|
|
8
|
+
export type MessageFocusReason = 'jump-to-message' | 'jump-to-first-unread' | 'jump-to-latest';
|
|
9
|
+
export type MessageFocusSignal = {
|
|
10
|
+
messageId: string;
|
|
11
|
+
reason: MessageFocusReason;
|
|
12
|
+
token: number;
|
|
13
|
+
createdAt: number;
|
|
14
|
+
ttlMs: number;
|
|
15
|
+
};
|
|
16
|
+
export type MessageFocusSignalState = {
|
|
17
|
+
signal: MessageFocusSignal | null;
|
|
18
|
+
};
|
|
19
|
+
export type JumpToMessageOptions = {
|
|
20
|
+
pageSize?: number;
|
|
21
|
+
/**
|
|
22
|
+
* Optional reason attached to emitted focus signal.
|
|
23
|
+
* Defaults to `jump-to-message`.
|
|
24
|
+
*/
|
|
25
|
+
focusReason?: MessageFocusReason;
|
|
26
|
+
/**
|
|
27
|
+
* TTL for the emitted focus signal in milliseconds.
|
|
28
|
+
* Defaults to `3000`.
|
|
29
|
+
*/
|
|
30
|
+
focusSignalTtlMs?: number;
|
|
31
|
+
/**
|
|
32
|
+
* If true, suppresses focus signal emission after a successful jump.
|
|
33
|
+
*/
|
|
34
|
+
suppressFocusSignal?: boolean;
|
|
35
|
+
};
|
|
36
|
+
export type MessagePaginatorSort = SortParamRequest[];
|
|
37
|
+
export type MessagePaginatorFilter = {
|
|
38
|
+
cid: string;
|
|
39
|
+
parent_id?: string;
|
|
40
|
+
};
|
|
41
|
+
export type MessagePaginatorState = PaginatorState<LocalMessage>;
|
|
42
|
+
export type MessageQueryShape = MessagePaginationOptions | PinnedMessagePaginationOptions;
|
|
43
|
+
export declare const getMessageCreatedAtTimestamp: (message: LocalMessage) => number | null;
|
|
44
|
+
export type MessagePaginatorOptions = {
|
|
45
|
+
channel: Channel;
|
|
46
|
+
id?: string;
|
|
47
|
+
itemIndex?: ItemIndexApi<LocalMessage>;
|
|
48
|
+
parentMessageId?: string;
|
|
49
|
+
/**
|
|
50
|
+
* Sort passed to backend message/replies query.
|
|
51
|
+
* Does not affect in-memory item ordering.
|
|
52
|
+
*/
|
|
53
|
+
requestSort?: MessagePaginatorSort;
|
|
54
|
+
/**
|
|
55
|
+
* @deprecated Use `requestSort` instead.
|
|
56
|
+
*/
|
|
57
|
+
sort?: MessagePaginatorSort;
|
|
58
|
+
/**
|
|
59
|
+
* In-memory ordering for items exposed by paginator state.
|
|
60
|
+
*/
|
|
61
|
+
itemOrder?: MessagePaginatorSort;
|
|
62
|
+
paginatorOptions?: PaginatorOptions<LocalMessage, MessageQueryShape>;
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* MessageIntervalPaginator allows configuring backend request sort, while keeping internal item ordering stable.
|
|
66
|
+
* Filtering of ingested items is still limited to local predicates (`filterQueryResults`).
|
|
67
|
+
*/
|
|
68
|
+
export declare class MessageIntervalPaginator extends BasePaginator<LocalMessage, MessageQueryShape> {
|
|
69
|
+
state: StateStore<MessagePaginatorState>;
|
|
70
|
+
private readonly _id;
|
|
71
|
+
protected channel: Channel;
|
|
72
|
+
protected parentMessageId?: string;
|
|
73
|
+
readonly messageFocusSignal: StateStore<MessageFocusSignalState>;
|
|
74
|
+
private clearMessageFocusSignalTimeoutId;
|
|
75
|
+
private messageFocusSignalToken;
|
|
76
|
+
protected _requestSort: MessagePaginatorSort;
|
|
77
|
+
protected _itemOrder: MessagePaginatorSort;
|
|
78
|
+
protected _nextQueryShape: MessageQueryShape | undefined;
|
|
79
|
+
sortComparator: (a: LocalMessage, b: LocalMessage) => number;
|
|
80
|
+
/**
|
|
81
|
+
* Single source of truth for whether a message should be included in paginator intervals/state.
|
|
82
|
+
* Keep this consistent with `filterQueryResults` AND cursor flag derivation.
|
|
83
|
+
*/
|
|
84
|
+
shouldIncludeMessageInInterval(message: LocalMessage): boolean;
|
|
85
|
+
/**
|
|
86
|
+
* Entity-store adapter (this paginator is an `EntityStoreSubscriber`): the `EntityStore` calls this
|
|
87
|
+
* on each holder with the subset of its watched ids that changed. Unwraps the batch and delegates to
|
|
88
|
+
* the base's store-agnostic {@link BasePaginator.reconcileChangedIds}. Lives here, not on the generic
|
|
89
|
+
* `BasePaginator`, so the base stays free of `EntityStore` types — only message paginators are
|
|
90
|
+
* store-backed.
|
|
91
|
+
*/
|
|
92
|
+
onEntitiesChanged({ changedIds }: EntityStoreChangeBatch): void;
|
|
93
|
+
/**
|
|
94
|
+
* Entity-store subscriber flush (the optional `EntityStoreSubscriber.flushState`): the `EntityStore`
|
|
95
|
+
* calls this after an optimistic (local-user) write so the change renders without throttle delay.
|
|
96
|
+
* Delegates to the base's generic {@link BasePaginator.flushPendingPublishes}.
|
|
97
|
+
*/
|
|
98
|
+
flushState(): void;
|
|
99
|
+
protected get intervalItemIdsAreHeadFirst(): boolean;
|
|
100
|
+
protected get intervalSortDirection(): 'asc' | 'desc';
|
|
101
|
+
constructor({ channel, id, itemIndex, parentMessageId, requestSort, sort, itemOrder, paginatorOptions, }: MessagePaginatorOptions);
|
|
102
|
+
get id(): string;
|
|
103
|
+
get sort(): MessagePaginatorSort;
|
|
104
|
+
get requestSort(): MessagePaginatorSort;
|
|
105
|
+
get itemOrder(): MessagePaginatorSort;
|
|
106
|
+
/**
|
|
107
|
+
* Even though we do not send filters object to the server, we need to have filters for client-side item ingestion logic.
|
|
108
|
+
*/
|
|
109
|
+
buildMatchFilters: () => MessagePaginatorFilter;
|
|
110
|
+
protected getNextQueryShape({ direction, }: Omit<PaginationQueryParams<MessageQueryShape>, 'isFirstPageQuery'>): MessageQueryShape;
|
|
111
|
+
getCursorFromQueryResults: ({ direction, items, }: {
|
|
112
|
+
direction?: PaginationDirection;
|
|
113
|
+
items: LocalMessage[];
|
|
114
|
+
}) => {
|
|
115
|
+
tailward: string | undefined;
|
|
116
|
+
headward: string | undefined;
|
|
117
|
+
};
|
|
118
|
+
query: ({ direction, }: PaginationQueryParams<MessageQueryShape>) => Promise<PaginationQueryReturnValue<LocalMessage>>;
|
|
119
|
+
/**
|
|
120
|
+
* Seed the paginator with the page a channel-open query just fetched (`Channel.query` for
|
|
121
|
+
* `watch`/`create`, and `client.hydrateActiveChannels`).
|
|
122
|
+
*
|
|
123
|
+
* These paths hydrate the channel read state in the SAME synchronous tick they add messages
|
|
124
|
+
* (`Channel._initializeState`), and the read patch drives `MessageReceiptsTracker`, which resolves
|
|
125
|
+
* read/delivered cursors against this paginator (`findItemByTimestamp`) whenever the server omits
|
|
126
|
+
* the `last_read_message_id` / `last_delivered_message_id`. `postQueryReconcile` is fully
|
|
127
|
+
* synchronous (filtering is a local predicate), so seeding here guarantees the paginator is
|
|
128
|
+
* populated before the reconcile runs. First-page reconciliation also takes the unread snapshot.
|
|
129
|
+
*
|
|
130
|
+
* The fetched page is NOT always the latest window: a channel can be opened AROUND a message
|
|
131
|
+
* (`messages: { id_around }` / `{ created_at_around }`), so the original pagination options are
|
|
132
|
+
* threaded through as the query shape. For an around/jump open this lets `postQueryReconcile`
|
|
133
|
+
* apply jump semantics (no forced head/tail; cursor flags derived from the around position)
|
|
134
|
+
* instead of wrongly flagging the window as the head (newest) page.
|
|
135
|
+
*/
|
|
136
|
+
seedFirstPageSync(messages: LocalMessage[], requestedPageSize: number, messagePaginationOptions?: MessagePaginationOptions): void;
|
|
137
|
+
isJumpQueryShape(queryShape: MessageQueryShape): boolean;
|
|
138
|
+
jumpToMessage: (messageId: string, { focusReason, focusSignalTtlMs, pageSize, suppressFocusSignal, }?: JumpToMessageOptions) => Promise<boolean>;
|
|
139
|
+
jumpToTheLatestMessage: (options?: JumpToMessageOptions) => Promise<boolean>;
|
|
140
|
+
/**
|
|
141
|
+
* Fold an already fetched newest (head) page into the currently loaded items without issuing a
|
|
142
|
+
* query. The caller supplies a page it obtained on its own and this reconciles it against what is
|
|
143
|
+
* loaded, instead of rerunning the first page query, so the loaded set is updated in place rather
|
|
144
|
+
* than blanked and reloaded. Two cases, decided by whether the incoming page overlaps the loaded
|
|
145
|
+
* head:
|
|
146
|
+
*
|
|
147
|
+
* 1. OVERLAP - the incoming page shares at least one id with the loaded head (fewer than a full
|
|
148
|
+
* page is new). Merge in place: existing items are reconciled by id (edits, soft deletes), new
|
|
149
|
+
* items are appended and every already loaded item (including older pages already paged in) is
|
|
150
|
+
* kept. `hasMoreTail`/`cursor.tailward` are left as-is so the page can be any size, so deriving
|
|
151
|
+
* "has older items" from its length would wrongly clear it while older items remain.
|
|
152
|
+
*
|
|
153
|
+
* 2. DISJOINT - the incoming page shares no id with the loaded head (at least a full page is new).
|
|
154
|
+
* Merging would weld the two across the gap (the interval merge treats two head intervals as
|
|
155
|
+
* overlapping when one reaches further headward), hiding the items in between with no way to
|
|
156
|
+
* reach them. Instead the loaded set is discarded and rebuilt from the incoming page as a fresh
|
|
157
|
+
* contiguous head (`hasMoreTail: true`, cursor reanchored to the page's oldest item) so the
|
|
158
|
+
* gap and older history load again when paginating older.
|
|
159
|
+
*
|
|
160
|
+
* Both paths emit exactly once and never blank the loaded set. Noop unless the page is non empty
|
|
161
|
+
* and the newest slice is both loaded AND the interval currently in view (the head interval is
|
|
162
|
+
* anchored at the head and active); when the caller has jumped to a separate older window the
|
|
163
|
+
* merge is skipped so their position is preserved, and the incoming page is picked up on a later
|
|
164
|
+
* load.
|
|
165
|
+
*/
|
|
166
|
+
mergeNewestPage: (page: LocalMessage[]) => void;
|
|
167
|
+
protected resolveUnreadBoundaryIdsByTimestamp: ({ lastReadAt, messages, }: {
|
|
168
|
+
lastReadAt: Date;
|
|
169
|
+
messages: LocalMessage[];
|
|
170
|
+
}) => {
|
|
171
|
+
firstUnreadMessageId: string | null;
|
|
172
|
+
lastReadMessageId: string | null;
|
|
173
|
+
};
|
|
174
|
+
emitMessageFocusSignal: ({ messageId, reason, ttlMs, }: {
|
|
175
|
+
messageId: string;
|
|
176
|
+
reason: MessageFocusReason;
|
|
177
|
+
ttlMs?: number;
|
|
178
|
+
}) => MessageFocusSignal;
|
|
179
|
+
/**
|
|
180
|
+
* Starts the auto-dismissal countdown for the currently active focus signal. Call this once the
|
|
181
|
+
* focused message has been viewed (rendered and visible), so the highlight's lifetime is measured
|
|
182
|
+
* from when the user could actually see it rather than from when the jump resolved. No-op if the
|
|
183
|
+
* signal has already been cleared or superseded (guarded by `token`).
|
|
184
|
+
*/
|
|
185
|
+
scheduleMessageFocusSignalClear: ({ token, ttlMs, }?: {
|
|
186
|
+
token?: number;
|
|
187
|
+
ttlMs?: number;
|
|
188
|
+
}) => void;
|
|
189
|
+
clearMessageFocusSignal: ({ token }?: {
|
|
190
|
+
token?: number;
|
|
191
|
+
}) => void;
|
|
192
|
+
clearStateAndCache(): void;
|
|
193
|
+
/**
|
|
194
|
+
* Partial truncation for `channel.truncated` carrying a `truncated_at`: drop every loaded
|
|
195
|
+
* message strictly older than the cutoff (keeping newer ones) across all loaded windows,
|
|
196
|
+
* mirroring the legacy per-message-set pruning. For a full truncation (no `truncated_at`) use
|
|
197
|
+
* {@link MessageIntervalPaginator.clearStateAndCache} instead.
|
|
198
|
+
*
|
|
199
|
+
* Batched and edge-classified: because messages are chronological, each interval is classified by
|
|
200
|
+
* its `tail` (oldest) and `head` (newest) edges, so only the single interval that *straddles* the
|
|
201
|
+
* cutoff is scanned member-by-member — the rest are kept or dropped wholesale. The straddling
|
|
202
|
+
* interval becomes the new global tail (nothing older than the cutoff exists anymore), so its
|
|
203
|
+
* `isTail`/`hasMoreTail` are set; intervals entirely newer keep their flags (unloaded older
|
|
204
|
+
* messages may still sit between them and the cutoff). The active window is re-emitted once.
|
|
205
|
+
*/
|
|
206
|
+
truncate: ({ truncatedAt }: {
|
|
207
|
+
truncatedAt: Date;
|
|
208
|
+
}) => void;
|
|
209
|
+
applyMessageDeletionForUser: ({ userId, hardDelete, deletedAt, }: {
|
|
210
|
+
userId: string;
|
|
211
|
+
hardDelete?: boolean;
|
|
212
|
+
deletedAt: Date;
|
|
213
|
+
}) => void;
|
|
214
|
+
/**
|
|
215
|
+
* Ensures quoted-message snapshots across loaded paginator cache are in sync
|
|
216
|
+
* with the provided message.
|
|
217
|
+
*
|
|
218
|
+
* Scans cached messages and updates any item where `quoted_message_id`
|
|
219
|
+
* matches `message.id`.
|
|
220
|
+
*/
|
|
221
|
+
reflectQuotedMessageUpdate: (message: LocalMessage) => void;
|
|
222
|
+
/**
|
|
223
|
+
* Reflect an updated `user` object onto every cached message authored by that user, mirroring
|
|
224
|
+
* the legacy `ChannelState.updateUserMessages` for the main message list (does not touch
|
|
225
|
+
* `quoted_message.user` — that is not part of the legacy behavior).
|
|
226
|
+
*
|
|
227
|
+
* Batched: a user rename can affect many messages, so this patches the shared item index and
|
|
228
|
+
* re-emits the active window a single time (if it held an affected message) rather than one
|
|
229
|
+
* `ingestItem` re-emit per message.
|
|
230
|
+
*/
|
|
231
|
+
reflectUserUpdate: (user: UserResponse) => void;
|
|
232
|
+
/**
|
|
233
|
+
* Apply a reaction WS event (`reaction.new` / `reaction.updated` / `reaction.deleted`) to the
|
|
234
|
+
* cached message. The event's `message` already carries the server-updated
|
|
235
|
+
* `reaction_groups` / `latest_reactions`; only `own_reactions` needs local preservation so a
|
|
236
|
+
* cross-user reaction does not wipe the current user's reactions. This re-homes what
|
|
237
|
+
* `ChannelState.addReaction` / `removeReaction` used to do off the now-removed
|
|
238
|
+
* `channel.state.messages` / `channel.state.threads` caches (the same logic backs the thread
|
|
239
|
+
* paginator via `Thread.messagePaginator`).
|
|
240
|
+
*
|
|
241
|
+
* `own_reactions` is seeded from the currently cached item (so another user's reaction keeps ours),
|
|
242
|
+
* falling back to the event's own_reactions when the message is not loaded — matching the legacy
|
|
243
|
+
* behavior where `_updateMessage` only mutated a message that existed locally.
|
|
244
|
+
*
|
|
245
|
+
* @param params - The reaction event payload.
|
|
246
|
+
* @param params.message - The reaction event's message, carrying the
|
|
247
|
+
* server-computed `reaction_groups` / `latest_reactions`. Ingested as-is except for `own_reactions`.
|
|
248
|
+
* @param params.reaction - The reaction from the event. Only added to/removed from
|
|
249
|
+
* `own_reactions` when its `user_id` is the current user; otherwise the current user's
|
|
250
|
+
* `own_reactions` are left untouched.
|
|
251
|
+
* @param [params.removed=false] - `true` for `reaction.deleted` (remove the reaction from
|
|
252
|
+
* `own_reactions`); `false` for `reaction.new` / `reaction.updated` (add it).
|
|
253
|
+
* @param [params.enforceUnique=false] - When adding, first clear the current user's existing
|
|
254
|
+
* `own_reactions` so only the incoming one remains (used by `reaction.updated`, where a user's
|
|
255
|
+
* reaction replaces their previous one).
|
|
256
|
+
*
|
|
257
|
+
* TODO(reactive-store): reflect reactions ONCE at the store level, not per-paginator. Both the
|
|
258
|
+
* channel handler (channel.ts) and the thread handler (thread.ts) call this on every reaction.*
|
|
259
|
+
* event, so a message held in more than one collection (a show_in_channel reply, or the thread
|
|
260
|
+
* parent) is reflected TWICE: two writes to the same canonical slot, each fanning out to the
|
|
261
|
+
* other holder (double re-projection) and minting a fresh ref that defeats the reconcile
|
|
262
|
+
* ref-equality bail. Idempotent (counts come wholesale from the event) so the result is correct,
|
|
263
|
+
* just wasteful. The store already fans out to every holder, so reflect once (by id, if held) and
|
|
264
|
+
* retire the per-collection reflect calls + parent path + enforce_unique branch.
|
|
265
|
+
*/
|
|
266
|
+
reflectReaction: ({ enforceUnique, message, reaction, removed, }: {
|
|
267
|
+
message: MessageResponse | LocalMessage;
|
|
268
|
+
reaction: ReactionResponse;
|
|
269
|
+
enforceUnique?: boolean;
|
|
270
|
+
removed?: boolean;
|
|
271
|
+
}) => void;
|
|
272
|
+
/**
|
|
273
|
+
* Map a timestamp to a loaded message — the first message in the latest (head) window whose
|
|
274
|
+
* `created_at` is >= `timestampMs` (mirrors the legacy `ChannelState.findMessageByTimestamp`
|
|
275
|
+
* lower-bound search), or the newest loaded message when the timestamp is beyond it. Used by the
|
|
276
|
+
* receipts tracker to resolve read/delivered cursors. Searches the newest loaded window — where
|
|
277
|
+
* read cursors live — which is already sorted, so this is O(log n) with no re-sort.
|
|
278
|
+
*/
|
|
279
|
+
findItemByTimestamp: (timestampMs: number, exactTsMatch?: boolean) => LocalMessage | null;
|
|
280
|
+
filterQueryResults: (items: LocalMessage[]) => LocalMessage[];
|
|
281
|
+
private getCanonicalQueryItems;
|
|
282
|
+
}
|