@kispi/chat 0.2.1 → 0.2.3

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
@@ -142,6 +142,21 @@ type Message = {
142
142
  emoji: string;
143
143
  count: number;
144
144
  }[];
145
+ /**
146
+ * The emoji this client's user has on the message.
147
+ *
148
+ * Filled by history reads and kept in step by the SDK afterwards: a
149
+ * `reaction.*` event whose `userId` is `chat.user.id` updates it, and
150
+ * this client's own `react()`/`unreact()` update it **before the frame
151
+ * goes out**, rolling back if the server refuses. Absent on a row the
152
+ * server rendered without a viewer (a live `message.created` has none
153
+ * yet, which is the same as empty).
154
+ *
155
+ * The SDK owns this field, so a consumer does not need -- and should
156
+ * not add -- an optimistic layer of its own on top of it. The count in
157
+ * `reactions` is the opposite: always the server's, never moved locally.
158
+ */
159
+ myReactions?: string[];
145
160
  thread?: {
146
161
  count: number;
147
162
  lastSeq?: number;
@@ -281,6 +296,15 @@ declare class Room extends Emitter<RoomEvents> {
281
296
  id?: string;
282
297
  key?: string;
283
298
  });
299
+ /**
300
+ * Whether older history exists above the first message held -- what
301
+ * `loadOlder()` would report as `hasMore`, known before calling it.
302
+ *
303
+ * Derived from the first row's seq against the room's retention floor
304
+ * (the subscribe ack's `minSeq`), and false once a `loadOlder()` came
305
+ * back short. False while nothing is loaded. Re-read it on `messages`.
306
+ */
307
+ get hasOlder(): boolean;
284
308
  /** Everything this client knows about the room, in seq order. A new array whenever it changes. */
285
309
  get messages(): Message[];
286
310
  /**
@@ -348,9 +372,34 @@ declare class Room extends Emitter<RoomEvents> {
348
372
  thread: string;
349
373
  };
350
374
  }): Promise<Message[]>;
351
- /** Adds a reaction. Idempotent, like the frame. */
375
+ /**
376
+ * Adds a reaction. Idempotent, like the frame.
377
+ *
378
+ * The row's `myReactions` moves **before the frame goes out** and rolls
379
+ * back if the server refuses; its count stays the server's. See
380
+ * `toggleReaction`.
381
+ */
352
382
  react(messageId: string, emoji: string): Promise<void>;
383
+ /** Removes a reaction. Idempotent, and optimistic the same way `react` is. */
353
384
  unreact(messageId: string, emoji: string): Promise<void>;
385
+ /**
386
+ * Moves `myReactions` now, sends the frame after.
387
+ *
388
+ * 누른 값은 (사용자, 이모지)로 로컬에서 정해지고 엔진은 멱등이므로 ack를
389
+ * 기다릴 이유가 없다 — 기다리면 누른 느낌이 왕복 시간만큼 늦는다. 소비자가
390
+ * 자기 낙관 계층을 덧대면 이 필드의 주인이 둘이 되므로, SDK가 한다.
391
+ * **발행은 다르다**: `before_publish` 훅이 본문을 바꿀 수 있어 미리 그릴 값이
392
+ * 로컬에 없다. 그래서 `send()`는 낙관적이지 않다.
393
+ *
394
+ * 개수는 옮기지 않는다. ack가 오기 전에 남이 같은 이모지를 누르면 로컬
395
+ * +1/-1은 서버가 보낸 수와 다른 값이 되고, 그것을 고칠 이벤트는 이미
396
+ * 지나갔다. 또 ack와 방 프레임은 다른 길로 와 순서가 없으므로, 늦게 온 내
397
+ * ack(count 1)가 앞서 온 남의 이벤트(count 2)를 되돌린다.
398
+ *
399
+ * 거절·타임아웃·끊김이면 되돌리지만, 그 사이 더 새로운 값이 자리를 차지했다면
400
+ * 두고 나온다(`Timeline.settleReaction`).
401
+ */
402
+ private toggleReaction;
354
403
  /**
355
404
  * Moves this user's read cursor.
356
405
  *
@@ -686,6 +735,31 @@ declare class ChatClient extends Emitter<ChatClientEvents> {
686
735
  registerRoomId(roomId: string, room: Room): void;
687
736
  /** Opens the connection and resolves when `hello` arrives. */
