@palbase/web 1.4.0 → 1.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.
@@ -710,6 +710,20 @@ type ChatRole = 'owner' | 'admin' | 'member';
710
710
  type MessageDirection = 'incoming' | 'outgoing';
711
711
  /** A renderable message kind. `system` = a membership commit / control frame. */
712
712
  type ChatMessageKind = 'text' | 'media' | 'system';
713
+ /**
714
+ * A resolved mention span inside a message body. Produced at decode/merge time by
715
+ * NORMALIZING the wire `body_ranges` (the pinned `normalizeMentionRangesUtf16`
716
+ * contract) against the message text, then resolving the `mentionedUserId` to a
717
+ * roster display name. Offsets are UTF-16 code units, half-open `[start, start+length)`.
718
+ * `displayName` is `null` when the mentioned user is not in the local roster (the
719
+ * renderer falls back to the underlying `text` slice). Mirrors iOS `ResolvedMention`.
720
+ */
721
+ interface ResolvedMention {
722
+ readonly start: number;
723
+ readonly length: number;
724
+ readonly mentionedUserId: string;
725
+ readonly displayName: string | null;
726
+ }
713
727
  /** A participating USER (not a device). For a direct chat: `[me, peer]`. */
714
728
  interface ChatMember {
715
729
  /** == userId (stable identity). */
@@ -774,6 +788,15 @@ interface ChatMessage {
774
788
  * local-only suppression that omits the message from this view entirely.)
775
789
  */
776
790
  readonly isDeleted: boolean;
791
+ /**
792
+ * The resolved mention spans on this message (defaults to `[]`). A mention is a
793
+ * NORMAL bubble — these spans only annotate the existing `text` for highlighting,
794
+ * they never make a message non-bubble. Recomputed by the Chat as the roster
795
+ * resolves (display names are live, not snapshotted). When this message is
796
+ * tombstoned (deleted-for-everyone) the spans are scrubbed to `[]` (delete
797
+ * DOMINATES); when it is edited they reflect the EDIT's replacement `body_ranges`.
798
+ */
799
+ readonly mentions: ResolvedMention[];
777
800
  }
778
801
  /** The receipt from a send — the server's monotonic sequence + accepted epoch. */
