@palbase/web 1.1.0 → 1.2.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.
@@ -749,6 +749,13 @@ interface ChatMessage {
749
749
  readonly clientMsgId: string;
750
750
  /** Resolved reply context, or null if this is not a reply. */
751
751
  readonly replyTo: ResolvedReply | null;
752
+ /**
753
+ * Display-only reaction tally: `emoji → sorted reactor userIds[]`. Defaults to
754
+ * `{}` (no reactions). Recomputed by the Chat from its authoritative
755
+ * `ReactionFold` as reaction events fold onto this message. Reactions are never
756
+ * a visible message of their own — they only mutate the target's tally.
757
+ */
758
+ readonly reactions: Record<string, string[]>;
752
759
  }
753
760
  /** The receipt from a send — the server's monotonic sequence + accepted epoch. */
754
761
  interface SentReceipt {
@@ -789,6 +796,11 @@ interface ReplyRef {
789
796
  client_msg_id: string;
790
797
  preview?: QuotePreview;
791
798
  }
799
+ interface ReactionPayload {
800
+ targetClientMsgId: string;
801
+ emoji: string;
802
+ op: 'add' | 'remove';
803
+ }
792
804
 
793
805
  /** A decoded incoming message handed to chat listeners. */
794
806
  interface IncomingMessage {
@@ -803,6 +815,15 @@ interface IncomingMessage {
803
815
  clientMsgId: string;
804
816
  /** The decoded reply reference, if present in the envelope. */
805
817
  replyRef: ReplyRef | null;
818
+ /**
819
+ * The decoded envelope discriminator (`'text'`/`'reaction'`/`'media'`/…).
820
+ * Defaults to `'text'` at every existing call site — only the reaction branch
821
+ * sets `'reaction'`, so the Chat can route a reaction into its fold instead of
822
+ * appending a visible bubble. Optional for forward-compat with old emitters.
823
+ */
824
+ envelopeType?: string;
825
+ /** The decoded reaction payload, present only when `envelopeType === 'reaction'`. */
826
+ reaction?: ReactionPayload | null;
806
827
  }
807
828
 
808
829
  /** The intended participants of a draft chat (held until the first send). */
@@ -826,6 +847,17 @@ interface ChatBackend {
826
847
  receipt: SentReceipt;
827
848
  clientMsgId: string;
828
849
  }>;
850
+ /** Send a reaction (add/remove an emoji on a target message) through the same
851
+ * MLS application path as `sendText`. Returns the receipt + the wire clientMsgId. */
852
+ sendReaction(group: MessagingGroup, args: {
853
+ clientMsgId: string;
854
+ targetClientMsgId: string;
855
+ emoji: string;
856
+ op: 'add' | 'remove';
857
+ }): Promise<{
858
+ receipt: SentReceipt;
859
+ clientMsgId: string;
860
+ }>;
829
861
  history(group: MessagingGroup, limit: number, before?: number): Promise<ChatMessage[]>;
830
862
  members(group: MessagingGroup): Promise<ChatMember[]>;
831
863
  addMember(group: MessagingGroup, userId: string): Promise<void>;
@@ -856,6 +888,8 @@ declare class Chat {
856
888
  private readonly seenKeys;
857
889
  /** Index: clientMsgId → { text, senderUserId } for resolveReply lookups. */
858
890
  private readonly byClientMsgId;
891
+ /** The single authoritative reaction fold for this chat (live + own-send + history). */
892
+ private readonly reactionFold;
859
893
  private loadedEarliestSeq;
860
894
  private historyLoaded;
861
895
  private wired;
@@ -888,6 +922,18 @@ declare class Chat {
888
922
  private mergeHistory;
889
923
  /** @internal — called by the backend's live subscription. */
890
924
  ingestLive(incoming: IncomingMessage): Promise<void>;
925
+ /**
926
+ * Rebuild the target message's `reactions` from the authoritative fold and
927
+ * re-emit. No-op when the target isn't present yet (its tally is attached the
928
+ * moment it lands, via the append/merge paths) or when the tally is unchanged.
929
+ */
930
+ private recomputeReactions;
931
+ /**
932
+ * Overlay the authoritative fold's tally onto a message as it is appended/merged.
933
+ * The Chat fold WINS when it has a non-empty tally; otherwise the tally already
934
+ * attached upstream (the coordinator's page-local history fold) is preserved.
935
+ */
936
+ private applyReactionTally;
891
937
  /** @internal — called by the backend's conv subscription. */
892
938
  applyConv(event: string, payload: Record<string, unknown>): void;
893
939
  private kindOf;
@@ -908,6 +954,15 @@ declare class Chat {
908
954
  leave(): Promise<void>;
909
955
  setTyping(isTyping: boolean): void;
910
956
  markRead(message: ChatMessage): Promise<void>;
957
+ /** Add an emoji reaction to a message. No-op if the message isn't reactable
958
+ * (empty clientMsgId — a legacy/system row). The reaction folds locally with
959
+ * the server receipt's `(epoch, serverSeq)` so the target's tally updates
960
+ * instantly; the durable echo on the next pump is a fold no-op (dedup on the
961
+ * SAME wire clientMsgId). Never appends a bubble. */
962
+ react(message: ChatMessage, emoji: string): Promise<void>;
963
+ /** Remove this user's emoji reaction from a message (op:'remove'). */
964
+ unreact(message: ChatMessage, emoji: string): Promise<void>;
965
+ private sendReaction;
911
966
  }
912
967
 
913
968
  declare class PalbeMessaging {
@@ -749,6 +749,13 @@ interface ChatMessage {
749
749
  readonly clientMsgId: string;
750
750
  /** Resolved reply context, or null if this is not a reply. */
751
751
  readonly replyTo: ResolvedReply | null;
752
+ /**
753
+ * Display-only reaction tally: `emoji → sorted reactor userIds[]`. Defaults to
754
+ * `{}` (no reactions). Recomputed by the Chat from its authoritative
755
+ * `ReactionFold` as reaction events fold onto this message. Reactions are never
756
+ * a visible message of their own — they only mutate the target's tally.
757
+ */
758
+ readonly reactions: Record<string, string[]>;
752
759
  }
753
760
  /** The receipt from a send — the server's monotonic sequence + accepted epoch. */
754
761
  interface SentReceipt {
@@ -789,6 +796,11 @@ interface ReplyRef {
789
796
  client_msg_id: string;
790
797
  preview?: QuotePreview;
791
798
  }
799
+ interface ReactionPayload {
800
+ targetClientMsgId: string;
801
+ emoji: string;
802
+ op: 'add' | 'remove';
803
+ }
792
804
 
793
805
  /** A decoded incoming message handed to chat listeners. */
794
806
  interface IncomingMessage {
@@ -803,6 +815,15 @@ interface IncomingMessage {
803
815
  clientMsgId: string;
804
816
  /** The decoded reply reference, if present in the envelope. */
805
817
  replyRef: ReplyRef | null;
818
+ /**
819
+ * The decoded envelope discriminator (`'text'`/`'reaction'`/`'media'`/…).
820
+ * Defaults to `'text'` at every existing call site — only the reaction branch
821
+ * sets `'reaction'`, so the Chat can route a reaction into its fold instead of
822
+ * appending a visible bubble. Optional for forward-compat with old emitters.
823
+ */
824
+ envelopeType?: string;
825
+ /** The decoded reaction payload, present only when `envelopeType === 'reaction'`. */
826
+ reaction?: ReactionPayload | null;
806
827
  }
807
828
 
808
829
  /** The intended participants of a draft chat (held until the first send). */
@@ -826,6 +847,17 @@ interface ChatBackend {
826
847
  receipt: SentReceipt;
827
848
  clientMsgId: string;
828
849
  }>;
850
+ /** Send a reaction (add/remove an emoji on a target message) through the same
851
+ * MLS application path as `sendText`. Returns the receipt + the wire clientMsgId. */
852
+ sendReaction(group: MessagingGroup, args: {
853
+ clientMsgId: string;
854
+ targetClientMsgId: string;
855
+ emoji: string;
856
+ op: 'add' | 'remove';
857
+ }): Promise<{
858
+ receipt: SentReceipt;
859
+ clientMsgId: string;
860
+ }>;
829
861
  history(group: MessagingGroup, limit: number, before?: number): Promise<ChatMessage[]>;
830
862
  members(group: MessagingGroup): Promise<ChatMember[]>;
831
863
  addMember(group: MessagingGroup, userId: string): Promise<void>;
@@ -856,6 +888,8 @@ declare class Chat {
856
888
  private readonly seenKeys;
857
889
  /** Index: clientMsgId → { text, senderUserId } for resolveReply lookups. */
858
890
  private readonly byClientMsgId;
891
+ /** The single authoritative reaction fold for this chat (live + own-send + history). */
892
+ private readonly reactionFold;
859
893
  private loadedEarliestSeq;
860
894
  private historyLoaded;
861
895
  private wired;
@@ -888,6 +922,18 @@ declare class Chat {
888
922
  private mergeHistory;
889
923
  /** @internal — called by the backend's live subscription. */
890
924
  ingestLive(incoming: IncomingMessage): Promise<void>;
925
+ /**
926
+ * Rebuild the target message's `reactions` from the authoritative fold and
927
+ * re-emit. No-op when the target isn't present yet (its tally is attached the
928
+ * moment it lands, via the append/merge paths) or when the tally is unchanged.
929
+ */
930
+ private recomputeReactions;
931
+ /**
932
+ * Overlay the authoritative fold's tally onto a message as it is appended/merged.
933
+ * The Chat fold WINS when it has a non-empty tally; otherwise the tally already
934
+ * attached upstream (the coordinator's page-local history fold) is preserved.
935
+ */
936
+ private applyReactionTally;
891
937
  /** @internal — called by the backend's conv subscription. */
892
938
  applyConv(event: string, payload: Record<string, unknown>): void;
893
939
  private kindOf;
@@ -908,6 +954,15 @@ declare class Chat {
908
954
  leave(): Promise<void>;
909
955
  setTyping(isTyping: boolean): void;
910
956
  markRead(message: ChatMessage): Promise<void>;
957
+ /** Add an emoji reaction to a message. No-op if the message isn't reactable
958
+ * (empty clientMsgId — a legacy/system row). The reaction folds locally with
959
+ * the server receipt's `(epoch, serverSeq)` so the target's tally updates
960
+ * instantly; the durable echo on the next pump is a fold no-op (dedup on the
961
+ * SAME wire clientMsgId). Never appends a bubble. */
962
+ react(message: ChatMessage, emoji: string): Promise<void>;
963
+ /** Remove this user's emoji reaction from a message (op:'remove'). */
964
+ unreact(message: ChatMessage, emoji: string): Promise<void>;
965
+ private sendReaction;
911
966
  }
912
967
 
913
968
  declare class PalbeMessaging {