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,848 @@
|
|
|
1
|
+
import type { ItemLocation } from '../sortCompiler';
|
|
2
|
+
import { StateStore, type ValueOrPatch } from '../../store';
|
|
3
|
+
import { type DebouncedFunc } from '../../utils';
|
|
4
|
+
import type { FieldToDataResolver } from '../types.normalization';
|
|
5
|
+
import type { ItemIndexApi } from '../ItemIndex';
|
|
6
|
+
export declare const LOGICAL_HEAD_INTERVAL_ID = "__logical_head__";
|
|
7
|
+
export declare const LOGICAL_TAIL_INTERVAL_ID = "__logical_tail__";
|
|
8
|
+
type IntervalSortBounds<T> = {
|
|
9
|
+
start: T;
|
|
10
|
+
end: T;
|
|
11
|
+
};
|
|
12
|
+
type IntervalPaginationEdges<T> = {
|
|
13
|
+
head: T;
|
|
14
|
+
tail: T;
|
|
15
|
+
};
|
|
16
|
+
export type LogicalInterval = {
|
|
17
|
+
itemIds: string[];
|
|
18
|
+
id: typeof LOGICAL_HEAD_INTERVAL_ID | typeof LOGICAL_TAIL_INTERVAL_ID;
|
|
19
|
+
};
|
|
20
|
+
export type Interval = {
|
|
21
|
+
hasMoreHead: boolean;
|
|
22
|
+
hasMoreTail: boolean;
|
|
23
|
+
itemIds: string[];
|
|
24
|
+
id: string;
|
|
25
|
+
/**
|
|
26
|
+
* True if this interval represents the global head of the dataset
|
|
27
|
+
* under the current sortComparator.
|
|
28
|
+
*
|
|
29
|
+
* Cursor pagination:
|
|
30
|
+
* headward === null
|
|
31
|
+
*
|
|
32
|
+
* Offset pagination:
|
|
33
|
+
* offset === 0
|
|
34
|
+
*/
|
|
35
|
+
isHead: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* True if this interval represents the global tail of the dataset
|
|
38
|
+
* under the current sortComparator.
|
|
39
|
+
*
|
|
40
|
+
* Cursor pagination:
|
|
41
|
+
* tailward === null
|
|
42
|
+
*
|
|
43
|
+
* Offset pagination:
|
|
44
|
+
* returnedItems.length < pageSize
|
|
45
|
+
*/
|
|
46
|
+
isTail: boolean;
|
|
47
|
+
};
|
|
48
|
+
export type AnyInterval = Interval | LogicalInterval;
|
|
49
|
+
export type IntervalMergePolicy = 'auto' | 'strict-overlap-only';
|
|
50
|
+
type ItemIntervalCoordinates = ItemLocation & {
|
|
51
|
+
interval: Interval | LogicalInterval;
|
|
52
|
+
};
|
|
53
|
+
export type ItemCoordinates = {
|
|
54
|
+
/** Location inside state.items (visible list) */
|
|
55
|
+
state?: ItemLocation;
|
|
56
|
+
/** Location inside an interval (anchored or logical) */
|
|
57
|
+
interval?: ItemIntervalCoordinates;
|
|
58
|
+
};
|
|
59
|
+
export declare const isLiveHeadInterval: (interval: AnyInterval) => interval is LogicalInterval;
|
|
60
|
+
export declare const isLiveTailInterval: (interval: AnyInterval) => interval is LogicalInterval;
|
|
61
|
+
export declare const isLogicalInterval: (interval: AnyInterval) => interval is LogicalInterval;
|
|
62
|
+
export type MakeIntervalParams<T> = {
|
|
63
|
+
page: T[];
|
|
64
|
+
isHead?: boolean;
|
|
65
|
+
isTail?: boolean;
|
|
66
|
+
};
|
|
67
|
+
export type SetPaginatorItemsParams<T> = {
|
|
68
|
+
valueOrFactory: ValueOrPatch<T[]>;
|
|
69
|
+
cursor?: PaginatorCursor;
|
|
70
|
+
/**
|
|
71
|
+
* Relevant only is using item interval storage in the paginator.
|
|
72
|
+
* Indicates that the page would be the head of pagination intervals array.
|
|
73
|
+
* Items falling outside this intervals head bound will be merged into this interval.
|
|
74
|
+
*/
|
|
75
|
+
isFirstPage?: boolean;
|
|
76
|
+
/**
|
|
77
|
+
* Relevant only is using item interval storage in the paginator.
|
|
78
|
+
* Indicates that the page would be the tail of pagination intervals array
|
|
79
|
+
* Items falling outside this intervals tail bound will be merged into this interval.
|
|
80
|
+
*/
|
|
81
|
+
isLastPage?: boolean;
|
|
82
|
+
};
|
|
83
|
+
type MergeIntervalsResult = {
|
|
84
|
+
logicalHead: LogicalInterval | null;
|
|
85
|
+
merged: Interval | null;
|
|
86
|
+
logicalTail: LogicalInterval | null;
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* headward - going from page X -> X-Y -> 0
|
|
90
|
+
* tailward - goring from page 0 -> X -> X + Y ...
|
|
91
|
+
*
|
|
92
|
+
* Head is the place where new items are added - same as git.
|
|
93
|
+
* Tail is the place where retrieved pages are appended.
|
|
94
|
+
*/
|
|
95
|
+
export type PaginationDirection = 'headward' | 'tailward';
|
|
96
|
+
export type CursorDeriveContext<T, Q> = {
|
|
97
|
+
/**
|
|
98
|
+
* Current cursor to be merged with the newly derived cursor.
|
|
99
|
+
* Allows to preserve the direction we have not paginated with the given request.
|
|
100
|
+
*/
|
|
101
|
+
cursor: PaginatorCursor | undefined;
|
|
102
|
+
/**
|
|
103
|
+
* Direction we just paginated in.
|
|
104
|
+
*
|
|
105
|
+
* May be undefined for non-directional queries (e.g. jump-to / *_around).
|
|
106
|
+
*/
|
|
107
|
+
direction: PaginationDirection | undefined;
|
|
108
|
+
hasMoreTail: boolean;
|
|
109
|
+
hasMoreHead: boolean;
|
|
110
|
+
/** The parent interval the page was ingested into (if any) */
|
|
111
|
+
interval: Interval;
|
|
112
|
+
/** The page we just received after filtering */
|
|
113
|
+
page: T[];
|
|
114
|
+
/** Last query shape (sometimes useful for bespoke logic) */
|
|
115
|
+
queryShape: Q | undefined;
|
|
116
|
+
/** Number we asked for */
|
|
117
|
+
requestedPageSize: number;
|
|
118
|
+
};
|
|
119
|
+
export type PaginationFlags = {
|
|
120
|
+
hasMoreHead: boolean;
|
|
121
|
+
hasMoreTail: boolean;
|
|
122
|
+
};
|
|
123
|
+
export type CursorDeriveResult = PaginationFlags & {
|
|
124
|
+
cursor: PaginatorCursor | undefined;
|
|
125
|
+
};
|
|
126
|
+
export type CursorDerivator<T, Q> = (ctx: CursorDeriveContext<T, Q>) => CursorDeriveResult;
|
|
127
|
+
/**
|
|
128
|
+
* string - there is a next page in the given direction
|
|
129
|
+
* null - pagination in the given direction has been exhausted
|
|
130
|
+
* undefined - no page has been requested in the given pagination direction
|
|
131
|
+
*/
|
|
132
|
+
export type PaginatorCursor = {
|
|
133
|
+
tailward: string | null | undefined;
|
|
134
|
+
headward: string | null | undefined;
|
|
135
|
+
};
|
|
136
|
+
export declare const ZERO_PAGE_CURSOR: PaginatorCursor;
|
|
137
|
+
type StateResetPolicy = 'auto' | 'yes' | 'no' | (string & {});
|
|
138
|
+
export type PaginationQueryShapeChangeIdentifier<S> = (toHeadQueryShape?: S, toTailQueryShape?: S) => boolean;
|
|
139
|
+
export type PaginationQueryParams<Q> = {
|
|
140
|
+
direction?: PaginationDirection;
|
|
141
|
+
/**
|
|
142
|
+
* Keep the currently loaded items (and cursor/flags) visible while a first-page query runs
|
|
143
|
+
* instead of blanking to the empty initial state. The freshly fetched page is merged into the
|
|
144
|
+
* active interval by `postQueryReconcile` (upserting changed items, appending new ones), so the
|
|
145
|
+
* list is refreshed in place with no loading-screen flash. Used by the non-destructive refresh.
|
|
146
|
+
*/
|
|
147
|
+
keepPreviousItems?: boolean;
|
|
148
|
+
/** Data that define the query (filters, sort, ...) */
|
|
149
|
+
queryShape?: Q;
|
|
150
|
+
/** Per-call override of the reset behavior. */
|
|
151
|
+
reset?: StateResetPolicy;
|
|
152
|
+
/**
|
|
153
|
+
* How many times to **retry** a failed request, i.e. `retryCount + 1` attempts in total. Per-call
|
|
154
|
+
* override of `PaginatorOptions.retryCount`, which defaults to 0 (no retry).
|
|
155
|
+
*/
|
|
156
|
+
retryCount?: number;
|
|
157
|
+
/**
|
|
158
|
+
* Suppress `isLoading` transitions for this query (a silent, background refresh). When falsy
|
|
159
|
+
* (default) the usual loading state is surfaced so the UI can show a spinner.
|
|
160
|
+
*/
|
|
161
|
+
silent?: boolean;
|
|
162
|
+
/** Determines, whether the page loaded with the query will be committed to the paginator state. Default: true. */
|
|
163
|
+
updateState?: boolean;
|
|
164
|
+
};
|
|
165
|
+
export type PostQueryReconcileParams<T, Q> = Pick<PaginationQueryParams<Q>, 'direction' | 'queryShape' | 'updateState' | 'keepPreviousItems'> & {
|
|
166
|
+
isFirstPage: boolean;
|
|
167
|
+
requestedPageSize: number;
|
|
168
|
+
results: PaginationQueryReturnValue<T> | null;
|
|
169
|
+
};
|
|
170
|
+
export type ExecuteQueryReturnValue<T> = {
|
|
171
|
+
/**
|
|
172
|
+
* State object resulting from the post query processing.
|
|
173
|
+
* The object is committed to the state if PaginationQueryParams<Q>['updateState'] === true.
|
|
174
|
+
*/
|
|
175
|
+
stateCandidate: Partial<PaginatorState<T>>;
|
|
176
|
+
/** In case the items are kept in intervals, the interval into which the page has been merged, will be returned. */
|
|
177
|
+
targetInterval: AnyInterval | null;
|
|
178
|
+
};
|
|
179
|
+
export type PaginationQueryReturnValue<T> = {
|
|
180
|
+
items: T[];
|
|
181
|
+
} & {
|
|
182
|
+
headward?: string;
|
|
183
|
+
tailward?: string;
|
|
184
|
+
/**
|
|
185
|
+
* @deprecated Use `tailward` instead.
|
|
186
|
+
*/
|
|
187
|
+
next?: string;
|
|
188
|
+
/**
|
|
189
|
+
* @deprecated Use `headward` instead.
|
|
190
|
+
*/
|
|
191
|
+
prev?: string;
|
|
192
|
+
};
|
|
193
|
+
export type PaginatorDebounceOptions = {
|
|
194
|
+
debounceMs: number;
|
|
195
|
+
};
|
|
196
|
+
type DebouncedExecQueryFunction<Q> = DebouncedFunc<(params: PaginationQueryParams<Q>) => Promise<void>>;
|
|
197
|
+
export type PaginatorState<T> = {
|
|
198
|
+
hasMoreHead: boolean;
|
|
199
|
+
hasMoreTail: boolean;
|
|
200
|
+
isLoading: boolean;
|
|
201
|
+
items: T[] | undefined;
|
|
202
|
+
lastQueryError?: Error;
|
|
203
|
+
cursor?: PaginatorCursor;
|
|
204
|
+
offset?: number;
|
|
205
|
+
};
|
|
206
|
+
/**
|
|
207
|
+
* Reactive projections of specific (fixed-identity) intervals, published independently of the
|
|
208
|
+
* paginated `state` (which tracks only the *active* interval). See {@link BasePaginator.intervalViews}.
|
|
209
|
+
* A field is rewritten only when its own interval changes, so a `useStateStore`/`subscribeWithSelector`
|
|
210
|
+
* consumer selecting one field only wakes when *that* interval changes. (The head-most window that can
|
|
211
|
+
* be either a logical or an anchored interval is a derived *role*, not a fixed interval, so it is not
|
|
212
|
+
* published here — read it one-shot via {@link BasePaginator.headItems} / {@link BasePaginator.headmostItem}.)
|
|
213
|
+
*/
|
|
214
|
+
export type PaginatorIntervalViews<T> = {
|
|
215
|
+
/** Live logical-head interval — out-of-order items above the loaded window. */
|
|
216
|
+
logicalHead: T[];
|
|
217
|
+
/** Live logical-tail interval — out-of-order items below the loaded window. */
|
|
218
|
+
logicalTail: T[];
|
|
219
|
+
/**
|
|
220
|
+
* Anchored head interval — the loaded page bounded at the dataset head (`isHead`), i.e. the newest
|
|
221
|
+
* loaded page; empty when the head is not loaded. Its content updates when that page ingests/removes
|
|
222
|
+
* an item, and its identity updates when a page's `isHead` flag flips during query reconciliation.
|
|
223
|
+
*/
|
|
224
|
+
anchoredHead: T[];
|
|
225
|
+
};
|
|
226
|
+
export type PaginatorItemsChangeProcessor<T> = (params: {
|
|
227
|
+
nextItems: T[] | undefined;
|
|
228
|
+
previousItems: T[] | undefined;
|
|
229
|
+
}) => T[] | undefined;
|
|
230
|
+
export interface PaginatorPlugin<T> {
|
|
231
|
+
/**
|
|
232
|
+
* Optional plugin hook invoked immediately before the paginator emits a new
|
|
233
|
+
* `items` value to subscribers, but only when the `items` array has actually
|
|
234
|
+
* changed by reference.
|
|
235
|
+
*
|
|
236
|
+
* This hook allows plugins to post-process the visible items—such as
|
|
237
|
+
* deduplicating, normalizing, sorting, enriching, or otherwise transforming
|
|
238
|
+
* the array—at the final stage of state emission. The processed value becomes
|
|
239
|
+
* the `items` value delivered to subscribers.
|
|
240
|
+
*
|
|
241
|
+
* Return a new array to replace `nextState.items`, or return `undefined`
|
|
242
|
+
* to leave the items unchanged.
|
|
243
|
+
*
|
|
244
|
+
* Executed in the order plugins are registered.
|
|
245
|
+
*/
|
|
246
|
+
onBeforeItemsEmitted?: PaginatorItemsChangeProcessor<T>;
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Optional list of plugins that can hook into paginator lifecycle events.
|
|
250
|
+
*
|
|
251
|
+
* Plugins allow you to encapsulate cross-cutting behavior (such as items
|
|
252
|
+
* post-processing, analytics, offline caching, etc.) without modifying
|
|
253
|
+
* the core paginator logic. Each plugin can register handlers like
|
|
254
|
+
* `onItemsChange` that are invoked when relevant events occur.
|
|
255
|
+
*
|
|
256
|
+
* All registered plugins are executed in the order they appear in this array.
|
|
257
|
+
*/
|
|
258
|
+
export type PaginatorOptions<T, Q> = {
|
|
259
|
+
/** The number of milliseconds to debounce the search query. The default interval is 300ms. */
|
|
260
|
+
debounceMs?: number;
|
|
261
|
+
/**
|
|
262
|
+
* When set (and not disabled for tests — see `stateThrottling.ts`), coalesces the paginator's own
|
|
263
|
+
* live `state.items` publishes to at most once per `stateThrottleMs` (leading + trailing edge): a
|
|
264
|
+
* burst of live mutations (WS `message.new`, reactions, reads) re-projects the active window and
|
|
265
|
+
* publishes it ~2×/sec instead of once per event. Only the paginator's OWN writes to `state.items`
|
|
266
|
+
* are batched — `state.getLatestValue()` is untouched (no `StateStore` change), pagination / jump /
|
|
267
|
+
* query publishes stay immediate, and an immediate flush past it is available via
|
|
268
|
+
* {@link flushPendingPublishes}. Unset ⇒ no throttle (default). Enabled at
|
|
269
|
+
* 500ms for the message list — see {@link MessagePaginator}.
|
|
270
|
+
*/
|
|
271
|
+
stateThrottleMs?: number;
|
|
272
|
+
/**
|
|
273
|
+
* Function containing custom logic that decides, whether the next pagination query to be executed should be considered the first page query.
|
|
274
|
+
* It makes sense to consider the next query as the first page query if filters, sort, options etc. (query params) excluding the page size have changed.
|
|
275
|
+
*/
|
|
276
|
+
hasPaginationQueryShapeChanged?: PaginationQueryShapeChangeIdentifier<any>;
|
|
277
|
+
/**
|
|
278
|
+
* Optional hook to fully control cursor + hasMore logic in 'derived' mode.
|
|
279
|
+
* If not provided, BasePaginator uses its own default implementation.
|
|
280
|
+
*/
|
|
281
|
+
deriveCursor?: CursorDerivator<T, Q>;
|
|
282
|
+
/** Custom function to retrieve items pages and optionally return a cursor in case of cursor pagination. */
|
|
283
|
+
doRequest?: (queryParams: Q) => Promise<{
|
|
284
|
+
items: T[];
|
|
285
|
+
cursor?: PaginatorCursor;
|
|
286
|
+
}>;
|
|
287
|
+
/** In case of cursor pagination, specify the initial cursor value. */
|
|
288
|
+
initialCursor?: PaginatorCursor;
|
|
289
|
+
/** In case of offset pagination, specify the initial offset value. */
|
|
290
|
+
initialOffset?: number;
|
|
291
|
+
/** If item index is provided, this index ensures updates in a single place and all consumers have access to a single source of data. */
|
|
292
|
+
itemIndex?: ItemIndexApi<T>;
|
|
293
|
+
/**
|
|
294
|
+
* Factory for the item index, invoked with the fully-constructed paginator as `owner`.
|
|
295
|
+
* Lets a subclass back the paginator with an adapter that needs a reference to the
|
|
296
|
+
* owner (e.g. a shared, client-global store) without the `this`-before-`super` problem.
|
|
297
|
+
* Ignored when an explicit `itemIndex` is supplied.
|
|
298
|
+
*/
|
|
299
|
+
createItemIndex?: (owner: BasePaginator<T, Q>) => ItemIndexApi<T>;
|
|
300
|
+
/**
|
|
301
|
+
* Comparator defining in-memory item ordering for interval math and visible list rendering.
|
|
302
|
+
* Defaults to `sortComparator` to preserve existing paginator behavior.
|
|
303
|
+
*/
|
|
304
|
+
itemOrderComparator?: (a: T, b: T) => number;
|
|
305
|
+
/**
|
|
306
|
+
* Will prevent changing the index of existing items in state.
|
|
307
|
+
* If true, an item that is already visible keeps its relative position in the current items array when updated.
|
|
308
|
+
* It does not guarantee global stability across interval changes or page jumps.
|
|
309
|
+
*/
|
|
310
|
+
lockItemOrder?: boolean;
|
|
311
|
+
/** The item page size to be requested from the server. */
|
|
312
|
+
pageSize?: number;
|
|
313
|
+
/**
|
|
314
|
+
* How many times to **retry** a failed request before giving up, i.e. `retryCount + 1` attempts in
|
|
315
|
+
* total, with `DEFAULT_QUERY_CHANNELS_MS_BETWEEN_RETRIES` between them. Defaults to 0 (no retry);
|
|
316
|
+
* `PaginationQueryParams.retryCount` overrides it per call.
|
|
317
|
+
*/
|
|
318
|
+
retryCount?: number;
|
|
319
|
+
/** Prevent silencing the errors thrown during the pagination execution. Default is false. */
|
|
320
|
+
throwErrors?: boolean;
|
|
321
|
+
};
|
|
322
|
+
type OptionalPaginatorConfigFields = 'stateThrottleMs' | 'deriveCursor' | 'doRequest' | 'initialCursor' | 'initialOffset' | 'itemIndex' | 'createItemIndex' | 'itemOrderComparator' | 'throwErrors';
|
|
323
|
+
export type BasePaginatorConfig<T, Q> = Pick<PaginatorOptions<T, Q>, OptionalPaginatorConfigFields> & Required<Omit<PaginatorOptions<T, Q>, OptionalPaginatorConfigFields>>;
|
|
324
|
+
export declare const DEFAULT_PAGINATION_OPTIONS: BasePaginatorConfig<any, any>;
|
|
325
|
+
export declare abstract class BasePaginator<T, Q> {
|
|
326
|
+
state: StateStore<PaginatorState<T>>;
|
|
327
|
+
/**
|
|
328
|
+
* Reactive projections of specific intervals — see {@link PaginatorIntervalViews}. Unlike `state`
|
|
329
|
+
* (which only re-emits when the *active* interval is impacted), a field here is rewritten whenever
|
|
330
|
+
* its own interval changes, regardless of which interval is active — so consumers can reactively
|
|
331
|
+
* render off-window "sideloaded" content (`logicalHead`/`logicalTail`) and the newest loaded page
|
|
332
|
+
* (`anchoredHead`). Kept separate from `state` so the paginated-list contract stays focused on the
|
|
333
|
+
* active window + pagination status.
|
|
334
|
+
*/
|
|
335
|
+
intervalViews: StateStore<PaginatorIntervalViews<T>>;
|
|
336
|
+
config: BasePaginatorConfig<T, Q>;
|
|
337
|
+
/**
|
|
338
|
+
* Throttle for the active-window `state.items` publish (message list). Created only when
|
|
339
|
+
* `config.stateThrottleMs` is set; drives {@link scheduleWindowPublish} / {@link flushPendingPublishes}. See
|
|
340
|
+
* `stateThrottleMs` in {@link PaginatorOptions}.
|
|
341
|
+
*/
|
|
342
|
+
private _windowPublishThrottle?;
|
|
343
|
+
/**
|
|
344
|
+
* Throttle for the interval-view publishes (`anchoredHead` / `logicalHead` / `logicalTail`) driven
|
|
345
|
+
* by sibling store updates. Independent of {@link _windowPublishThrottle} so a view refresh lands on
|
|
346
|
+
* its own trailing edge even when `state.items` stays quiet. Created alongside it (only when
|
|
347
|
+
* `config.stateThrottleMs` is set); buffers changed ids in {@link _pendingViewChangedIds}.
|
|
348
|
+
*/
|
|
349
|
+
private _viewPublishThrottle?;
|
|
350
|
+
/** Changed ids buffered since the last {@link flushIntervalViewPublish} (throttled paginators only). */
|
|
351
|
+
private _pendingViewChangedIds;
|
|
352
|
+
/**
|
|
353
|
+
* Intervals keep items in disconnected ranges.
|
|
354
|
+
* That is a scenario of jumping to non-sequential pages.
|
|
355
|
+
* Intervals are populated only if itemIndex is provided.
|
|
356
|
+
*/
|
|
357
|
+
protected _itemIntervals: Map<string, AnyInterval>;
|
|
358
|
+
protected _activeIntervalId: string | undefined;
|
|
359
|
+
/**
|
|
360
|
+
* ItemIndex is a canonical, ID-addressable storage layer for domain items.
|
|
361
|
+
* It serves as a single source of truth for all those that need to access the items
|
|
362
|
+
* outside the paginator.
|
|
363
|
+
*/
|
|
364
|
+
protected _itemIndex: ItemIndexApi<T>;
|
|
365
|
+
protected _executeQueryDebounced: DebouncedExecQueryFunction<Q>;
|
|
366
|
+
/** Last effective query shape produced by subclass for the most recent request. */
|
|
367
|
+
protected _lastQueryShape?: Q;
|
|
368
|
+
protected _nextQueryShape?: Q;
|
|
369
|
+
/**
|
|
370
|
+
* Stable, performs purely item data-driven (age, last_message_at, etc.) comparison.
|
|
371
|
+
* Used under the hood
|
|
372
|
+
* 1. as a fallback by effectiveComparator / boostComparator if boost comparison is not conclusive
|
|
373
|
+
* 2. interval comparator
|
|
374
|
+
*
|
|
375
|
+
* Intervals cannot be sorted using boostComparator, because boosting the interval boundary (top item)
|
|
376
|
+
* would lead to the boosting of the entire interval when sorting the intervals.
|
|
377
|
+
*
|
|
378
|
+
* Sorting within a single interval should be done using effectiveComparator, which by default uses boostComparator.
|
|
379
|
+
*/
|
|
380
|
+
sortComparator: (a: T, b: T) => number;
|
|
381
|
+
protected _filterFieldToDataResolvers: FieldToDataResolver<T>[];
|
|
382
|
+
protected boosts: Map<string, {
|
|
383
|
+
until: number;
|
|
384
|
+
seq: number;
|
|
385
|
+
}>;
|
|
386
|
+
protected _maxBoostSeq: number;
|
|
387
|
+
/**
|
|
388
|
+
* Describes how `interval.itemIds` are oriented relative to pagination semantics.
|
|
389
|
+
*
|
|
390
|
+
* - `true` => `itemIds[0]` is the pagination head edge (default)
|
|
391
|
+
* - `false` => `itemIds[itemIds.length - 1]` is the pagination head edge
|
|
392
|
+
*
|
|
393
|
+
* NOTE: This does not affect the *sorting* of `itemIds` (they are always kept
|
|
394
|
+
* in `sortComparator` order). It only affects which side is considered
|
|
395
|
+
* "head" for interval ordering and live ingestion decisions.
|
|
396
|
+
*/
|
|
397
|
+
protected get intervalItemIdsAreHeadFirst(): boolean;
|
|
398
|
+
/**
|
|
399
|
+
* Determines the ordering of intervals in the internal interval list.
|
|
400
|
+
*
|
|
401
|
+
* This controls only the ordering of intervals relative to each other (by comparing
|
|
402
|
+
* their head edges using `sortComparator`). It is intentionally decoupled from:
|
|
403
|
+
* - the ordering of itemIds inside an interval
|
|
404
|
+
* - the meaning of the head edge (controlled by `intervalItemIdsAreHeadFirst`)
|
|
405
|
+
*/
|
|
406
|
+
protected get intervalSortDirection(): 'asc' | 'desc';
|
|
407
|
+
protected constructor({ initialCursor, initialOffset, itemIndex, createItemIndex, ...options }?: PaginatorOptions<T, Q>);
|
|
408
|
+
get lastQueryError(): Error | undefined;
|
|
409
|
+
get hasMoreTail(): boolean;
|
|
410
|
+
get hasMoreHead(): boolean;
|
|
411
|
+
/**
|
|
412
|
+
* @deprecated Use `hasMoreTail` instead.
|
|
413
|
+
*/
|
|
414
|
+
get hasNext(): boolean;
|
|
415
|
+
/**
|
|
416
|
+
* @deprecated Use `hasMoreHead` instead.
|
|
417
|
+
*/
|
|
418
|
+
get hasPrev(): boolean;
|
|
419
|
+
get hasResults(): boolean;
|
|
420
|
+
get isLoading(): boolean;
|
|
421
|
+
/** Signals that the paginator has not performed any query so far */
|
|
422
|
+
get isInitialized(): boolean;
|
|
423
|
+
get isOfflineSupportEnabled(): boolean;
|
|
424
|
+
get isCursorPagination(): boolean;
|
|
425
|
+
get initialState(): PaginatorState<T>;
|
|
426
|
+
get items(): T[] | undefined;
|
|
427
|
+
/**
|
|
428
|
+
* The newest loaded window of items, independent of which window is currently *active*
|
|
429
|
+
* (`items` follows the active interval, which may point at a jumped-to / searched window). This is
|
|
430
|
+
* the head-most loaded interval under the paginator's ordering (anchored or the live-head logical
|
|
431
|
+
* interval).
|
|
432
|
+
*
|
|
433
|
+
* NOTE: this deliberately uses the head-*most loaded* interval rather than requiring the
|
|
434
|
+
* `isHead` flag — the query/hydration seed does not reliably mark a freshly loaded latest page
|
|
435
|
+
* as `isHead`, so an isHead-only check would miss channel-list channels entirely. The trade-off
|
|
436
|
+
* is that after jumping to an older window with the latest window not loaded, this reports that
|
|
437
|
+
* older window as "latest" (best effort). Use for "latest"-derived reads: last message, unread
|
|
438
|
+
* counting, delivery candidates, channel-list previews.
|
|
439
|
+
*/
|
|
440
|
+
get headItems(): T[];
|
|
441
|
+
/**
|
|
442
|
+
* The item on the head edge of the head pagination interval (of {@link BasePaginator.headItems}).
|
|
443
|
+
* `undefined` when nothing is loaded.
|
|
444
|
+
*/
|
|
445
|
+
get headmostItem(): T | undefined;
|
|
446
|
+
get cursor(): PaginatorCursor | undefined;
|
|
447
|
+
get offset(): number | undefined;
|
|
448
|
+
get pageSize(): number;
|
|
449
|
+
set pageSize(size: number);
|
|
450
|
+
set initialCursor(cursor: PaginatorCursor);
|
|
451
|
+
set initialOffset(offset: number);
|
|
452
|
+
/** Single point of truth: always use the effective comparator */
|
|
453
|
+
get effectiveComparator(): (a: T, b: T) => number;
|
|
454
|
+
protected get itemOrderComparator(): (a: T, b: T) => number;
|
|
455
|
+
get intervalComparator(): (a: AnyInterval, b: AnyInterval) => number;
|
|
456
|
+
get maxBoostSeq(): number;
|
|
457
|
+
protected get itemIntervals(): AnyInterval[];
|
|
458
|
+
protected get liveHeadLogical(): LogicalInterval | undefined;
|
|
459
|
+
protected get liveTailLogical(): LogicalInterval | undefined;
|
|
460
|
+
/**
|
|
461
|
+
* The current contents of the live logical-head interval (items ingested out of pagination order).
|
|
462
|
+
* Reads the same value published to {@link BasePaginator.intervalViews}.`logicalHead`.
|
|
463
|
+
*/
|
|
464
|
+
get logicalHeadItems(): T[];
|
|
465
|
+
/**
|
|
466
|
+
* The current contents of the live logical-tail interval (out-of-order items below the loaded
|
|
467
|
+
* window). Reads the same value published to {@link BasePaginator.intervalViews}.`logicalTail`.
|
|
468
|
+
*/
|
|
469
|
+
get logicalTailItems(): T[];
|
|
470
|
+
/**
|
|
471
|
+
* The current contents of the anchored head interval (the loaded page bounded at the dataset head,
|
|
472
|
+
* `isHead`). Reads the same value published to {@link BasePaginator.intervalViews}.`anchoredHead`.
|
|
473
|
+
*/
|
|
474
|
+
get anchoredHeadItems(): T[];
|
|
475
|
+
/**
|
|
476
|
+
* Commit an interval into storage. Single choke point for adding/updating an interval, so it also
|
|
477
|
+
* republishes the matching {@link intervalViews} field when the committed interval is a tracked one
|
|
478
|
+
* (logical head / logical tail / anchored head). Use this instead of writing `_itemIntervals`
|
|
479
|
+
* directly — bulk re-sorting (which does not change any interval's membership) goes through
|
|
480
|
+
* {@link setIntervals}.
|
|
481
|
+
*/
|
|
482
|
+
protected commitInterval(interval: AnyInterval): void;
|
|
483
|
+
/** Drop an interval from storage, republishing the matching {@link intervalViews} field if tracked. */
|
|
484
|
+
protected dropInterval(id: string): void;
|
|
485
|
+
/**
|
|
486
|
+
* Republish the {@link intervalViews} field backed by the given interval — called from
|
|
487
|
+
* {@link commitInterval} / {@link dropInterval} (i.e. when that interval ingests or removes an item).
|
|
488
|
+
* A write to an untracked interval touches nothing here. (The anchored head is also published
|
|
489
|
+
* directly via {@link publishAsAnchoredHead} from the reconciliation points that flip `isHead` —
|
|
490
|
+
* see {@link postQueryReconcile}.)
|
|
491
|
+
*/
|
|
492
|
+
private publishIntervalViewFor;
|
|
493
|
+
/**
|
|
494
|
+
* Publish `interval` as the anchored head — the loaded page bounded at the dataset head (`isHead`),
|
|
495
|
+
* or `undefined` to clear it (the head page was removed or a page stopped being the head). Callers
|
|
496
|
+
* pass the interval they already have, so this does not re-scan storage for the head. Its content
|
|
497
|
+
* changes via ingest/remove (routed through {@link commitInterval}/{@link dropInterval}) and its
|
|
498
|
+
* identity changes when a page's `isHead` flag flips during query reconciliation — both call here.
|
|
499
|
+
*/
|
|
500
|
+
protected publishAsAnchoredHead(interval: AnyInterval | undefined): void;
|
|
501
|
+
/**
|
|
502
|
+
* Keep `anchoredHead` in sync after a page's `isHead` flag was (re)computed during query
|
|
503
|
+
* reconciliation, given its value `wasHead` beforehand. Acts only on an actual transition:
|
|
504
|
+
* - became the head page → publish it as the anchored head;
|
|
505
|
+
* - stopped being the head page → clear the anchored head;
|
|
506
|
+
* - unchanged → nothing (a content change, if any, was already published when the interval was
|
|
507
|
+
* committed — see {@link commitInterval}).
|
|
508
|
+
*/
|
|
509
|
+
protected syncAnchoredHeadAfterHeadFlip(interval: Interval, wasHead: boolean): void;
|
|
510
|
+
private intervalItemsOrEmpty;
|
|
511
|
+
/**
|
|
512
|
+
* Empty every {@link intervalViews} field. Used by reset paths that clear intervals in bulk (via
|
|
513
|
+
* {@link setIntervals}), which bypasses the per-interval {@link commitInterval}/{@link dropInterval}
|
|
514
|
+
* publishing. No-ops when the views are already empty so a reset does not emit needlessly.
|
|
515
|
+
*/
|
|
516
|
+
protected clearIntervalViews(): void;
|
|
517
|
+
abstract query(params: PaginationQueryParams<Q>): Promise<PaginationQueryReturnValue<T>>;
|
|
518
|
+
abstract filterQueryResults(items: T[]): T[];
|
|
519
|
+
/**
|
|
520
|
+
* Subclasses must return the query shape.
|
|
521
|
+
*/
|
|
522
|
+
protected getNextQueryShape(_params?: Pick<PaginationQueryParams<Q>, 'direction'>): Q;
|
|
523
|
+
/**
|
|
524
|
+
* Filters an item is matched against locally (`matchesFilter`) — NOT the filters sent to the server.
|
|
525
|
+
* A paginator whose backend query is filtered has to build the request filters separately (see
|
|
526
|
+
* `ChannelPaginator.buildQueryFilters`), because the two can differ: the backend may resolve a
|
|
527
|
+
* server-side stored filter of its own, and some paginators filter locally without sending anything.
|
|
528
|
+
*/
|
|
529
|
+
protected buildMatchFilters(): object | null;
|
|
530
|
+
matchesFilter(item: T): boolean;
|
|
531
|
+
setFilterResolvers(resolvers: FieldToDataResolver<T>[]): void;
|
|
532
|
+
addFilterResolvers(resolvers: FieldToDataResolver<T>[]): void;
|
|
533
|
+
getItemId(item: T): string;
|
|
534
|
+
getItem(id: string | undefined): T | undefined;
|
|
535
|
+
/**
|
|
536
|
+
* Whether this paginator's live `state.items` publishes are currently throttled — `stateThrottleMs`
|
|
537
|
+
* is set, throttling is not globally disabled (tests), and item order is not locked (a locked-order
|
|
538
|
+
* list must emit the caller-computed, order-preserved array, not a re-projection). When false, every
|
|
539
|
+
* live mutation publishes immediately, exactly as before this feature.
|
|
540
|
+
*/
|
|
541
|
+
protected get isStateThrottled(): boolean;
|
|
542
|
+
/** Re-project the active window from its (live, source-of-truth) interval. `undefined` when inactive. */
|
|
543
|
+
private projectActiveWindow;
|
|
544
|
+
/**
|
|
545
|
+
* Publish the active window to `state`, re-projecting it fresh from the active interval at call time
|
|
546
|
+
* (the throttle boundary / flush). Because the intervals are mutated synchronously by every live op,
|
|
547
|
+
* this always reflects the latest settled state, so intermediate values within a window coalesce
|
|
548
|
+
* away. Clears the visible window when the active interval is gone (e.g. the last item was removed).
|
|
549
|
+
*/
|
|
550
|
+
private flushWindowPublish;
|
|
551
|
+
/**
|
|
552
|
+
* Schedule a throttled active-window publish (leading + trailing). Called from live mutations
|
|
553
|
+
* (ingest / content-change / remove) INSTEAD of an inline `state.partialNext({ items })` when
|
|
554
|
+
* {@link isStateThrottled}. Safe to call many times within one op — they coalesce to a single emit.
|
|
555
|
+
*/
|
|
556
|
+
protected scheduleWindowPublish(): void;
|
|
557
|
+
/**
|
|
558
|
+
* Flush any pending throttled window + interval-view publishes immediately. No-op when nothing
|
|
559
|
+
* is pending or throttling is off.
|
|
560
|
+
*/
|
|
561
|
+
protected flushPendingPublishes(): void;
|
|
562
|
+
/**
|
|
563
|
+
* {@link _viewPublishThrottle} boundary: apply every interval-view change buffered since the last
|
|
564
|
+
* flush, then clear the buffer. Independent of the `state.items` window publish, so a view update
|
|
565
|
+
* lands within one throttle interval even when the active window stays quiet (e.g. a reaction on a
|
|
566
|
+
* head message while a non-head window is active). No-op when nothing was buffered.
|
|
567
|
+
*/
|
|
568
|
+
private flushIntervalViewPublish;
|
|
569
|
+
/**
|
|
570
|
+
* Refresh any tracked {@link intervalViews} field (logical head, logical tail, anchored head) that
|
|
571
|
+
* holds one of `changedIds`. A sibling holder writing new content through the shared item store
|
|
572
|
+
* swaps the item object those views reference, but only this paginator's own ingest/remove
|
|
573
|
+
* ({@link commitInterval}/{@link dropInterval}) republish them — so a reaction/edit made elsewhere
|
|
574
|
+
* would otherwise leave stale references in `anchoredHead`/`logicalHead`/`logicalTail` even though
|
|
575
|
+
* the active window (`state.items`, see {@link reconcileChangedIds}) was refreshed.
|
|
576
|
+
*
|
|
577
|
+
* Called immediately for un-throttled paginators, or from {@link flushIntervalViewPublish} at the
|
|
578
|
+
* view-publish throttle boundary when throttled — see {@link reconcileChangedIds}. Handled
|
|
579
|
+
* independently of `state.items`. When the anchored head is also the active interval its content is
|
|
580
|
+
* projected here as well as into `state.items`; deduping that double projection is a separate,
|
|
581
|
+
* deferred perf follow-up.
|
|
582
|
+
*/
|
|
583
|
+
private refreshIntervalViewsForChangedIds;
|
|
584
|
+
private intervalHoldsAnyChangedId;
|
|
585
|
+
/**
|
|
586
|
+
* Reconcile the projected window + interval views against a set of changed ids: another holder
|
|
587
|
+
* swapped the shared item object those views reference. Refreshes any tracked interval view that
|
|
588
|
+
* holds a changed id and re-projects (or slot-swaps) the active window — coalesced through the
|
|
589
|
+
* publish throttles when throttling is on.
|
|
590
|
+
*/
|
|
591
|
+
protected reconcileChangedIds(changedIds: ReadonlySet<string>): void;
|
|
592
|
+
protected clearExpiredBoosts(now?: number): void;
|
|
593
|
+
/**
|
|
594
|
+
* Applied by the effectiveComparator to take into consideration item boosts when sorting items.
|
|
595
|
+
*
|
|
596
|
+
* @param a - The first item to compare.
|
|
597
|
+
* @param b - The second item to compare.
|
|
598
|
+
*/
|
|
599
|
+
protected boostComparator: (a: T, b: T) => number;
|
|
600
|
+
/**
|
|
601
|
+
* Increases the item's importance when sorting.
|
|
602
|
+
* Boost affects position inside an item interval (if used), but should not redefine interval boundaries.
|
|
603
|
+
*
|
|
604
|
+
* @param itemId - Id of the item to boost.
|
|
605
|
+
* @param opts - Boost options: `ttlMs` / `until` control expiry and `seq` orders concurrent boosts.
|
|
606
|
+
*/
|
|
607
|
+
boost(itemId: string, opts?: {
|
|
608
|
+
ttlMs?: number;
|
|
609
|
+
until?: number;
|
|
610
|
+
seq?: number;
|
|
611
|
+
}): void;
|
|
612
|
+
getBoost(id: string): {
|
|
613
|
+
until: number;
|
|
614
|
+
seq: number;
|
|
615
|
+
} | undefined;
|
|
616
|
+
removeBoost(id: string): void;
|
|
617
|
+
isBoosted(id: string): boolean;
|
|
618
|
+
generateIntervalId(_page: (T | string)[]): string;
|
|
619
|
+
intervalToItems(interval: Interval | LogicalInterval): T[];
|
|
620
|
+
makeInterval({ page, isHead, isTail }: MakeIntervalParams<T>): Interval;
|
|
621
|
+
protected getCursorFromInterval(interval: Interval): PaginatorCursor;
|
|
622
|
+
isActiveInterval(interval: AnyInterval): boolean;
|
|
623
|
+
/**
|
|
624
|
+
* Whether the currently active (viewed) interval is the anchored head. Used to decide if it is
|
|
625
|
+
* safe to re-seed an already-loaded paginator with a fresh newest page: only when at the head
|
|
626
|
+
* (the newest page overlaps it, so the re-seed reconciles + re-derives cursors in place). When the
|
|
627
|
+
* caller has jumped to an older window (active interval is NOT the head), a first-page re-seed
|
|
628
|
+
* would force-merge the newest page into that window across the gap - so the re-seed is skipped.
|
|
629
|
+
*/
|
|
630
|
+
get isActiveIntervalAtHead(): boolean;
|
|
631
|
+
setActiveInterval(interval: AnyInterval | undefined, opts?: {
|
|
632
|
+
updateState?: boolean;
|
|
633
|
+
}): void;
|
|
634
|
+
protected getIntervalSortBounds(interval: Interval | LogicalInterval): IntervalSortBounds<T> | null;
|
|
635
|
+
/**
|
|
636
|
+
* Returns pagination head/tail edges of an interval.
|
|
637
|
+
*
|
|
638
|
+
* IMPORTANT:
|
|
639
|
+
* - Edges are derived from the *sort bounds* of the interval (min/max under `sortComparator`).
|
|
640
|
+
* - Which bound is treated as the pagination "head" is controlled by `intervalItemIdsAreHeadFirst`.
|
|
641
|
+
* - This is a semantic notion of head/tail (where new items are expected to appear),
|
|
642
|
+
* not necessarily "min/max under sortComparator".
|
|
643
|
+
* New items are always expected to appear at the head of the interval.
|
|
644
|
+
*/
|
|
645
|
+
protected getIntervalPaginationEdges(interval: Interval | LogicalInterval): IntervalPaginationEdges<T> | null;
|
|
646
|
+
protected compareIntervalHeadEdges(a: T, b: T): number;
|
|
647
|
+
protected aIsMoreHeadwardThanB(a: T, b: T): boolean;
|
|
648
|
+
protected aIsMoreTailwardThanB(a: T, b: T): boolean;
|
|
649
|
+
protected getHeadIntervalFromSortedIntervals(intervals: AnyInterval[]): AnyInterval | undefined;
|
|
650
|
+
protected getTailIntervalFromSortedIntervals(intervals: AnyInterval[]): AnyInterval | undefined;
|
|
651
|
+
protected sortIntervals<I extends AnyInterval>(intervals: I[]): I[];
|
|
652
|
+
protected setIntervals(intervals: AnyInterval[]): void;
|
|
653
|
+
protected intervalsStrictlyOverlap(a: AnyInterval, b: AnyInterval): boolean;
|
|
654
|
+
/**
|
|
655
|
+
* Returns true if intervals A and B should be merged.
|
|
656
|
+
*
|
|
657
|
+
* 1) Strict overlap (range overlap in `sortComparator` order):
|
|
658
|
+
* A.min ≤ B.max AND B.min ≤ A.max
|
|
659
|
+
*
|
|
660
|
+
* 2) Forced merge (policy: 'auto' only):
|
|
661
|
+
* If one interval is marked as `isHead`/`isTail`, treat the other as mergeable
|
|
662
|
+
* when it extends beyond that interval's pagination head/tail edge
|
|
663
|
+
* (computed via `getIntervalPaginationEdges` + headward/tailward helpers).
|
|
664
|
+
*
|
|
665
|
+
* In 'strict-overlap-only' policy, only (1) applies.
|
|
666
|
+
*/
|
|
667
|
+
protected intervalsOverlap(a: AnyInterval, b: AnyInterval, policy?: IntervalMergePolicy): boolean;
|
|
668
|
+
/**
|
|
669
|
+
* Whether an item belongs to an anchored interval.
|
|
670
|
+
*/
|
|
671
|
+
protected belongsToInterval(item: T, interval: AnyInterval): boolean;
|
|
672
|
+
protected mergeTwoAnchoredIntervals(preceding: Interval, following: Interval): Interval;
|
|
673
|
+
/**
|
|
674
|
+
* Merges anchored intervals. Returns null if there are no intervals to merge.
|
|
675
|
+
*/
|
|
676
|
+
protected mergeAnchoredIntervals(intervals: Interval[], baseInterval?: Interval): Interval | null;
|
|
677
|
+
protected locateIntervalIndex(interval: Interval): number;
|
|
678
|
+
/**
|
|
679
|
+
* Locate item inside a specific interval using the same logic as locateByItem,
|
|
680
|
+
* but scoped to interval items.
|
|
681
|
+
*/
|
|
682
|
+
protected locateByItemInInterval({ item, interval, }: {
|
|
683
|
+
item: T;
|
|
684
|
+
interval: Interval | LogicalInterval;
|
|
685
|
+
}): ItemLocation | null;
|
|
686
|
+
protected locateIntervalForItem(item: T): AnyInterval | undefined;
|
|
687
|
+
/**
|
|
688
|
+
* The interval whose `itemIds` lists this id, regardless of where the item now sorts.
|
|
689
|
+
*/
|
|
690
|
+
protected findIntervalHoldingItem(item: T): AnyInterval | undefined;
|
|
691
|
+
protected locateByItemInIntervals(item: T): ItemCoordinates['interval'] | undefined;
|
|
692
|
+
/**
|
|
693
|
+
* Locates the current position of the item and the index at which the item should be inserted
|
|
694
|
+
* according to effectiveComparator.
|
|
695
|
+
*
|
|
696
|
+
* @param item - The item to locate within the current state.
|
|
697
|
+
*/
|
|
698
|
+
protected locateItemInState(item: T): ItemLocation | null;
|
|
699
|
+
locateByItem: (item: T) => ItemCoordinates;
|
|
700
|
+
protected removeItemIdFromInterval({ interval, ...itemLocation }: ItemIntervalCoordinates): ItemIntervalCoordinates;
|
|
701
|
+
/**
|
|
702
|
+
* Inserts an item ID into the interval in the correct sorted position.
|
|
703
|
+
* Returns unchanged interval if the correct insertion position could not be determined.
|
|
704
|
+
*/
|
|
705
|
+
protected insertItemIdIntoInterval<I extends Interval | LogicalInterval>(interval: I, item: T): I;
|
|
706
|
+
/**
|
|
707
|
+
* Re-evaluates what the logical (live head / tail) intervals still hold against a freshly ingested
|
|
708
|
+
* page, returning the resulting anchored interval. Live updates park items there before any page
|
|
709
|
+
* exists — a channel archived while the archived list is untouched lands in the live head — and
|
|
710
|
+
* once a page covers such an item, leaving it gives the same id two homes, which is what renders
|
|
711
|
+
* as a duplicated row. The merge in `ingestPage` only folds logical intervals in when its
|
|
712
|
+
* `isHead`/overlap heuristics fire; this pass is unconditional and idempotent.
|
|
713
|
+
*/
|
|
714
|
+
protected reconcileLogicalIntervalsAgainst(anchored: Interval): Interval;
|
|
715
|
+
/**
|
|
716
|
+
* Moves items the loaded window proves are parked on the wrong side: an item sitting in the live
|
|
717
|
+
* head that actually sorts past the tail edge of everything loaded belongs to the live tail (the
|
|
718
|
+
* unloaded region on that side), and vice versa. Leaving it claims the wrong end of the list —
|
|
719
|
+
* the archived channel would render above a page it sorts below.
|
|
720
|
+
*
|
|
721
|
+
* Compared against the outermost anchored interval, not the page just ingested: an item that
|
|
722
|
+
* lands between two loaded pages is not "beyond" either side, it is a gap item, and those stay
|
|
723
|
+
* where they are (`ingestPage` turns them into their own island once the merge reaches the edge).
|
|
724
|
+
*/
|
|
725
|
+
protected moveMisfiledItemsToOppositeSide(logical: LogicalInterval, ingested: Interval): void;
|
|
726
|
+
/**
|
|
727
|
+
* Splits a logical interval by checking each item individually.
|
|
728
|
+
* Items overlapping anchoredInterval are merged into it.
|
|
729
|
+
* Others stay in a retained logical interval.
|
|
730
|
+
*/
|
|
731
|
+
protected mergeItemsFromLogicalInterval(logical: LogicalInterval, anchored: Interval): {
|
|
732
|
+
mergedAnchored: Interval;
|
|
733
|
+
remainingLogical: LogicalInterval | null;
|
|
734
|
+
};
|
|
735
|
+
/**
|
|
736
|
+
* Merges all intervals (anchored + logical head/tail).
|
|
737
|
+
* Returns:
|
|
738
|
+
* - merged anchored interval (or null if none merged)
|
|
739
|
+
* - possibly reduced logical head / tail intervals
|
|
740
|
+
*/
|
|
741
|
+
protected mergeIntervals(intervals: AnyInterval[], baseInterval?: Interval): MergeIntervalsResult;
|
|
742
|
+
/**
|
|
743
|
+
* Ingests the whole page into intervals and returns the resulting anchored interval.
|
|
744
|
+
*/
|
|
745
|
+
ingestPage({ page, policy, isHead, isTail, targetIntervalId, setActive, }: {
|
|
746
|
+
page: T[];
|
|
747
|
+
/**
|
|
748
|
+
* Describes the policy for merging intervals.
|
|
749
|
+
* - 'auto' (default): Merge intervals if they overlap.
|
|
750
|
+
* - 'strict-overlap-only': Merge intervals only if they strictly overlap. Useful for jumping to a specific message.
|
|
751
|
+
* - This is useful for jumping to a specific message.
|
|
752
|
+
*/
|
|
753
|
+
policy?: IntervalMergePolicy;
|
|
754
|
+
isHead?: boolean;
|
|
755
|
+
isTail?: boolean;
|
|
756
|
+
targetIntervalId?: string;
|
|
757
|
+
setActive?: boolean;
|
|
758
|
+
}): Interval | null;
|
|
759
|
+
/**
|
|
760
|
+
* Ingests a single item on live update:
|
|
761
|
+
* - update the ItemIndex
|
|
762
|
+
* - find an anchored interval whose sort bounds contain the item
|
|
763
|
+
* - insert the item into that interval using locate+plateau logic
|
|
764
|
+
* - if this is the active interval, re-emit state.items from interval
|
|
765
|
+
*/
|
|
766
|
+
ingestItem(ingestedItem: T): boolean;
|
|
767
|
+
protected removeItemAtCoordinates(coords: ItemCoordinates): ItemCoordinates;
|
|
768
|
+
/**
|
|
769
|
+
* Meaning of location values
|
|
770
|
+
* - currentIndex === -1 could not be found
|
|
771
|
+
* - insertionIndex === -1 insertion index was no intended to be determined
|
|
772
|
+
*
|
|
773
|
+
* If we are removing the last item from the currently active interval, we do not search for a new active interval.
|
|
774
|
+
* If the number of items approach 0 in an active interval, we expect from the UI to load new pages to populate
|
|
775
|
+
* the active interval.
|
|
776
|
+
*/
|
|
777
|
+
removeItem({ id, item: inputItem }: {
|
|
778
|
+
id?: string;
|
|
779
|
+
item?: T;
|
|
780
|
+
}): ItemCoordinates;
|
|
781
|
+
/** Sets the items in the state, ingesting them so the active interval is updated. */
|
|
782
|
+
setItems({ valueOrFactory, cursor, isFirstPage, isLastPage, }: SetPaginatorItemsParams<T>): void;
|
|
783
|
+
setDebounceOptions: ({ debounceMs }: PaginatorDebounceOptions) => void;
|
|
784
|
+
protected shouldResetStateBeforeQuery(prevQueryShape: unknown | undefined, nextQueryShape: unknown | undefined): boolean;
|
|
785
|
+
protected canExecuteQuery: ({ direction, reset, }: {
|
|
786
|
+
direction?: PaginationDirection;
|
|
787
|
+
} & Pick<PaginationQueryParams<Q>, "reset">) => boolean;
|
|
788
|
+
isFirstPageQuery: (params: {
|
|
789
|
+
queryShape?: unknown;
|
|
790
|
+
} & Pick<PaginationQueryParams<Q>, "reset">) => boolean;
|
|
791
|
+
protected getStateBeforeFirstQuery(): PaginatorState<T>;
|
|
792
|
+
isJumpQueryShape(_queryShape: Q): boolean;
|
|
793
|
+
protected getStateAfterQuery(stateUpdate: Partial<PaginatorState<T>>, _isFirstPage: boolean): PaginatorState<T>;
|
|
794
|
+
preloadFirstPageFromOfflineDb: (_params: PaginationQueryParams<Q>) => Promise<T[] | undefined> | T[] | undefined;
|
|
795
|
+
populateOfflineDbAfterQuery: (_params: {
|
|
796
|
+
items: T[] | undefined;
|
|
797
|
+
queryShape: Q | undefined;
|
|
798
|
+
}) => Promise<T[] | undefined> | T[] | undefined;
|
|
799
|
+
protected runQueryRetryable(params?: PaginationQueryParams<Q>): Promise<PaginationQueryReturnValue<T> | null>;
|
|
800
|
+
/**
|
|
801
|
+
* Falsy return value means query was not successful.
|
|
802
|
+
*
|
|
803
|
+
* @param params - Query parameters.
|
|
804
|
+
* @param params.direction - Direction to paginate in (headward or tailward).
|
|
805
|
+
* @param params.keepPreviousItems - Keep already-loaded items instead of clearing them on a first-page query.
|
|
806
|
+
* @param params.queryShape - Explicit query shape overriding the one derived from current state.
|
|
807
|
+
* @param params.reset - Whether to reset the loaded state before querying.
|
|
808
|
+
* @param params.retryCount - Number of remaining retry attempts on failure.
|
|
809
|
+
* @param params.silent - Suppress loading/state updates for this query.
|
|
810
|
+
* @param params.updateState - Whether to write the query results back to state.
|
|
811
|
+
*/
|
|
812
|
+
executeQuery({ direction, keepPreviousItems, queryShape: forcedQueryShape, reset, retryCount, silent, updateState, }?: PaginationQueryParams<Q>): Promise<ExecuteQueryReturnValue<T> | void>;
|
|
813
|
+
postQueryReconcile({ direction, isFirstPage, keepPreviousItems, queryShape, requestedPageSize, results, updateState, }: PostQueryReconcileParams<T, Q>): ExecuteQueryReturnValue<T>;
|
|
814
|
+
cancelScheduledQuery(): void;
|
|
815
|
+
resetState(): void;
|
|
816
|
+
/**
|
|
817
|
+
* Releases this paginator's hold on its item content. With a shared, refcounted item index this
|
|
818
|
+
* unlinks every member id from the backing store, so the store no longer strong-references this
|
|
819
|
+
* paginator through its subscriber registry — otherwise a discarded owner stays pinned, keeps
|
|
820
|
+
* receiving change notifications, and its items never garbage-collect. Call on teardown of the
|
|
821
|
+
* owner: a discard, not a reset (the owner is not reused; a re-appearing id gets a fresh instance;
|
|
822
|
+
* leftover interval/state caches die with the paginator when it is dropped). Also cancels any
|
|
823
|
+
* pending throttled window/view publish, so nothing emits after teardown.
|
|
824
|
+
*/
|
|
825
|
+
dispose(): void;
|
|
826
|
+
toTail: (params?: Omit<PaginationQueryParams<Q>, "direction" | "queryShape">) => Promise<void | ExecuteQueryReturnValue<T>>;
|
|
827
|
+
toHead: (params?: Omit<PaginationQueryParams<Q>, "direction" | "queryShape">) => Promise<void | ExecuteQueryReturnValue<T>>;
|
|
828
|
+
/**
|
|
829
|
+
* @deprecated Use `toTail` instead.
|
|
830
|
+
*/
|
|
831
|
+
next: (params?: Omit<PaginationQueryParams<Q>, "direction" | "queryShape">) => Promise<void | ExecuteQueryReturnValue<T>>;
|
|
832
|
+
/**
|
|
833
|
+
* @deprecated Use `toHead` instead.
|
|
834
|
+
*/
|
|
835
|
+
prev: (params?: Omit<PaginationQueryParams<Q>, "direction" | "queryShape">) => Promise<void | ExecuteQueryReturnValue<T>>;
|
|
836
|
+
toTailDebounced: (params?: Omit<PaginationQueryParams<Q>, "direction" | "queryShape">) => void;
|
|
837
|
+
toHeadDebounced: (params?: Omit<PaginationQueryParams<Q>, "direction" | "queryShape">) => void;
|
|
838
|
+
/**
|
|
839
|
+
* @deprecated Use `toTailDebounced` instead.
|
|
840
|
+
*/
|
|
841
|
+
nextDebounced: (params?: Omit<PaginationQueryParams<Q>, "direction" | "queryShape">) => void;
|
|
842
|
+
/**
|
|
843
|
+
* @deprecated Use `toHeadDebounced` instead.
|
|
844
|
+
*/
|
|
845
|
+
prevDebounced: (params?: Omit<PaginationQueryParams<Q>, "direction" | "queryShape">) => void;
|
|
846
|
+
reload: () => Promise<void>;
|
|
847
|
+
}
|
|
848
|
+
export {};
|