688
737
  connect(): Promise<void>;
738
+ /**
739
+ * Re-authenticates: calls `token()` again and replaces the socket, keeping
740
+ * every room handle and every subscription.
741
+ *
742
+ * For when the identity the server holds has to change mid-session --
743
+ * a nickname change, a new avatar, fresh claims. The server reads the
744
+ * token once, at `auth`, so `sender.name` on the next message is the old
745
+ * one until the connection is re-authenticated. `close()` + `connect()`
746
+ * does that too, but passes through `closed` (a consumer's "you are
747
+ * offline" screen) and tears down the page listeners.
748
+ *
749
+ * States: `open` → `reconnecting` → `open`, never `closed`. Rooms
750
+ * resubscribe from what they hold and catch up the gap, as after any
751
+ * drop; `messages` is kept. Frames awaiting an ack on the old socket are
752
+ * rejected with `closed`. `chat.user` is the new identity once this
753
+ * resolves. If `token()` fails the client keeps retrying in the
754
+ * background like any reconnect (and this rejects); a `ChatError` from
755
+ * `token()` stops it at `closed`, as on connect.
756
+ *
757
+ * On a client that is not connected (never connected, or `close()`d) it
758
+ * is `connect()`.
759
+ */
760
+ reconnect(): Promise<void>;
761
+ /** Sockets `reconnect()` replaced: their late events are not this client's any more. */
762
+ private readonly retired;
689
763
  /**
690
764
  * Closes for good.
691
765
  *
@@ -797,6 +871,21 @@ type FetchRange = (range: {
797
871
  before: number;
798
872
  limit: number;
799
873
  }) => Promise<Message[]>;
874
+ /**
875
+ * A press of this client's own that the server has not answered yet.
876
+ *
877
+ * Carries its own sequence number, which is the whole point: by the time
878
+ * an answer comes back the (message, emoji) pair may belong to a newer
879
+ * press, and settling this one then would put a value nobody is showing
880
+ * any more back on screen.
881
+ */
882
+ type PendingReaction = {
883
+ messageId: string;
884
+ emoji: string;
885
+ /** What the press asked for: in `myReactions`, or out of it. */
886
+ mine: boolean;
887
+ seq: number;
888
+ };
800
889
  type TimelineOptions = {
801
890
  fetchRange: FetchRange;
802
891
  /** Called whenever the list changes. */
@@ -840,9 +929,39 @@ declare class Timeline {
840
929
  private shared;
841
930
  /** The `loadOlder` in flight, so a scroll handler firing twice asks once. */
842
931
  private older;
932
+ /**
933
+ * The lowest seq the room still keeps (`minSeq` from the subscribe ack;
934
+ * 1 until told). Below it there is nothing to read, whatever seq says.
935
+ */
936
+ private floor;
937
+ /** A `loadOlder` came back short: the top of what the server keeps was reached. */
938
+ private exhausted;
939
+ /**
940
+ * Presses this client has made and the server has not answered yet, one
941
+ * entry per (message, emoji) pair, each remembering the last value the
942
+ * **server** gave for that pair.
943
+ *
944
+ * 되돌릴 자리로 "누르기 직전 화면값"을 쓰면 안 된다. 눌렀다 곧바로 취소하고
945
+ * 두 거절이 차례로 오면, 두 번째 거절이 첫 번째의 낙관값 — 서버가 한 번도
946
+ * 가진 적 없는 값 — 을 화면에 되살린다. 마지막으로 서버가 말한 값만이
947
+ * 되돌릴 자리다.
948
+ */
949
+ private readonly presses;
950
+ private pressSeq;
843
951
  constructor(options: TimelineOptions);
844
952
  /** A new array whenever the list changes; never mutated once returned. */
845
953
  get messages(): Message[];
954
+ /**
955
+ * Whether `loadOlder()` would find anything, answered without asking.
956
+ *
957
+ * `loadOlder()`의 `hasMore`와 같은 판정이다: 맨 위 행이 방의 보존 하한
958
+ * (`minSeq`, seq는 1부터 구멍 없이 붙는다)보다 위에 있고, 앞선 `loadOlder`가
959
+ * 덜 찬 페이지로 끝을 알린 적이 없으면 더 있다. 첫 `loadOlder()` 전에 "이전
960
+ * 메시지 더 보기"를 그릴지 정할 수 있게 한다. 목록이 비었으면 false다.
961
+ */
962
+ get hasOlder(): boolean;
963
+ /** Records the room's retention floor (`minSeq`). */
964
+ setFloor(minSeq: number): void;
846
965
  /** The highest seq this timeline holds, hole or no hole. */
847
966
  get highestSeq(): number;
848
967
  /**
@@ -917,9 +1036,42 @@ declare class Timeline {
917
1036
  *
918
1037
  * The server sends the new `count` with the event, so this is a
919
1038
  * replacement rather than an increment: two clients reacting at once
920
- * cannot drift the way `+1`/`-1` would.
1039
+ * cannot drift the way `+1`/`-1` would. `count` undefined leaves the
1040
+ * aggregate alone (the react ack path); `mine` undefined leaves
1041
+ * `myReactions` alone (somebody else's event).
1042
+ *
1043
+ * This is the **authoritative** entry point: a value the server sent.
1044
+ * So a press still waiting on an answer for the same pair is finished
1045
+ * here -- a refusal landing afterwards must not push this value back
1046
+ * to the older one it was going to restore.
921
1047
  */
922
- reaction(messageId: string, emoji: string, count: number): void;
1048
+ reaction(messageId: string, emoji: string, count: number | undefined, mine?: boolean): void;
1049
+ /**
1050
+ * Applies this client's own react/unreact to `myReactions` **before the
1051
+ * frame goes out**, and returns the press so its answer can settle it.
1052
+ *
1053
+ * 누른 값은 (사용자, 이모지)로 로컬에서 정해지고 엔진은 멱등이므로, 미리
1054
+ * 적용해도 ack가 새로 알려 줄 것이 없다. `count`는 일부러 건드리지 않는다 —
1055
+ * 그 사이 남이 같은 이모지를 누르면 로컬 +1/-1은 서버가 보낼 수와 다르고,
1056
+ * 그 차이를 고칠 이벤트는 이미 지나갔다.
1057
+ *
1058
+ * Undefined when the row is not held: there is nothing to show now and
1059
+ * nothing to put back later.
1060
+ */
1061
+ pressReaction(messageId: string, emoji: string, mine: boolean): PendingReaction | undefined;
1062
+ /**
1063
+ * Settles a press with what the server said.
1064
+ *
1065
+ * `accepted` re-asserts the value the press asked for; a refusal puts
1066
+ * the last server-given value back. Either way it does nothing once
1067
+ * this press no longer owns the pair -- a newer press took it over
1068
+ * (and that one's answer decides), or something authoritative already
1069
+ * landed on it (a `reaction.*` event carrying this user's id, a
1070
+ * `reload()`, a reconnect's catch-up page). Reverting there would
1071
+ * resurrect a value older than what is on screen.
1072
+ */
1073
+ settleReaction(press: PendingReaction, accepted: boolean): void;
1074
+ private applyReaction;
923
1075
  /** Applies a `thread.updated` to the root message's aggregate. */
924
1076
  thread(rootId: string, count: number, lastSeq?: number): void;
925
1077
  /** Applies a `message.deleted`, remembering it if the row is not here. */
@@ -962,10 +1114,19 @@ declare class Timeline {
962
1114
  /** Inserts at the seq position, replacing an existing row with that seq. */
963
1115
  private insert;
964
1116
  private applyDelete;
1117
+ /**
1118
+ * Forgets the presses on a row the server has just re-rendered.
1119
+ *
1120
+ * 히스토리 응답의 행은 뷰어별 `myReactions`를 싣고 오므로 그 값이 서버의
1121
+ * 값이다. 누름을 남겨 두면 그 뒤에 온 거절이 더 새로운 진실 위에 옛 값을
1122
+ * 덮어쓴다. 행 전체 단위인 것은 페이지가 그 행의 이모지 전부를 다시 그려
1123
+ * 주기 때문이다.
1124
+ */
1125
+ private serverRendered;
965
1126
  /** Makes `items` safe to mutate: a copy, if the current one was handed out. */
966
1127
  private own;
967
1128
  private changed;
968
1129
  }
969
1130
  declare function createTimeline(options: TimelineOptions): Timeline;
970
1131
 
971
- export { type AuthUser, ChatClient, type ChatClientEvents, type ChatClientOptions, ChatError, type ConnectionState, type FetchRange, type Frame, type Hello, type Message, type PublishAck, type ReactionUser, type ReactionsPage, Room, type RoomEvents, type SendInput, type SendOptions, Timeline, type TimelineOptions, type WebSocketFactory, type WebSocketLike, createChatClient, createTimeline };
1132
+ export { type AuthUser, ChatClient, type ChatClientEvents, type ChatClientOptions, ChatError, type ConnectionState, type FetchRange, type Frame, type Hello, type Message, type PendingReaction, type PublishAck, type ReactionUser, type ReactionsPage, Room, type RoomEvents, type SendInput, type SendOptions, Timeline, type TimelineOptions, type WebSocketFactory, type WebSocketLike, createChatClient, createTimeline };
package/dist/index.d.ts CHANGED
@@ -142,6 +142,21 @@ type Message = {
142
142
  emoji: string;
143
143
  count: number;
144
144
  }[];
145
+ /**
146
+ * The emoji this client's user has on the message.
147
+ *
148
+ * Filled by history reads and kept in step by the SDK afterwards: a
149
+ * `reaction.*` event whose `userId` is `chat.user.id` updates it, and
150
+ * this client's own `react()`/`unreact()` update it **before the frame
151
+ * goes out**, rolling back if the server refuses. Absent on a row the
152
+ * server rendered without a viewer (a live `message.created` has none
153
+ * yet, which is the same as empty).
154
+ *
155
+ * The SDK owns this field, so a consumer does not need -- and should
156
+ * not add -- an optimistic layer of its own on top of it. The count in
157
+ * `reactions` is the opposite: always the server's, never moved locally.
158
+ */
159
+ myReactions?: string[];
145
160
  thread?: {
146
161
  count: number;
147
162
  lastSeq?: number;
@@ -281,6 +296,15 @@ declare class Room extends Emitter<RoomEvents> {
281
296
  id?: string;
282
297
  key?: string;
283
298
  });
299
+ /**
300
+ * Whether older history exists above the first message held -- what
301
+ * `loadOlder()` would report as `hasMore`, known before calling it.
302
+ *
303
+ * Derived from the first row's seq against the room's retention floor
304
+ * (the subscribe ack's `minSeq`), and false once a `loadOlder()` came
305
+ * back short. False while nothing is loaded. Re-read it on `messages`.
306
+ */
307
+ get hasOlder(): boolean;
284
308
  /** Everything this client knows about the room, in seq order. A new array whenever it changes. */
285
309
  get messages(): Message[];
286
310
  /**
@@ -348,9 +372,34 @@ declare class Room extends Emitter<RoomEvents> {
348
372
  thread: string;
349
373
  };
350
374
  }): Promise<Message[]>;
351
- /** Adds a reaction. Idempotent, like the frame. */
375
+ /**
376
+ * Adds a reaction. Idempotent, like the frame.
377
+ *
378
+ * The row's `myReactions` moves **before the frame goes out** and rolls
379
+ * back if the server refuses; its count stays the server's. See
380
+ * `toggleReaction`.
381
+ */
352
382
  react(messageId: string, emoji: string): Promise<void>;
383
+ /** Removes a reaction. Idempotent, and optimistic the same way `react` is. */
353
384
  unreact(messageId: string, emoji: string): Promise<void>;
385
+ /**
386
+ * Moves `myReactions` now, sends the frame after.
387
+ *
388
+ * 누른 값은 (사용자, 이모지)로 로컬에서 정해지고 엔진은 멱등이므로 ack를
389
+ * 기다릴 이유가 없다 — 기다리면 누른 느낌이 왕복 시간만큼 늦는다. 소비자가
390
+ * 자기 낙관 계층을 덧대면 이 필드의 주인이 둘이 되므로, SDK가 한다.
391
+ * **발행은 다르다**: `before_publish` 훅이 본문을 바꿀 수 있어 미리 그릴 값이
392
+ * 로컬에 없다. 그래서 `send()`는 낙관적이지 않다.
393
+ *
394
+ * 개수는 옮기지 않는다. ack가 오기 전에 남이 같은 이모지를 누르면 로컬
395
+ * +1/-1은 서버가 보낸 수와 다른 값이 되고, 그것을 고칠 이벤트는 이미
396
+ * 지나갔다. 또 ack와 방 프레임은 다른 길로 와 순서가 없으므로, 늦게 온 내
397
+ * ack(count 1)가 앞서 온 남의 이벤트(count 2)를 되돌린다.
398
+ *
399
+ * 거절·타임아웃·끊김이면 되돌리지만, 그 사이 더 새로운 값이 자리를 차지했다면
400
+ * 두고 나온다(`Timeline.settleReaction`).
401
+ */
402
+ private toggleReaction;
354
403
  /**
355
404
  * Moves this user's read cursor.
356
405
  *
@@ -686,6 +735,31 @@ declare class ChatClient extends Emitter<ChatClientEvents> {
686
735
  registerRoomId(roomId: string, room: Room): void;
687
736
  /** Opens the connection and resolves when `hello` arrives. */
688
737
  connect(): Promise<void>;
738
+ /**
739
+ * Re-authenticates: calls `token()` again and replaces the socket, keeping
740
+ * every room handle and every subscription.
741
+ *
742
+ * For when the identity the server holds has to change mid-session --
743
+ * a nickname change, a new avatar, fresh claims. The server reads the
744
+ * token once, at `auth`, so `sender.name` on the next message is the old
745
+ * one until the connection is re-authenticated. `close()` + `connect()`
746
+ * does that too, but passes through `closed` (a consumer's "you are
747
+ * offline" screen) and tears down the page listeners.
748
+ *
749
+ * States: `open` → `reconnecting` → `open`, never `closed`. Rooms
750
+ * resubscribe from what they hold and catch up the gap, as after any
751
+ * drop; `messages` is kept. Frames awaiting an ack on the old socket are
752
+ * rejected with `closed`. `chat.user` is the new identity once this
753
+ * resolves. If `token()` fails the client keeps retrying in the
754
+ * background like any reconnect (and this rejects); a `ChatError` from
755
+ * `token()` stops it at `closed`, as on connect.
756
+ *
757
+ * On a client that is not connected (never connected, or `close()`d) it
758
+ * is `connect()`.
759
+ */
760
+ reconnect(): Promise<void>;
761
+ /** Sockets `reconnect()` replaced: their late events are not this client's any more. */
762
+ private readonly retired;
689
763
  /**
690
764
  * Closes for good.
691
765
  *
@@ -797,6 +871,21 @@ type FetchRange = (range: {
797
871
  before: number;
798
872
  limit: number;
799
873
  }) => Promise<Message[]>;
874
+ /**
875
+ * A press of this client's own that the server has not answered yet.
876
+ *
877
+ * Carries its own sequence number, which is the whole point: by the time
878
+ * an answer comes back the (message, emoji) pair may belong to a newer
879
+ * press, and settling this one then would put a value nobody is showing
880
+ * any more back on screen.
881
+ */
882
+ type PendingReaction = {
883
+ messageId: string;
884
+ emoji: string;
885
+ /** What the press asked for: in `myReactions`, or out of it. */
886
+ mine: boolean;
887
+ seq: number;
888
+ };
800
889
  type TimelineOptions = {
801
890
  fetchRange: FetchRange;
802
891
  /** Called whenever the list changes. */
@@ -840,9 +929,39 @@ declare class Timeline {
840
929
  private shared;
841
930
  /** The `loadOlder` in flight, so a scroll handler firing twice asks once. */
842
931
  private older;
932
+ /**
933
+ * The lowest seq the room still keeps (`minSeq` from the subscribe ack;
934
+ * 1 until told). Below it there is nothing to read, whatever seq says.
935
+ */
936
+ private floor;
937
+ /** A `loadOlder` came back short: the top of what the server keeps was reached. */
938
+ private exhausted;
939
+ /**
940
+ * Presses this client has made and the server has not answered yet, one
941
+ * entry per (message, emoji) pair, each remembering the last value the
942
+ * **server** gave for that pair.
943
+ *
944
+ * 되돌릴 자리로 "누르기 직전 화면값"을 쓰면 안 된다. 눌렀다 곧바로 취소하고
945
+ * 두 거절이 차례로 오면, 두 번째 거절이 첫 번째의 낙관값 — 서버가 한 번도
946
+ * 가진 적 없는 값 — 을 화면에 되살린다. 마지막으로 서버가 말한 값만이
947
+ * 되돌릴 자리다.
948
+ */
949
+ private readonly presses;
950
+ private pressSeq;
843
951
  constructor(options: TimelineOptions);
844
952
  /** A new array whenever the list changes; never mutated once returned. */
845
953
  get messages(): Message[];
954
+ /**
955
+ * Whether `loadOlder()` would find anything, answered without asking.
956
+ *
957
+ * `loadOlder()`의 `hasMore`와 같은 판정이다: 맨 위 행이 방의 보존 하한
958
+ * (`minSeq`, seq는 1부터 구멍 없이 붙는다)보다 위에 있고, 앞선 `loadOlder`가
959
+ * 덜 찬 페이지로 끝을 알린 적이 없으면 더 있다. 첫 `loadOlder()` 전에 "이전
960
+ * 메시지 더 보기"를 그릴지 정할 수 있게 한다. 목록이 비었으면 false다.
961
+ */
962
+ get hasOlder(): boolean;
963
+ /** Records the room's retention floor (`minSeq`). */
964
+ setFloor(minSeq: number): void;
846
965
  /** The highest seq this timeline holds, hole or no hole. */
847
966
  get highestSeq(): number;
848
967
  /**
@@ -917,9 +1036,42 @@ declare class Timeline {
917
1036
  *
918
1037
  * The server sends the new `count` with the event, so this is a
919
1038
  * replacement rather than an increment: two clients reacting at once
920
- * cannot drift the way `+1`/`-1` would.
1039
+ * cannot drift the way `+1`/`-1` would. `count` undefined leaves the
1040
+ * aggregate alone (the react ack path); `mine` undefined leaves
1041
+ * `myReactions` alone (somebody else's event).
1042
+ *
1043
+ * This is the **authoritative** entry point: a value the server sent.
1044
+ * So a press still waiting on an answer for the same pair is finished
1045
+ * here -- a refusal landing afterwards must not push this value back
1046
+ * to the older one it was going to restore.
921
1047
  */
922
- reaction(messageId: string, emoji: string, count: number): void;
1048
+ reaction(messageId: string, emoji: string, count: number | undefined, mine?: boolean): void;
1049
+ /**
1050
+ * Applies this client's own react/unreact to `myReactions` **before the
1051
+ * frame goes out**, and returns the press so its answer can settle it.
1052
+ *
1053
+ * 누른 값은 (사용자, 이모지)로 로컬에서 정해지고 엔진은 멱등이므로, 미리
1054
+ * 적용해도 ack가 새로 알려 줄 것이 없다. `count`는 일부러 건드리지 않는다 —
1055
+ * 그 사이 남이 같은 이모지를 누르면 로컬 +1/-1은 서버가 보낼 수와 다르고,
1056
+ * 그 차이를 고칠 이벤트는 이미 지나갔다.
1057
+ *
1058
+ * Undefined when the row is not held: there is nothing to show now and
1059
+ * nothing to put back later.
1060
+ */
1061
+ pressReaction(messageId: string, emoji: string, mine: boolean): PendingReaction | undefined;
1062
+ /**
1063
+ * Settles a press with what the server said.
1064
+ *
1065
+ * `accepted` re-asserts the value the press asked for; a refusal puts
1066
+ * the last server-given value back. Either way it does nothing once
1067
+ * this press no longer owns the pair -- a newer press took it over
1068
+ * (and that one's answer decides), or something authoritative already
1069
+ * landed on it (a `reaction.*` event carrying this user's id, a
1070
+ * `reload()`, a reconnect's catch-up page). Reverting there would
1071
+ * resurrect a value older than what is on screen.
1072
+ */
1073
+ settleReaction(press: PendingReaction, accepted: boolean): void;
1074
+ private applyReaction;
923
1075
  /** Applies a `thread.updated` to the root message's aggregate. */
924
1076
  thread(rootId: string, count: number, lastSeq?: number): void;
925
1077
  /** Applies a `message.deleted`, remembering it if the row is not here. */
@@ -962,10 +1114,19 @@ declare class Timeline {
962
1114
  /** Inserts at the seq position, replacing an existing row with that seq. */
963
1115
  private insert;
964
1116
  private applyDelete;
1117
+ /**
1118
+ * Forgets the presses on a row the server has just re-rendered.
1119
+ *
1120
+ * 히스토리 응답의 행은 뷰어별 `myReactions`를 싣고 오므로 그 값이 서버의
1121
+ * 값이다. 누름을 남겨 두면 그 뒤에 온 거절이 더 새로운 진실 위에 옛 값을
1122
+ * 덮어쓴다. 행 전체 단위인 것은 페이지가 그 행의 이모지 전부를 다시 그려
1123
+ * 주기 때문이다.
1124
+ */
1125
+ private serverRendered;
965
1126
  /** Makes `items` safe to mutate: a copy, if the current one was handed out. */
966
1127
  private own;
967
1128
  private changed;
968
1129
  }
969
1130
  declare function createTimeline(options: TimelineOptions): Timeline;
970
1131
 
971
- export { type AuthUser, ChatClient, type ChatClientEvents, type ChatClientOptions, ChatError, type ConnectionState, type FetchRange, type Frame, type Hello, type Message, type PublishAck, type ReactionUser, type ReactionsPage, Room, type RoomEvents, type SendInput, type SendOptions, Timeline, type TimelineOptions, type WebSocketFactory, type WebSocketLike, createChatClient, createTimeline };
1132
+ export { type AuthUser, ChatClient, type ChatClientEvents, type ChatClientOptions, ChatError, type ConnectionState, type FetchRange, type Frame, type Hello, type Message, type PendingReaction, type PublishAck, type ReactionUser, type ReactionsPage, Room, type RoomEvents, type SendInput, type SendOptions, Timeline, type TimelineOptions, type WebSocketFactory, type WebSocketLike, createChatClient, createTimeline };