@convokitapp/vue-ui 0.4.1 → 0.5.0

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/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { Conversation as Conversation$1, MessageListOptions, Message, SendMessageInput, RealtimeConnectionHandlers, RealtimeSubscription, MessageEvent, MessageDeletedEvent, ReadEvent, TypingEvent, MessageMedia, ConvoKitClient } from '@convokitapp/sdk';
1
+ import { Conversation as Conversation$1, MessageListOptions, Message, SendMessageInput, MarkConversationReadOptions, RealtimeConnectionHandlers, RealtimeSubscription, MessageEvent, MessageDeletedEvent, ReadEvent, TypingEvent, ReadPosition, MessageMedia, ConvoKitClient } from '@convokitapp/sdk';
2
2
  import * as vue from 'vue';
3
3
  import { CSSProperties, HTMLAttributes, Ref, VNodeChild, PropType, MaybeRefOrGetter, TextareaHTMLAttributes } from 'vue';
4
4
 
@@ -17,7 +17,11 @@ interface ConvoKitUiClient {
17
17
  /** Complete authorized message, including related media absent from raw row events. */
18
18
  getMessage(id: string): Promise<Message>;
19
19
  sendMessage(input: SendMessageInput): Promise<Message>;
20
- markConversationRead(conversationId: string): Promise<void>;
20
+ /** Acknowledge through `options.throughMessageId` (the newest rendered row). Custom adapters must forward it
21
+ * and reject a missing target with `code: 'MESSAGE_NOT_FOUND'` (or a 404 without a code); the UI never sends a
22
+ * request without a target. Membership failures keep their error code, if any, so they surface as errors.
23
+ */
24
+ markConversationRead(conversationId: string, options?: MarkConversationReadOptions): Promise<void>;
21
25
  sendTyping(input: {
22
26
  conversationId: string;
23
27
  isTyping: boolean;
@@ -58,7 +62,10 @@ interface ConversationState {
58
62
  conversation: Readonly<Ref<Conversation$1 | null>>;
59
63
  messages: Readonly<Ref<Message[]>>;
60
64
  typingUserIds: Readonly<Ref<ReadonlySet<string>>>;
65
+ /** Last acknowledgement time per user; kept for custom renderers. */
61
66
  readAtByUserId: Readonly<Ref<ReadonlyMap<string, Date>>>;
67
+ /** Monotonic read-through position per user; `readerIdsFor` prefers it over `readAtByUserId`. */
68
+ readPositionByUserId: Readonly<Ref<ReadonlyMap<string, ReadPosition>>>;
62
69
  isInitialLoading: Readonly<Ref<boolean>>;
63
70
  isLoadingOlder: Readonly<Ref<boolean>>;
64
71
  isReconciling: Readonly<Ref<boolean>>;
@@ -171,7 +178,10 @@ interface ConversationController extends ConversationState {
171
178
  text?: string;
172
179
  media?: MessageMedia[];
173
180
  }): Promise<Message | null>;
181
+ /** Acknowledge through the newest rendered message now; no request is sent while nothing is rendered. */
174
182
  markRead(): Promise<void>;
183
+ /** Automatic acknowledgements pause while hidden and resume when the view becomes visible again. */
184
+ setVisible(visible: boolean): void;
175
185
  updateTyping(isTyping: boolean): Promise<void>;
176
186
  dispose(): Promise<void>;
177
187
  }
@@ -185,6 +195,7 @@ interface ConversationViewProps extends ConvoKitAppearanceProps {
185
195
  onSendMessage: (text: string) => boolean | void | Promise<boolean | void>;
186
196
  typingUserIds?: ReadonlySet<string>;
187
197
  readAtByUserId?: ReadonlyMap<string, Date>;
198
+ readPositionByUserId?: ReadonlyMap<string, ReadPosition>;
188
199
  readersResolver?: (message: Message) => ReadonlySet<string>;
189
200
  onBack?: () => void;
190
201
  onRefresh?: () => void | Promise<void>;
@@ -239,6 +250,10 @@ declare const ConversationView: vue.DefineComponent<vue.ExtractPropTypes<{
239
250
  readonly type: PropType<ReadonlyMap<string, Date>>;
240
251
  readonly default: () => Map<any, any>;
241
252
  };
253
+ readonly readPositionByUserId: {
254
+ readonly type: PropType<ReadonlyMap<string, ReadPosition>>;
255
+ readonly default: () => Map<any, any>;
256
+ };
242
257
  readonly readersResolver: {
243
258
  readonly type: PropType<(message: Message) => ReadonlySet<string>>;
244
259
  readonly default: undefined;
@@ -382,6 +397,10 @@ declare const ConversationView: vue.DefineComponent<vue.ExtractPropTypes<{
382
397
  readonly type: PropType<ReadonlyMap<string, Date>>;
383
398
  readonly default: () => Map<any, any>;
384
399
  };
400
+ readonly readPositionByUserId: {
401
+ readonly type: PropType<ReadonlyMap<string, ReadPosition>>;
402
+ readonly default: () => Map<any, any>;
403
+ };
385
404
  readonly readersResolver: {
386
405
  readonly type: PropType<(message: Message) => ReadonlySet<string>>;
387
406
  readonly default: undefined;
@@ -510,6 +529,7 @@ declare const ConversationView: vue.DefineComponent<vue.ExtractPropTypes<{
510
529
  }>, {
511
530
  readonly typingUserIds: ReadonlySet<string>;
512
531
  readonly readAtByUserId: ReadonlyMap<string, Date>;
532
+ readonly readPositionByUserId: ReadonlyMap<string, ReadPosition>;
513
533
  readonly isInitialLoading: boolean;
514
534
  readonly isLoadingOlder: boolean;
515
535
  readonly isSending: boolean;
@@ -538,7 +558,7 @@ declare const ConversationView: vue.DefineComponent<vue.ExtractPropTypes<{
538
558
  readonly defaultDraft: string;
539
559
  readonly onDraftChange: (value: string) => void;
540
560
  }, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
541
- interface ConversationProps extends Omit<ConversationViewProps, 'conversation' | 'messages' | 'currentUserId' | 'onSendMessage' | 'typingUserIds' | 'readAtByUserId' | 'onRefresh' | 'onLoadOlder' | 'onTypingChange' | 'isInitialLoading' | 'isLoadingOlder' | 'isSending' | 'hasOlderMessages' | 'error'>, Omit<UseConversationOptions, 'client' | 'conversationId'> {
561
+ interface ConversationProps extends Omit<ConversationViewProps, 'conversation' | 'messages' | 'currentUserId' | 'onSendMessage' | 'typingUserIds' | 'readAtByUserId' | 'readPositionByUserId' | 'onRefresh' | 'onLoadOlder' | 'onTypingChange' | 'isInitialLoading' | 'isLoadingOlder' | 'isSending' | 'hasOlderMessages' | 'error'>, Omit<UseConversationOptions, 'client' | 'conversationId'> {
542
562
  client: ConvoKitUiClient;
543
563
  conversationId: string;
544
564
  onControllerChange?: (controller: ConversationController) => void;
@@ -601,6 +621,10 @@ declare const Conversation: vue.DefineComponent<vue.ExtractPropTypes<{
601
621
  readonly type: PropType<ReadonlyMap<string, Date>>;
602
622
  readonly default: () => Map<any, any>;
603
623
  };
624
+ readPositionByUserId: {
625
+ readonly type: PropType<ReadonlyMap<string, ReadPosition>>;
626
+ readonly default: () => Map<any, any>;
627
+ };
604
628
  readersResolver: {
605
629
  readonly type: PropType<(message: Message) => ReadonlySet<string>>;
606
630
  readonly default: undefined;
@@ -776,6 +800,10 @@ declare const Conversation: vue.DefineComponent<vue.ExtractPropTypes<{
776
800
  readonly type: PropType<ReadonlyMap<string, Date>>;
777
801
  readonly default: () => Map<any, any>;
778
802
  };
803
+ readPositionByUserId: {
804
+ readonly type: PropType<ReadonlyMap<string, ReadPosition>>;
805
+ readonly default: () => Map<any, any>;
806
+ };
779
807
  readersResolver: {
780
808
  readonly type: PropType<(message: Message) => ReadonlySet<string>>;
781
809
  readonly default: undefined;
@@ -907,6 +935,7 @@ declare const Conversation: vue.DefineComponent<vue.ExtractPropTypes<{
907
935
  conversation: Conversation$1;
908
936
  typingUserIds: ReadonlySet<string>;
909
937
  readAtByUserId: ReadonlyMap<string, Date>;
938
+ readPositionByUserId: ReadonlyMap<string, ReadPosition>;
910
939
  isInitialLoading: boolean;
911
940
  isLoadingOlder: boolean;
912
941
  isSending: boolean;
@@ -1349,7 +1378,10 @@ interface MessageListViewProps extends ConvoKitAppearanceProps {
1349
1378
  conversation: Conversation$1;
1350
1379
  messages: readonly Message[];
1351
1380
  currentUserId: string;
1381
+ /** Acknowledgement times; the fallback for users without a read position. */
1352
1382
  readAtByUserId?: ReadonlyMap<string, Date>;
1383
+ /** Read-through positions; a user's position decides their receipts whenever one is present. */
1384
+ readPositionByUserId?: ReadonlyMap<string, ReadPosition>;
1353
1385
  readersResolver?: (message: Message) => ReadonlySet<string>;
1354
1386
  onLoadOlder?: () => void | Promise<void>;
1355
1387
  hasOlderMessages?: boolean;
@@ -1384,6 +1416,10 @@ declare const MessageListView: vue.DefineComponent<vue.ExtractPropTypes<{
1384
1416
  type: PropType<ReadonlyMap<string, Date>>;
1385
1417
  default: () => Map<any, any>;
1386
1418
  };
1419
+ readPositionByUserId: {
1420
+ type: PropType<ReadonlyMap<string, ReadPosition>>;
1421
+ default: () => Map<any, any>;
1422
+ };
1387
1423
  readersResolver: {
1388
1424
  type: PropType<(message: Message) => ReadonlySet<string>>;
1389
1425
  default: undefined;
@@ -1467,6 +1503,10 @@ declare const MessageListView: vue.DefineComponent<vue.ExtractPropTypes<{
1467
1503
  type: PropType<ReadonlyMap<string, Date>>;
1468
1504
  default: () => Map<any, any>;
1469
1505
  };
1506
+ readPositionByUserId: {
1507
+ type: PropType<ReadonlyMap<string, ReadPosition>>;
1508
+ default: () => Map<any, any>;
1509
+ };
1470
1510
  readersResolver: {
1471
1511
  type: PropType<(message: Message) => ReadonlySet<string>>;
1472
1512
  default: undefined;
@@ -1537,6 +1577,7 @@ declare const MessageListView: vue.DefineComponent<vue.ExtractPropTypes<{
1537
1577
  }>, {
1538
1578
  reverse: boolean;
1539
1579
  readAtByUserId: ReadonlyMap<string, Date>;
1580
+ readPositionByUserId: ReadonlyMap<string, ReadPosition>;
1540
1581
  isLoadingOlder: boolean;
1541
1582
  hasOlderMessages: boolean;
1542
1583
  readersResolver: (message: Message) => ReadonlySet<string>;
@@ -1552,7 +1593,7 @@ declare const MessageListView: vue.DefineComponent<vue.ExtractPropTypes<{
1552
1593
  density: ConvoKitUiDensity;
1553
1594
  unstyled: boolean;
1554
1595
  }, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
1555
- declare function defaultReadersResolver(readAtByUserId: ReadonlyMap<string, Date>): (message: Message) => ReadonlySet<string>;
1596
+ declare function defaultReadersResolver(readAtByUserId: ReadonlyMap<string, Date>, readPositionByUserId?: ReadonlyMap<string, ReadPosition>): (message: Message) => ReadonlySet<string>;
1556
1597
 
1557
1598
  interface ConvoKitTheme {
1558
1599
  background: string;
@@ -1611,7 +1652,11 @@ declare function matchesConversation(conversation: Conversation$1, filter: Conve
1611
1652
  declare function applyConversationFilter(conversations: readonly Conversation$1[], filter: ConversationFilter): Conversation$1[];
1612
1653
  declare function mergeConversations(current: readonly Conversation$1[], incoming: readonly Conversation$1[]): Conversation$1[];
1613
1654
  declare function mergeMessages(current: readonly Message[], incoming: readonly Message[]): Message[];
1614
- declare function readerIdsFor(message: Message, readAtByUserId: ReadonlyMap<string, Date>): ReadonlySet<string>;
1655
+ /** Readers of a message under the unified rule: a user's read position (createdAt, id) wins when present,
1656
+ * otherwise the acknowledgement time is compared with createdAt (legacy participants, empty-room acknowledgements).
1657
+ * The sender and pending rows never have readers.
1658
+ */
1659
+ declare function readerIdsFor(message: Message, readAtByUserId: ReadonlyMap<string, Date>, readPositionByUserId?: ReadonlyMap<string, ReadPosition>): ReadonlySet<string>;
1615
1660
  declare function formatFileSize(size: number | undefined): string | null;
1616
1661
 
1617
1662
  export { type BaseViewProps, type ComposerSlotProps, Conversation, type ConversationController, type ConversationFilter, type ConversationItemSlotProps, ConversationList, type ConversationListController, type ConversationListProps, type ConversationListState, ConversationListView, type ConversationListViewProps, type ConversationPageLoader, type ConversationPageRequest, type ConversationProps, type ConversationState, ConversationView, type ConversationViewProps, type ConvoKitAppearanceProps, ConvoKitAvatar, type ConvoKitTheme, ConvoKitThemeProvider, type ConvoKitUiClient, type ConvoKitUiDensity, type ConvoKitUiPart, type ErrorSlot, type ErrorSlotProps, type MediaSlotProps, MessageListView, type MessageListViewProps, type MessageSlotProps, type ReadReceiptSlotProps, type ScrollOptions, type StateSlot, type TypingSlotProps, type UseConversationListOptions, type UseConversationOptions, applyConversationFilter, createConvoKitUiClient, defaultConvoKitTheme, defaultReadersResolver, formatFileSize, isConvoKitPendingMessage, matchesConversation, mergeConversations, mergeMessages, readerIdsFor, useConversation, useConversationList, useConvoKitTheme };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Conversation as Conversation$1, MessageListOptions, Message, SendMessageInput, RealtimeConnectionHandlers, RealtimeSubscription, MessageEvent, MessageDeletedEvent, ReadEvent, TypingEvent, MessageMedia, ConvoKitClient } from '@convokitapp/sdk';
1
+ import { Conversation as Conversation$1, MessageListOptions, Message, SendMessageInput, MarkConversationReadOptions, RealtimeConnectionHandlers, RealtimeSubscription, MessageEvent, MessageDeletedEvent, ReadEvent, TypingEvent, ReadPosition, MessageMedia, ConvoKitClient } from '@convokitapp/sdk';
2
2
  import * as vue from 'vue';
3
3
  import { CSSProperties, HTMLAttributes, Ref, VNodeChild, PropType, MaybeRefOrGetter, TextareaHTMLAttributes } from 'vue';
4
4
 
@@ -17,7 +17,11 @@ interface ConvoKitUiClient {
17
17
  /** Complete authorized message, including related media absent from raw row events. */
18
18
  getMessage(id: string): Promise<Message>;
19
19
  sendMessage(input: SendMessageInput): Promise<Message>;
20
- markConversationRead(conversationId: string): Promise<void>;
20
+ /** Acknowledge through `options.throughMessageId` (the newest rendered row). Custom adapters must forward it
21
+ * and reject a missing target with `code: 'MESSAGE_NOT_FOUND'` (or a 404 without a code); the UI never sends a
22
+ * request without a target. Membership failures keep their error code, if any, so they surface as errors.
23
+ */
24
+ markConversationRead(conversationId: string, options?: MarkConversationReadOptions): Promise<void>;
21
25
  sendTyping(input: {
22
26
  conversationId: string;
23
27
  isTyping: boolean;
@@ -58,7 +62,10 @@ interface ConversationState {
58
62
  conversation: Readonly<Ref<Conversation$1 | null>>;
59
63
  messages: Readonly<Ref<Message[]>>;
60
64
  typingUserIds: Readonly<Ref<ReadonlySet<string>>>;
65
+ /** Last acknowledgement time per user; kept for custom renderers. */
61
66
  readAtByUserId: Readonly<Ref<ReadonlyMap<string, Date>>>;
67
+ /** Monotonic read-through position per user; `readerIdsFor` prefers it over `readAtByUserId`. */
68
+ readPositionByUserId: Readonly<Ref<ReadonlyMap<string, ReadPosition>>>;
62
69
  isInitialLoading: Readonly<Ref<boolean>>;
63
70
  isLoadingOlder: Readonly<Ref<boolean>>;
64
71
  isReconciling: Readonly<Ref<boolean>>;
@@ -171,7 +178,10 @@ interface ConversationController extends ConversationState {
171
178
  text?: string;
172
179
  media?: MessageMedia[];
173
180
  }): Promise<Message | null>;
181
+ /** Acknowledge through the newest rendered message now; no request is sent while nothing is rendered. */
174
182
  markRead(): Promise<void>;
183
+ /** Automatic acknowledgements pause while hidden and resume when the view becomes visible again. */
184
+ setVisible(visible: boolean): void;
175
185
  updateTyping(isTyping: boolean): Promise<void>;
176
186
  dispose(): Promise<void>;
177
187
  }
@@ -185,6 +195,7 @@ interface ConversationViewProps extends ConvoKitAppearanceProps {
185
195
  onSendMessage: (text: string) => boolean | void | Promise<boolean | void>;
186
196
  typingUserIds?: ReadonlySet<string>;
187
197
  readAtByUserId?: ReadonlyMap<string, Date>;
198
+ readPositionByUserId?: ReadonlyMap<string, ReadPosition>;
188
199
  readersResolver?: (message: Message) => ReadonlySet<string>;
189
200
  onBack?: () => void;
190
201
  onRefresh?: () => void | Promise<void>;
@@ -239,6 +250,10 @@ declare const ConversationView: vue.DefineComponent<vue.ExtractPropTypes<{
239
250
  readonly type: PropType<ReadonlyMap<string, Date>>;
240
251
  readonly default: () => Map<any, any>;
241
252
  };
253
+ readonly readPositionByUserId: {
254
+ readonly type: PropType<ReadonlyMap<string, ReadPosition>>;
255
+ readonly default: () => Map<any, any>;
256
+ };
242
257
  readonly readersResolver: {
243
258
  readonly type: PropType<(message: Message) => ReadonlySet<string>>;
244
259
  readonly default: undefined;
@@ -382,6 +397,10 @@ declare const ConversationView: vue.DefineComponent<vue.ExtractPropTypes<{
382
397
  readonly type: PropType<ReadonlyMap<string, Date>>;
383
398
  readonly default: () => Map<any, any>;
384
399
  };
400
+ readonly readPositionByUserId: {
401
+ readonly type: PropType<ReadonlyMap<string, ReadPosition>>;
402
+ readonly default: () => Map<any, any>;
403
+ };
385
404
  readonly readersResolver: {
386
405
  readonly type: PropType<(message: Message) => ReadonlySet<string>>;
387
406
  readonly default: undefined;
@@ -510,6 +529,7 @@ declare const ConversationView: vue.DefineComponent<vue.ExtractPropTypes<{
510
529
  }>, {
511
530
  readonly typingUserIds: ReadonlySet<string>;
512
531
  readonly readAtByUserId: ReadonlyMap<string, Date>;
532
+ readonly readPositionByUserId: ReadonlyMap<string, ReadPosition>;
513
533
  readonly isInitialLoading: boolean;
514
534
  readonly isLoadingOlder: boolean;
515
535
  readonly isSending: boolean;
@@ -538,7 +558,7 @@ declare const ConversationView: vue.DefineComponent<vue.ExtractPropTypes<{
538
558
  readonly defaultDraft: string;
539
559
  readonly onDraftChange: (value: string) => void;
540
560
  }, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
541
- interface ConversationProps extends Omit<ConversationViewProps, 'conversation' | 'messages' | 'currentUserId' | 'onSendMessage' | 'typingUserIds' | 'readAtByUserId' | 'onRefresh' | 'onLoadOlder' | 'onTypingChange' | 'isInitialLoading' | 'isLoadingOlder' | 'isSending' | 'hasOlderMessages' | 'error'>, Omit<UseConversationOptions, 'client' | 'conversationId'> {
561
+ interface ConversationProps extends Omit<ConversationViewProps, 'conversation' | 'messages' | 'currentUserId' | 'onSendMessage' | 'typingUserIds' | 'readAtByUserId' | 'readPositionByUserId' | 'onRefresh' | 'onLoadOlder' | 'onTypingChange' | 'isInitialLoading' | 'isLoadingOlder' | 'isSending' | 'hasOlderMessages' | 'error'>, Omit<UseConversationOptions, 'client' | 'conversationId'> {
542
562
  client: ConvoKitUiClient;
543
563
  conversationId: string;
544
564
  onControllerChange?: (controller: ConversationController) => void;
@@ -601,6 +621,10 @@ declare const Conversation: vue.DefineComponent<vue.ExtractPropTypes<{
601
621
  readonly type: PropType<ReadonlyMap<string, Date>>;
602
622
  readonly default: () => Map<any, any>;
603
623
  };
624
+ readPositionByUserId: {
625
+ readonly type: PropType<ReadonlyMap<string, ReadPosition>>;
626
+ readonly default: () => Map<any, any>;
627
+ };
604
628
  readersResolver: {
605
629
  readonly type: PropType<(message: Message) => ReadonlySet<string>>;
606
630
  readonly default: undefined;
@@ -776,6 +800,10 @@ declare const Conversation: vue.DefineComponent<vue.ExtractPropTypes<{
776
800
  readonly type: PropType<ReadonlyMap<string, Date>>;
777
801
  readonly default: () => Map<any, any>;
778
802
  };
803
+ readPositionByUserId: {
804
+ readonly type: PropType<ReadonlyMap<string, ReadPosition>>;
805
+ readonly default: () => Map<any, any>;
806
+ };
779
807
  readersResolver: {
780
808
  readonly type: PropType<(message: Message) => ReadonlySet<string>>;
781
809
  readonly default: undefined;
@@ -907,6 +935,7 @@ declare const Conversation: vue.DefineComponent<vue.ExtractPropTypes<{
907
935
  conversation: Conversation$1;
908
936
  typingUserIds: ReadonlySet<string>;
909
937
  readAtByUserId: ReadonlyMap<string, Date>;
938
+ readPositionByUserId: ReadonlyMap<string, ReadPosition>;
910
939
  isInitialLoading: boolean;
911
940
  isLoadingOlder: boolean;
912
941
  isSending: boolean;
@@ -1349,7 +1378,10 @@ interface MessageListViewProps extends ConvoKitAppearanceProps {
1349
1378
  conversation: Conversation$1;
1350
1379
  messages: readonly Message[];
1351
1380
  currentUserId: string;
1381
+ /** Acknowledgement times; the fallback for users without a read position. */
1352
1382
  readAtByUserId?: ReadonlyMap<string, Date>;
1383
+ /** Read-through positions; a user's position decides their receipts whenever one is present. */
1384
+ readPositionByUserId?: ReadonlyMap<string, ReadPosition>;
1353
1385
  readersResolver?: (message: Message) => ReadonlySet<string>;
1354
1386
  onLoadOlder?: () => void | Promise<void>;
1355
1387
  hasOlderMessages?: boolean;
@@ -1384,6 +1416,10 @@ declare const MessageListView: vue.DefineComponent<vue.ExtractPropTypes<{
1384
1416
  type: PropType<ReadonlyMap<string, Date>>;
1385
1417
  default: () => Map<any, any>;
1386
1418
  };
1419
+ readPositionByUserId: {
1420
+ type: PropType<ReadonlyMap<string, ReadPosition>>;
1421
+ default: () => Map<any, any>;
1422
+ };
1387
1423
  readersResolver: {
1388
1424
  type: PropType<(message: Message) => ReadonlySet<string>>;
1389
1425
  default: undefined;
@@ -1467,6 +1503,10 @@ declare const MessageListView: vue.DefineComponent<vue.ExtractPropTypes<{
1467
1503
  type: PropType<ReadonlyMap<string, Date>>;
1468
1504
  default: () => Map<any, any>;
1469
1505
  };
1506
+ readPositionByUserId: {
1507
+ type: PropType<ReadonlyMap<string, ReadPosition>>;
1508
+ default: () => Map<any, any>;
1509
+ };
1470
1510
  readersResolver: {
1471
1511
  type: PropType<(message: Message) => ReadonlySet<string>>;
1472
1512
  default: undefined;
@@ -1537,6 +1577,7 @@ declare const MessageListView: vue.DefineComponent<vue.ExtractPropTypes<{
1537
1577
  }>, {
1538
1578
  reverse: boolean;
1539
1579
  readAtByUserId: ReadonlyMap<string, Date>;
1580
+ readPositionByUserId: ReadonlyMap<string, ReadPosition>;
1540
1581
  isLoadingOlder: boolean;
1541
1582
  hasOlderMessages: boolean;
1542
1583
  readersResolver: (message: Message) => ReadonlySet<string>;
@@ -1552,7 +1593,7 @@ declare const MessageListView: vue.DefineComponent<vue.ExtractPropTypes<{
1552
1593
  density: ConvoKitUiDensity;
1553
1594
  unstyled: boolean;
1554
1595
  }, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
1555
- declare function defaultReadersResolver(readAtByUserId: ReadonlyMap<string, Date>): (message: Message) => ReadonlySet<string>;
1596
+ declare function defaultReadersResolver(readAtByUserId: ReadonlyMap<string, Date>, readPositionByUserId?: ReadonlyMap<string, ReadPosition>): (message: Message) => ReadonlySet<string>;
1556
1597
 
1557
1598
  interface ConvoKitTheme {
1558
1599
  background: string;
@@ -1611,7 +1652,11 @@ declare function matchesConversation(conversation: Conversation$1, filter: Conve
1611
1652
  declare function applyConversationFilter(conversations: readonly Conversation$1[], filter: ConversationFilter): Conversation$1[];
1612
1653
  declare function mergeConversations(current: readonly Conversation$1[], incoming: readonly Conversation$1[]): Conversation$1[];
1613
1654
  declare function mergeMessages(current: readonly Message[], incoming: readonly Message[]): Message[];
1614
- declare function readerIdsFor(message: Message, readAtByUserId: ReadonlyMap<string, Date>): ReadonlySet<string>;
1655
+ /** Readers of a message under the unified rule: a user's read position (createdAt, id) wins when present,
1656
+ * otherwise the acknowledgement time is compared with createdAt (legacy participants, empty-room acknowledgements).
1657
+ * The sender and pending rows never have readers.
1658
+ */
1659
+ declare function readerIdsFor(message: Message, readAtByUserId: ReadonlyMap<string, Date>, readPositionByUserId?: ReadonlyMap<string, ReadPosition>): ReadonlySet<string>;
1615
1660
  declare function formatFileSize(size: number | undefined): string | null;
1616
1661
 
1617
1662
  export { type BaseViewProps, type ComposerSlotProps, Conversation, type ConversationController, type ConversationFilter, type ConversationItemSlotProps, ConversationList, type ConversationListController, type ConversationListProps, type ConversationListState, ConversationListView, type ConversationListViewProps, type ConversationPageLoader, type ConversationPageRequest, type ConversationProps, type ConversationState, ConversationView, type ConversationViewProps, type ConvoKitAppearanceProps, ConvoKitAvatar, type ConvoKitTheme, ConvoKitThemeProvider, type ConvoKitUiClient, type ConvoKitUiDensity, type ConvoKitUiPart, type ErrorSlot, type ErrorSlotProps, type MediaSlotProps, MessageListView, type MessageListViewProps, type MessageSlotProps, type ReadReceiptSlotProps, type ScrollOptions, type StateSlot, type TypingSlotProps, type UseConversationListOptions, type UseConversationOptions, applyConversationFilter, createConvoKitUiClient, defaultConvoKitTheme, defaultReadersResolver, formatFileSize, isConvoKitPendingMessage, matchesConversation, mergeConversations, mergeMessages, readerIdsFor, useConversation, useConversationList, useConvoKitTheme };