779
802
  interface SentReceipt {
@@ -814,6 +837,15 @@ interface ReplyRef {
814
837
  client_msg_id: string;
815
838
  preview?: QuotePreview;
816
839
  }
840
+ /** A single mention range inside a message body.
841
+ * Offsets are UTF-16 code units, half-open [start, start+length).
842
+ * Wire: snake_case (mentioned_user_id, body_ranges) — web does RAW JSON, no case-convert.
843
+ */
844
+ interface MentionRange {
845
+ start: number;
846
+ length: number;
847
+ mentionedUserId: string;
848
+ }
817
849
  interface ReactionPayload {
818
850
  targetClientMsgId: string;
819
851
  emoji: string;
@@ -857,6 +889,10 @@ interface IncomingMessage {
857
889
  * the Chat route a delete-for-everyone tombstone into its DeleteFold instead of
858
890
  * appending a visible bubble. */
859
891
  delete?: DeletePayload | null;
892
+ /** The decoded mention ranges (raw, un-normalized). Present on a `'text'` bubble
893
+ * with `body_ranges` OR on an `'edit'` (the edit's replacement ranges). The Chat
894
+ * normalizes + resolves roster names → `ChatMessage.mentions` (mentions T6). */
895
+ bodyRanges?: MentionRange[] | null;
860
896
  }
861
897
 
862
898
  /** The intended participants of a draft chat (held until the first send). */
@@ -876,7 +912,7 @@ interface ChatBackend {
876
912
  selfUserId: string;
877
913
  /** Materialize a draft → the active group (DM get-or-create / group create+add). */
878
914
  materialize(draft: ChatDraft): Promise<MessagingGroup>;
879
- sendText(group: MessagingGroup, text: string, replyTo?: ReplyRef | null): Promise<{
915
+ sendText(group: MessagingGroup, text: string, replyTo?: ReplyRef | null, bodyRanges?: MentionRange[] | null): Promise<{
880
916
  receipt: SentReceipt;
881
917
  clientMsgId: string;
882
918
  }>;
@@ -897,6 +933,7 @@ interface ChatBackend {
897
933
  clientMsgId: string;
898
934
  targetClientMsgId: string;
899
935
  newText: string;
936
+ bodyRanges?: MentionRange[] | null;
900
937
  }): Promise<{
901
938
  receipt: SentReceipt;
902
939
  clientMsgId: string;
@@ -927,6 +964,11 @@ interface ChatBackend {
927
964
  loadSuppressed(group: MessagingGroup): Promise<string[]>;
928
965
  /** Persist this chat's delete-for-me suppression keys (durable, no wire). */
929
966
  saveSuppressed(group: MessagingGroup, keys: string[]): Promise<void>;
967
+ /** Load this chat's persisted self-elevation dedup keys (durable, no wire) so a
968
+ * re-delivered mention does not re-fire `onMentionElevation` after a cold launch. */
969
+ loadElevated(group: MessagingGroup): Promise<string[]>;
970
+ /** Persist this chat's self-elevation dedup keys (durable, no wire). */
971
+ saveElevated(group: MessagingGroup, keys: string[]): Promise<void>;
930
972
  }
931
973
  declare class Chat {
932
974
  /** Stable, URL/log-safe id (the grp_ display id once active; a reserved local id while draft). */
@@ -958,6 +1000,13 @@ declare class Chat {
958
1000
  /** True once the persisted suppression set has been loaded (so the omit applies
959
1001
  * even on the cold-launch hydrate path before a fresh deleteForMe). */
960
1002
  private suppressedLoaded;
1003
+ /** Self-elevation dedup keys (`<selfUserId>|<clientMsgId or seq:n>`). Once a
1004
+ * mention of me from another sender fires `onMentionElevation`, its key lands here
1005
+ * + is persisted, so a re-delivery / cold-launch re-hydrate never re-fires. */
1006
+ private readonly elevated;
1007
+ /** True once the persisted elevation set has been loaded (so a re-delivered mention
1008
+ * on the cold-launch hydrate path dedups against the persisted decision). */
1009
+ private elevatedLoaded;
961
1010
  /** Per-target BASE (original) text, so the rendered text is `edit ?? original`.
962
1011
  * Seeded once per target (write-once base) so a 2nd own edit can't corrupt it. */
963
1012
  private readonly originalTextByClientMsgId;
@@ -969,6 +1018,14 @@ declare class Chat {
969
1018
  private wired;
970
1019
  private liveUnsub;
971
1020
  private readonly listeners;
1021
+ /**
1022
+ * Fires ONCE per `(selfUserId, clientMsgId)` when an INCOMING message mentions THIS
1023
+ * user from ANOTHER sender (not an edit). The dedup survives re-delivery + reload
1024
+ * via the persisted elevation set, so this never double-fires for one mention. The
1025
+ * app wires it to a buzz/badge (e.g. an in-app banner). Best-effort cooperative —
1026
+ * the SDK guarantees the DECISION, not the buzz. Mirrors iOS `Chat.onMentionElevation`.
1027
+ */
1028
+ onMentionElevation?: (message: ChatMessage) => void;
972
1029
  /** @internal — obtain via pb.messaging.directChat / groupChat / chat(id). */
973
1030
  constructor(args: {
974
1031
  group: MessagingGroup;
@@ -1009,6 +1066,9 @@ declare class Chat {
1009
1066
  /** Hydrate the persisted delete-for-me suppression keys (once), then re-emit so
1010
1067
  * any already-surfaced suppressed message is omitted (cold-launch parity). */
1011
1068
  private loadSuppressed;
1069
+ /** Hydrate the persisted self-elevation dedup keys (once). No re-emit: the set only
1070
+ * gates the elevation DECISION, it does not change what renders. */
1071
+ private loadElevated;
1012
1072
  private hydrateHistory;
1013
1073
  private mergeHistory;
1014
1074
  /** @internal — called by the backend's live subscription. */
@@ -1017,6 +1077,31 @@ declare class Chat {
1017
1077
  * (null = target unknown/dangling → the fold HOLDs). Captured as a bound arrow
1018
1078
  * so it can be passed to the pure EditFold. */
1019
1079
  private readonly authorOfTarget;
1080
+ /** Resolve a message's decode-time mention spans: NORMALIZE the raw `body_ranges`
1081
+ * against `text` (the pinned `normalizeMentionRangesUtf16` cross-SDK contract) then
1082
+ * resolve each surviving range's `mentionedUserId` to a roster display name. An id
1083
+ * not in the roster resolves to `null` (the renderer falls back to the `text` slice).
1084
+ * Pure over (text, bodyRanges, memberCache); never throws. Mirrors iOS T3. */
1085
+ private resolveMentions;
1086
+ /** Re-resolve the roster display name on already-NORMALIZED spans (the history
1087
+ * projection produces them with null names — resolution is LIVE, not snapshotted).
1088
+ * A member rename then reflects on old messages. Returns the message unchanged when
1089
+ * it has no mentions (the common case) or no name changed. Mirrors iOS T3. */
1090
+ private resolveMentionNames;
1091
+ /** The WINNING edit's resolved mentions for a target (normalize its replacement
1092
+ * ranges against the new text + roster names), or `[]` if no winning edit / no
1093
+ * ranges. The edited message's mentions reflect the EDIT's ranges (mirrors iOS T3). */
1094
+ private editMentions;
1095
+ /** Resolve a userId → its roster display name (null if not a known member). */
1096
+ private displayNameOf;
1097
+ /** Compute the SELF-ELEVATION decision for a freshly-ingested INCOMING bubble and,
1098
+ * when it fires, record the dedup key (persisted) + invoke `onMentionElevation`.
1099
+ * Gate (mirrors iOS T3): a surviving mention targets THIS user AND the sender is not
1100
+ * me AND it's NOT an edit AND the `(selfUserId, clientMsgId|seq)` key isn't already
1101
+ * elevated. Dedup-once: the in-memory set gates the session, the persisted set
1102
+ * survives reload. An EDIT never reaches here (it folds, not a bubble) — the
1103
+ * `envelopeType !== 'edit'` guard is belt-and-braces. */
1104
+ private elevateIfMentioned;
1020
1105
  /** Seed the per-target base text + author for the edit fold. Base is write-once
1021
1106
  * (a later own/peer edit must not overwrite the original we render against). The
1022
1107
  * author is (re)recorded whenever a non-empty resolution is available. */
@@ -1057,10 +1142,14 @@ declare class Chat {
1057
1142
  /** Page older messages in. Returns how many were prepended. */
1058
1143
  loadEarlier(limit?: number): Promise<number>;
1059
1144
  private refreshMembers;
1145
+ /** Re-resolve roster display names across the whole transcript (called on a roster
1146
+ * change). Re-emits only if any name actually changed. */
1147
+ private reresolveAllMentionNames;
1060
1148
  private seedMembersFromGroup;
1061
1149
  private seedDraftMembers;
1062
1150
  send(text: string, opts?: {
1063
1151
  replyTo?: ChatMessage;
1152
+ mentions?: MentionRange[];
1064
1153
  }): Promise<SentReceipt>;
1065
1154
  private appendOwnSend;
1066
1155
  private materializeIfNeeded;
@@ -1084,8 +1173,11 @@ declare class Chat {
1084
1173
  * instantly; the durable echo on the next pump is a fold no-op (dedup on the
1085
1174
  * SAME wire clientMsgId). Never appends a bubble; PRESERVES the target's
1086
1175
  * reactions + reply context. Only the original author's edits count — for an own
1087
- * message self IS the author, so the author-gate passes. */
1088
- edit(message: ChatMessage, newText: string): Promise<void>;
1176
+ * message self IS the author, so the author-gate passes. `opts.mentions` carries the
1177
+ * edit's REPLACEMENT mention ranges → the edited message's mentions reflect them. */
1178
+ edit(message: ChatMessage, newText: string, opts?: {
1179
+ mentions?: MentionRange[];
1180
+ }): Promise<void>;
1089
1181
  /** Delete a message for EVERYONE (a cooperative encrypted tombstone). Only the
1090
1182
  * ORIGINAL SENDER can do this — for an own message self IS the author, so the
1091
1183
  * author-gate passes. Legacy messages (empty clientMsgId) are DISABLED (a
@@ -1491,4 +1583,4 @@ declare class PalbeAnalytics {
1491
1583
  private post;
1492
1584
  }
1493
1585
 
1494
- export { type AnalyticsProperties as A, type RealtimeConnectionState as B, Call as C, type RealtimeHandler as D, type RealtimePayload as E, type FlagsView as F, type RealtimeStatus as G, type RealtimeStatusSnapshot as H, type RealtimeSubscription as I, type ResolvedReply as J, type PalbeRuntime as K, buildRuntime as L, type MagicLinkResult as M, type OAuthExchangeResult as O, PalbeAnalytics as P, RealtimeChannel as R, type SentReceipt as S, type Unsubscribe as U, type AuthChangeEvent as a, type AuthState as b, type AuthSuccess as c, type AuthUser as d, type CallChangeCallback as e, type CallParticipant as f, type CallState as g, Chat as h, type ChatBackend as i, type ChatDraft as j, type ChatKind as k, type ChatMember as l, type ChatMessage as m, type ChatMessageKind as n, type ChatRole as o, type ChatState as p, type CommsPrefs as q, type MessageDirection as r, PalbeAuth as s, PalbeCalls as t, type PalbeConfig as u, PalbeFlags as v, PalbeMessaging as w, type PalbeOAuthConfig as x, PalbeRealtime as y, type PresenceState as z };
1586
+ export { type AnalyticsProperties as A, type PresenceState as B, Call as C, type RealtimeConnectionState as D, type RealtimeHandler as E, type FlagsView as F, type RealtimePayload as G, type RealtimeStatus as H, type RealtimeStatusSnapshot as I, type RealtimeSubscription as J, type ResolvedMention as K, type ResolvedReply as L, type MagicLinkResult as M, type PalbeRuntime as N, type OAuthExchangeResult as O, PalbeAnalytics as P, buildRuntime as Q, RealtimeChannel as R, type SentReceipt as S, type Unsubscribe as U, type AuthChangeEvent as a, type AuthState as b, type AuthSuccess as c, type AuthUser as d, type CallChangeCallback as e, type CallParticipant as f, type CallState as g, Chat as h, type ChatBackend as i, type ChatDraft as j, type ChatKind as k, type ChatMember as l, type ChatMessage as m, type ChatMessageKind as n, type ChatRole as o, type ChatState as p, type CommsPrefs as q, type MentionRange as r, type MessageDirection as s, PalbeAuth as t, PalbeCalls as u, type PalbeConfig as v, PalbeFlags as w, PalbeMessaging as x, type PalbeOAuthConfig as y, PalbeRealtime as z };
@@ -710,6 +710,20 @@ type ChatRole = 'owner' | 'admin' | 'member';
710
710
  type MessageDirection = 'incoming' | 'outgoing';
711
711
  /** A renderable message kind. `system` = a membership commit / control frame. */
712
712
  type ChatMessageKind = 'text' | 'media' | 'system';
713
+ /**
714
+ * A resolved mention span inside a message body. Produced at decode/merge time by
715
+ * NORMALIZING the wire `body_ranges` (the pinned `normalizeMentionRangesUtf16`
716
+ * contract) against the message text, then resolving the `mentionedUserId` to a
717
+ * roster display name. Offsets are UTF-16 code units, half-open `[start, start+length)`.
718
+ * `displayName` is `null` when the mentioned user is not in the local roster (the
719
+ * renderer falls back to the underlying `text` slice). Mirrors iOS `ResolvedMention`.
720
+ */
721
+ interface ResolvedMention {
722
+ readonly start: number;
723
+ readonly length: number;
724
+ readonly mentionedUserId: string;
725
+ readonly displayName: string | null;
726
+ }
713
727
  /** A participating USER (not a device). For a direct chat: `[me, peer]`. */
714
728
  interface ChatMember {
715
729
  /** == userId (stable identity). */
@@ -774,6 +788,15 @@ interface ChatMessage {
774
788
  * local-only suppression that omits the message from this view entirely.)
775
789
  */
776
790
  readonly isDeleted: boolean;
791
+ /**
792
+ * The resolved mention spans on this message (defaults to `[]`). A mention is a
793
+ * NORMAL bubble — these spans only annotate the existing `text` for highlighting,
794
+ * they never make a message non-bubble. Recomputed by the Chat as the roster
795
+ * resolves (display names are live, not snapshotted). When this message is
796
+ * tombstoned (deleted-for-everyone) the spans are scrubbed to `[]` (delete
797
+ * DOMINATES); when it is edited they reflect the EDIT's replacement `body_ranges`.
798
+ */
799
+ readonly mentions: ResolvedMention[];
777
800
  }
778
801
  /** The receipt from a send — the server's monotonic sequence + accepted epoch. */
779
802
  interface SentReceipt {
@@ -814,6 +837,15 @@ interface ReplyRef {
814
837
  client_msg_id: string;
815
838
  preview?: QuotePreview;
816
839
  }
840
+ /** A single mention range inside a message body.
841
+ * Offsets are UTF-16 code units, half-open [start, start+length).
842
+ * Wire: snake_case (mentioned_user_id, body_ranges) — web does RAW JSON, no case-convert.
843
+ */
844
+ interface MentionRange {
845
+ start: number;
846
+ length: number;
847
+ mentionedUserId: string;
848
+ }
817
849
  interface ReactionPayload {
818
850
  targetClientMsgId: string;
819
851
  emoji: string;
@@ -857,6 +889,10 @@ interface IncomingMessage {
857
889
  * the Chat route a delete-for-everyone tombstone into its DeleteFold instead of
858
890
  * appending a visible bubble. */
859
891
  delete?: DeletePayload | null;
892
+ /** The decoded mention ranges (raw, un-normalized). Present on a `'text'` bubble
893
+ * with `body_ranges` OR on an `'edit'` (the edit's replacement ranges). The Chat
894
+ * normalizes + resolves roster names → `ChatMessage.mentions` (mentions T6). */
895
+ bodyRanges?: MentionRange[] | null;
860
896
  }
861
897
 
862
898
  /** The intended participants of a draft chat (held until the first send). */
@@ -876,7 +912,7 @@ interface ChatBackend {
876
912
  selfUserId: string;
877
913
  /** Materialize a draft → the active group (DM get-or-create / group create+add). */
878
914
  materialize(draft: ChatDraft): Promise<MessagingGroup>;
879
- sendText(group: MessagingGroup, text: string, replyTo?: ReplyRef | null): Promise<{
915
+ sendText(group: MessagingGroup, text: string, replyTo?: ReplyRef | null, bodyRanges?: MentionRange[] | null): Promise<{
880
916
  receipt: SentReceipt;
881
917
  clientMsgId: string;
882
918
  }>;
@@ -897,6 +933,7 @@ interface ChatBackend {
897
933
  clientMsgId: string;
898
934
  targetClientMsgId: string;
899
935
  newText: string;
936
+ bodyRanges?: MentionRange[] | null;
900
937
  }): Promise<{
901
938
  receipt: SentReceipt;
902
939
  clientMsgId: string;
@@ -927,6 +964,11 @@ interface ChatBackend {
927
964
  loadSuppressed(group: MessagingGroup): Promise<string[]>;
928
965
  /** Persist this chat's delete-for-me suppression keys (durable, no wire). */
929
966
  saveSuppressed(group: MessagingGroup, keys: string[]): Promise<void>;
967
+ /** Load this chat's persisted self-elevation dedup keys (durable, no wire) so a
968
+ * re-delivered mention does not re-fire `onMentionElevation` after a cold launch. */
969
+ loadElevated(group: MessagingGroup): Promise<string[]>;
970
+ /** Persist this chat's self-elevation dedup keys (durable, no wire). */
971
+ saveElevated(group: MessagingGroup, keys: string[]): Promise<void>;
930
972
  }
931
973
  declare class Chat {
932
974
  /** Stable, URL/log-safe id (the grp_ display id once active; a reserved local id while draft). */
@@ -958,6 +1000,13 @@ declare class Chat {
958
1000
  /** True once the persisted suppression set has been loaded (so the omit applies
959
1001
  * even on the cold-launch hydrate path before a fresh deleteForMe). */
960
1002
  private suppressedLoaded;
1003
+ /** Self-elevation dedup keys (`<selfUserId>|<clientMsgId or seq:n>`). Once a
1004
+ * mention of me from another sender fires `onMentionElevation`, its key lands here
1005
+ * + is persisted, so a re-delivery / cold-launch re-hydrate never re-fires. */
1006
+ private readonly elevated;
1007
+ /** True once the persisted elevation set has been loaded (so a re-delivered mention
1008
+ * on the cold-launch hydrate path dedups against the persisted decision). */
1009
+ private elevatedLoaded;
961
1010
  /** Per-target BASE (original) text, so the rendered text is `edit ?? original`.
962
1011
  * Seeded once per target (write-once base) so a 2nd own edit can't corrupt it. */
963
1012
  private readonly originalTextByClientMsgId;
@@ -969,6 +1018,14 @@ declare class Chat {
969
1018
  private wired;
970
1019
  private liveUnsub;
971
1020
  private readonly listeners;
1021
+ /**
1022
+ * Fires ONCE per `(selfUserId, clientMsgId)` when an INCOMING message mentions THIS
1023
+ * user from ANOTHER sender (not an edit). The dedup survives re-delivery + reload
1024
+ * via the persisted elevation set, so this never double-fires for one mention. The
1025
+ * app wires it to a buzz/badge (e.g. an in-app banner). Best-effort cooperative —
1026
+ * the SDK guarantees the DECISION, not the buzz. Mirrors iOS `Chat.onMentionElevation`.
1027
+ */
1028
+ onMentionElevation?: (message: ChatMessage) => void;
972
1029
  /** @internal — obtain via pb.messaging.directChat / groupChat / chat(id). */
973
1030
  constructor(args: {
974
1031
  group: MessagingGroup;
@@ -1009,6 +1066,9 @@ declare class Chat {
1009
1066
  /** Hydrate the persisted delete-for-me suppression keys (once), then re-emit so
1010
1067
  * any already-surfaced suppressed message is omitted (cold-launch parity). */
1011
1068
  private loadSuppressed;
1069
+ /** Hydrate the persisted self-elevation dedup keys (once). No re-emit: the set only
1070
+ * gates the elevation DECISION, it does not change what renders. */
1071
+ private loadElevated;
1012
1072
  private hydrateHistory;
1013
1073
  private mergeHistory;
1014
1074
  /** @internal — called by the backend's live subscription. */
@@ -1017,6 +1077,31 @@ declare class Chat {
1017
1077
  * (null = target unknown/dangling → the fold HOLDs). Captured as a bound arrow
1018
1078
  * so it can be passed to the pure EditFold. */
1019
1079
  private readonly authorOfTarget;
1080
+ /** Resolve a message's decode-time mention spans: NORMALIZE the raw `body_ranges`
1081
+ * against `text` (the pinned `normalizeMentionRangesUtf16` cross-SDK contract) then
1082
+ * resolve each surviving range's `mentionedUserId` to a roster display name. An id
1083
+ * not in the roster resolves to `null` (the renderer falls back to the `text` slice).
1084
+ * Pure over (text, bodyRanges, memberCache); never throws. Mirrors iOS T3. */
1085
+ private resolveMentions;
1086
+ /** Re-resolve the roster display name on already-NORMALIZED spans (the history
1087
+ * projection produces them with null names — resolution is LIVE, not snapshotted).
1088
+ * A member rename then reflects on old messages. Returns the message unchanged when
1089
+ * it has no mentions (the common case) or no name changed. Mirrors iOS T3. */
1090
+ private resolveMentionNames;
1091
+ /** The WINNING edit's resolved mentions for a target (normalize its replacement
1092
+ * ranges against the new text + roster names), or `[]` if no winning edit / no
1093
+ * ranges. The edited message's mentions reflect the EDIT's ranges (mirrors iOS T3). */
1094
+ private editMentions;
1095
+ /** Resolve a userId → its roster display name (null if not a known member). */
1096
+ private displayNameOf;
1097
+ /** Compute the SELF-ELEVATION decision for a freshly-ingested INCOMING bubble and,
1098
+ * when it fires, record the dedup key (persisted) + invoke `onMentionElevation`.
1099
+ * Gate (mirrors iOS T3): a surviving mention targets THIS user AND the sender is not
1100
+ * me AND it's NOT an edit AND the `(selfUserId, clientMsgId|seq)` key isn't already
1101
+ * elevated. Dedup-once: the in-memory set gates the session, the persisted set
1102
+ * survives reload. An EDIT never reaches here (it folds, not a bubble) — the
1103
+ * `envelopeType !== 'edit'` guard is belt-and-braces. */
1104
+ private elevateIfMentioned;
1020
1105
  /** Seed the per-target base text + author for the edit fold. Base is write-once
1021
1106
  * (a later own/peer edit must not overwrite the original we render against). The
1022
1107
  * author is (re)recorded whenever a non-empty resolution is available. */
@@ -1057,10 +1142,14 @@ declare class Chat {
1057
1142
  /** Page older messages in. Returns how many were prepended. */
1058
1143
  loadEarlier(limit?: number): Promise<number>;
1059
1144
  private refreshMembers;
1145
+ /** Re-resolve roster display names across the whole transcript (called on a roster
1146
+ * change). Re-emits only if any name actually changed. */
1147
+ private reresolveAllMentionNames;
1060
1148
  private seedMembersFromGroup;
1061
1149
  private seedDraftMembers;
1062
1150
  send(text: string, opts?: {
1063
1151
  replyTo?: ChatMessage;
1152
+ mentions?: MentionRange[];
1064
1153
  }): Promise<SentReceipt>;
1065
1154
  private appendOwnSend;
1066
1155
  private materializeIfNeeded;
@@ -1084,8 +1173,11 @@ declare class Chat {
1084
1173
  * instantly; the durable echo on the next pump is a fold no-op (dedup on the
1085
1174
  * SAME wire clientMsgId). Never appends a bubble; PRESERVES the target's
1086
1175
  * reactions + reply context. Only the original author's edits count — for an own
1087
- * message self IS the author, so the author-gate passes. */
1088
- edit(message: ChatMessage, newText: string): Promise<void>;
1176
+ * message self IS the author, so the author-gate passes. `opts.mentions` carries the
1177
+ * edit's REPLACEMENT mention ranges → the edited message's mentions reflect them. */
1178
+ edit(message: ChatMessage, newText: string, opts?: {
1179
+ mentions?: MentionRange[];
1180
+ }): Promise<void>;
1089
1181
  /** Delete a message for EVERYONE (a cooperative encrypted tombstone). Only the
1090
1182
  * ORIGINAL SENDER can do this — for an own message self IS the author, so the
1091
1183
  * author-gate passes. Legacy messages (empty clientMsgId) are DISABLED (a
@@ -1491,4 +1583,4 @@ declare class PalbeAnalytics {
1491
1583
  private post;
1492
1584
  }
1493
1585
 
1494
- export { type AnalyticsProperties as A, type RealtimeConnectionState as B, Call as C, type RealtimeHandler as D, type RealtimePayload as E, type FlagsView as F, type RealtimeStatus as G, type RealtimeStatusSnapshot as H, type RealtimeSubscription as I, type ResolvedReply as J, type PalbeRuntime as K, buildRuntime as L, type MagicLinkResult as M, type OAuthExchangeResult as O, PalbeAnalytics as P, RealtimeChannel as R, type SentReceipt as S, type Unsubscribe as U, type AuthChangeEvent as a, type AuthState as b, type AuthSuccess as c, type AuthUser as d, type CallChangeCallback as e, type CallParticipant as f, type CallState as g, Chat as h, type ChatBackend as i, type ChatDraft as j, type ChatKind as k, type ChatMember as l, type ChatMessage as m, type ChatMessageKind as n, type ChatRole as o, type ChatState as p, type CommsPrefs as q, type MessageDirection as r, PalbeAuth as s, PalbeCalls as t, type PalbeConfig as u, PalbeFlags as v, PalbeMessaging as w, type PalbeOAuthConfig as x, PalbeRealtime as y, type PresenceState as z };
1586
+ export { type AnalyticsProperties as A, type PresenceState as B, Call as C, type RealtimeConnectionState as D, type RealtimeHandler as E, type FlagsView as F, type RealtimePayload as G, type RealtimeStatus as H, type RealtimeStatusSnapshot as I, type RealtimeSubscription as J, type ResolvedMention as K, type ResolvedReply as L, type MagicLinkResult as M, type PalbeRuntime as N, type OAuthExchangeResult as O, PalbeAnalytics as P, buildRuntime as Q, RealtimeChannel as R, type SentReceipt as S, type Unsubscribe as U, type AuthChangeEvent as a, type AuthState as b, type AuthSuccess as c, type AuthUser as d, type CallChangeCallback as e, type CallParticipant as f, type CallState as g, Chat as h, type ChatBackend as i, type ChatDraft as j, type ChatKind as k, type ChatMember as l, type ChatMessage as m, type ChatMessageKind as n, type ChatRole as o, type ChatState as p, type CommsPrefs as q, type MentionRange as r, type MessageDirection as s, PalbeAuth as t, PalbeCalls as u, type PalbeConfig as v, PalbeFlags as w, PalbeMessaging as x, type PalbeOAuthConfig as y, PalbeRealtime as z };