@@ -25,6 +25,12 @@ const INITIAL_STATE = Object.freeze({
2525 sortedChatHistoryList : Object . freeze ( [ ] )
2626} satisfies State ) ;
2727
28+ // Question: Why insertion sort works but not quick sort?
29+ // Short answer: Arrival order matters.
30+ // Long answer:
31+ // - Update activity: when replacing an activity, and data from their previous revision still matters
32+ // - Duplicate timestamps: activities without timestamp is consider duplicate value and can't be sort deterministically
33+
2834function upsert ( ponyfill : Pick < GlobalScopePonyfill , 'Date' > , state : State , activity : Activity ) : State {
2935 const nextActivityMap = new Map ( state . activityMap ) ;
3036 const nextLivestreamSessionMap = new Map ( state . livestreamingSessionMap ) ;
@@ -33,6 +39,7 @@ function upsert(ponyfill: Pick<GlobalScopePonyfill, 'Date'>, state: State, activ
3339
3440 const activityInternalId = getActivityInternalId ( activity ) ;
3541 const logicalTimestamp = getLogicalTimestamp ( activity , ponyfill ) ;
42+ let shouldReusePosition = true ;
3643
3744 nextActivityMap . set (
3845 activityInternalId ,
@@ -63,6 +70,11 @@ function upsert(ponyfill: Pick<GlobalScopePonyfill, 'Date'>, state: State, activ
6370 ( nextLivestreamingSession ? nextLivestreamingSession . finalized : false ) ||
6471 activityLivestreamingMetadata . type === 'final activity' ;
6572
73+ // If livestream become finalized in this round, update the position once.
74+ if ( finalized && ! nextLivestreamingSession ?. finalized ) {
75+ shouldReusePosition = false ;
76+ }
77+
6678 const nextLivestreamingSessionMapEntry = {
6779 activities : Object . freeze (
6880 insertSorted < LivestreamSessionMapEntryActivityEntry > (
@@ -167,16 +179,20 @@ function upsert(ponyfill: Pick<GlobalScopePonyfill, 'Date'>, state: State, activ
167179 : // eslint-disable-next-line no-magic-numbers
168180 - 1 ;
169181
170- ~ existingSortedChatHistoryListEntryIndex &&
171- nextSortedChatHistoryList . splice ( existingSortedChatHistoryListEntryIndex , 1 ) ;
172-
173- nextSortedChatHistoryList = insertSorted (
174- nextSortedChatHistoryList ,
175- Object . freeze ( sortedChatHistoryListEntry ) ,
176- ( { logicalTimestamp : x } , { logicalTimestamp : y } ) =>
177- // eslint-disable-next-line no-magic-numbers
178- typeof x === 'undefined' || typeof y === 'undefined' ? - 1 : x - y
179- ) ;
182+ if ( shouldReusePosition && ~ existingSortedChatHistoryListEntryIndex ) {
183+ nextSortedChatHistoryList [ + existingSortedChatHistoryListEntryIndex ] = Object . freeze ( sortedChatHistoryListEntry ) ;
184+ } else {
185+ ~ existingSortedChatHistoryListEntryIndex &&
186+ nextSortedChatHistoryList . splice ( existingSortedChatHistoryListEntryIndex , 1 ) ;
187+
188+ nextSortedChatHistoryList = insertSorted (
189+ nextSortedChatHistoryList ,
190+ Object . freeze ( sortedChatHistoryListEntry ) ,
191+ ( { logicalTimestamp : x } , { logicalTimestamp : y } ) =>
192+ // eslint-disable-next-line no-magic-numbers
193+ typeof x === 'undefined' || typeof y === 'undefined' ? - 1 : x - y
194+ ) ;
195+ }
180196
181197 // #endregion
182198
0 commit comments