@unwanted/matrix-sdk-mini 34.12.0-8 → 34.12.0-9

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.
Files changed (51) hide show
  1. package/lib/client.js +11 -11
  2. package/lib/client.js.map +1 -1
  3. package/lib/embedded.d.ts.map +1 -1
  4. package/lib/embedded.js +35 -2
  5. package/lib/embedded.js.map +1 -1
  6. package/lib/models/event-timeline-set.d.ts +6 -10
  7. package/lib/models/event-timeline-set.d.ts.map +1 -1
  8. package/lib/models/event-timeline-set.js +28 -36
  9. package/lib/models/event-timeline-set.js.map +1 -1
  10. package/lib/models/event-timeline.d.ts +7 -2
  11. package/lib/models/event-timeline.d.ts.map +1 -1
  12. package/lib/models/event-timeline.js +8 -9
  13. package/lib/models/event-timeline.js.map +1 -1
  14. package/lib/models/event.d.ts.map +1 -1
  15. package/lib/models/event.js +1 -1
  16. package/lib/models/event.js.map +1 -1
  17. package/lib/models/room-state.d.ts +2 -13
  18. package/lib/models/room-state.d.ts.map +1 -1
  19. package/lib/models/room-state.js +2 -30
  20. package/lib/models/room-state.js.map +1 -1
  21. package/lib/models/room.d.ts +2 -2
  22. package/lib/models/room.d.ts.map +1 -1
  23. package/lib/models/room.js +27 -14
  24. package/lib/models/room.js.map +1 -1
  25. package/lib/models/thread.d.ts.map +1 -1
  26. package/lib/models/thread.js +5 -3
  27. package/lib/models/thread.js.map +1 -1
  28. package/lib/sliding-sync-sdk.d.ts +1 -1
  29. package/lib/sliding-sync-sdk.d.ts.map +1 -1
  30. package/lib/sliding-sync-sdk.js +15 -13
  31. package/lib/sliding-sync-sdk.js.map +1 -1
  32. package/lib/sync-accumulator.d.ts +6 -4
  33. package/lib/sync-accumulator.d.ts.map +1 -1
  34. package/lib/sync-accumulator.js +23 -12
  35. package/lib/sync-accumulator.js.map +1 -1
  36. package/lib/sync.d.ts +10 -1
  37. package/lib/sync.d.ts.map +1 -1
  38. package/lib/sync.js +93 -42
  39. package/lib/sync.js.map +1 -1
  40. package/package.json +6 -6
  41. package/src/client.ts +11 -11
  42. package/src/embedded.ts +35 -2
  43. package/src/models/event-timeline-set.ts +17 -38
  44. package/src/models/event-timeline.ts +10 -5
  45. package/src/models/event.ts +3 -1
  46. package/src/models/room-state.ts +2 -29
  47. package/src/models/room.ts +18 -6
  48. package/src/models/thread.ts +4 -2
  49. package/src/sliding-sync-sdk.ts +8 -11
  50. package/src/sync-accumulator.ts +33 -16
  51. package/src/sync.ts +111 -45
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unwanted/matrix-sdk-mini",
3
- "version": "34.12.0-8",
3
+ "version": "34.12.0-9",
4
4
  "description": "Matrix Client-Server mini SDK for Javascript",
5
5
  "engines": {
6
6
  "node": ">=20.0.0"
@@ -59,7 +59,7 @@
59
59
  "matrix-widget-api": "^1.10.0",
60
60
  "oidc-client-ts": "^3.0.1",
61
61
  "p-retry": "4",
62
- "sdp-transform": "^2.14.1",
62
+ "sdp-transform": "^2.15.0",
63
63
  "unhomoglyph": "^1.0.6",
64
64
  "uuid": "11"
65
65
  },
@@ -98,7 +98,7 @@
98
98
  "eslint-import-resolver-typescript": "^3.5.1",
99
99
  "eslint-plugin-import": "^2.26.0",
100
100
  "eslint-plugin-jest": "^28.0.0",
101
- "eslint-plugin-jsdoc": "^50.0.0",
101
+ "eslint-plugin-jsdoc": "^50.6.0",
102
102
  "eslint-plugin-matrix-org": "^2.0.1",
103
103
  "eslint-plugin-n": "^14.0.0",
104
104
  "eslint-plugin-tsdoc": "^0.3.0",
@@ -111,15 +111,15 @@
111
111
  "jest-environment-jsdom": "^29.0.0",
112
112
  "jest-localstorage-mock": "^2.4.6",
113
113
  "jest-mock": "^29.0.0",
114
- "knip": "^5.0.0",
114
+ "knip": "^5.38.1",
115
115
  "lint-staged": "^15.0.2",
116
116
  "matrix-mock-request": "^2.5.0",
117
117
  "node-fetch": "^2.7.0",
118
- "prettier": "3.3.3",
118
+ "prettier": "3.4.1",
119
119
  "rimraf": "^6.0.0",
120
120
  "ts-node": "^10.9.2",
121
121
  "typedoc": "^0.26.0",
122
- "typedoc-plugin-coverage": "^3.0.0",
122
+ "typedoc-plugin-coverage": "^3.4.0",
123
123
  "typedoc-plugin-mdn-links": "^3.0.3",
124
124
  "typedoc-plugin-missing-exports": "^3.0.0",
125
125
  "typescript": "^5.4.2"
package/src/client.ts CHANGED
@@ -3456,7 +3456,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
3456
3456
  room.partitionThreadedEvents(matrixEvents);
3457
3457
 
3458
3458
  this.processAggregatedTimelineEvents(room, timelineEvents);
3459
- room.addEventsToTimeline(timelineEvents, true, room.getLiveTimeline());
3459
+ room.addEventsToTimeline(timelineEvents, true, true, room.getLiveTimeline());
3460
3460
  this.processThreadEvents(room, threadedEvents, true);
3461
3461
  unknownRelations.forEach((event) => room.relations.aggregateChildEvent(event));
3462
3462
 
@@ -3568,7 +3568,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
3568
3568
  }
3569
3569
 
3570
3570
  const [timelineEvents, threadedEvents, unknownRelations] = timelineSet.room.partitionThreadedEvents(events);
3571
- timelineSet.addEventsToTimeline(timelineEvents, true, timeline, res.start);
3571
+ timelineSet.addEventsToTimeline(timelineEvents, true, false, timeline, res.start);
3572
3572
  // The target event is not in a thread but process the contextual events, so we can show any threads around it.
3573
3573
  this.processThreadEvents(timelineSet.room, threadedEvents, true);
3574
3574
  this.processAggregatedTimelineEvents(timelineSet.room, timelineEvents);
@@ -3662,10 +3662,10 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
3662
3662
  timeline.initialiseState(res.state.map(mapper));
3663
3663
  }
3664
3664
 
3665
- timelineSet.addEventsToTimeline(events, true, timeline, resNewer.next_batch);
3665
+ timelineSet.addEventsToTimeline(events, true, false, timeline, resNewer.next_batch);
3666
3666
  if (!resOlder.next_batch) {
3667
3667
  const originalEvent = await this.fetchRoomEvent(timelineSet.room.roomId, thread.id);
3668
- timelineSet.addEventsToTimeline([mapper(originalEvent)], true, timeline, null);
3668
+ timelineSet.addEventsToTimeline([mapper(originalEvent)], true, false, timeline, null);
3669
3669
  }
3670
3670
  timeline.setPaginationToken(resOlder.next_batch ?? null, Direction.Backward);
3671
3671
  timeline.setPaginationToken(resNewer.next_batch ?? null, Direction.Forward);
@@ -3719,10 +3719,10 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
3719
3719
  const timeline = timelineSet.getLiveTimeline();
3720
3720
  timeline.getState(EventTimeline.BACKWARDS)!.setUnknownStateEvents(res.state.map(mapper));
3721
3721
 
3722
- timelineSet.addEventsToTimeline(events, true, timeline, null);
3722
+ timelineSet.addEventsToTimeline(events, true, false, timeline, null);
3723
3723
  if (!resOlder.next_batch) {
3724
3724
  const originalEvent = await this.fetchRoomEvent(timelineSet.room.roomId, thread.id);
3725
- timelineSet.addEventsToTimeline([mapper(originalEvent)], true, timeline, null);
3725
+ timelineSet.addEventsToTimeline([mapper(originalEvent)], true, false, timeline, null);
3726
3726
  }
3727
3727
  timeline.setPaginationToken(resOlder.next_batch ?? null, Direction.Backward);
3728
3728
  timeline.setPaginationToken(null, Direction.Forward);
@@ -3985,7 +3985,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
3985
3985
  // No need to partition events for threads here, everything lives
3986
3986
  // in the notification timeline set
3987
3987
  const timelineSet = eventTimeline.getTimelineSet();
3988
- timelineSet.addEventsToTimeline(matrixEvents, backwards, eventTimeline, token);
3988
+ timelineSet.addEventsToTimeline(matrixEvents, backwards, false, eventTimeline, token);
3989
3989
  this.processAggregatedTimelineEvents(timelineSet.room, matrixEvents);
3990
3990
 
3991
3991
  // if we've hit the end of the timeline, we need to stop trying to
@@ -4028,7 +4028,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
4028
4028
  const matrixEvents = res.chunk.filter(noUnsafeEventProps).map(this.getEventMapper());
4029
4029
 
4030
4030
  const timelineSet = eventTimeline.getTimelineSet();
4031
- timelineSet.addEventsToTimeline(matrixEvents, backwards, eventTimeline, token);
4031
+ timelineSet.addEventsToTimeline(matrixEvents, backwards, false, eventTimeline, token);
4032
4032
  this.processAggregatedTimelineEvents(room, matrixEvents);
4033
4033
  this.processThreadRoots(room, matrixEvents, backwards);
4034
4034
 
@@ -4076,12 +4076,12 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
4076
4076
  const newToken = res.next_batch;
4077
4077
 
4078
4078
  const timelineSet = eventTimeline.getTimelineSet();
4079
- timelineSet.addEventsToTimeline(matrixEvents, backwards, eventTimeline, newToken ?? null);
4079
+ timelineSet.addEventsToTimeline(matrixEvents, backwards, false, eventTimeline, newToken ?? null);
4080
4080
  if (!newToken && backwards) {
4081
4081
  const originalEvent =
4082
4082
  thread.rootEvent ??
4083
4083
  mapper(await this.fetchRoomEvent(eventTimeline.getRoomId() ?? "", thread.id));
4084
- timelineSet.addEventsToTimeline([originalEvent], true, eventTimeline, null);
4084
+ timelineSet.addEventsToTimeline([originalEvent], true, false, eventTimeline, null);
4085
4085
  }
4086
4086
  this.processAggregatedTimelineEvents(timelineSet.room, matrixEvents);
4087
4087
 
@@ -4120,7 +4120,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
4120
4120
 
4121
4121
  const timelineSet = eventTimeline.getTimelineSet();
4122
4122
  const [timelineEvents, , unknownRelations] = room.partitionThreadedEvents(matrixEvents);
4123
- timelineSet.addEventsToTimeline(timelineEvents, backwards, eventTimeline, token);
4123
+ timelineSet.addEventsToTimeline(timelineEvents, backwards, false, eventTimeline, token);
4124
4124
  this.processAggregatedTimelineEvents(room, timelineEvents);
4125
4125
  this.processThreadRoots(
4126
4126
  room,
package/src/embedded.ts CHANGED
@@ -282,7 +282,13 @@ export class RoomWidgetClient extends MatrixClient {
282
282
  const rawEvents = await this.widgetApi.readStateEvents(eventType, undefined, stateKey, [this.roomId]);
283
283
  const events = rawEvents.map((rawEvent) => new MatrixEvent(rawEvent as Partial<IEvent>));
284
284
 
285
- await this.syncApi!.injectRoomEvents(this.room!, [], events);
285
+ if (this.syncApi instanceof SyncApi) {
286
+ // Passing undefined for `stateAfterEventList` allows will make `injectRoomEvents` run in legacy mode
287
+ // -> state events in `timelineEventList` will update the state.
288
+ await this.syncApi.injectRoomEvents(this.room!, undefined, events);
289
+ } else {
290
+ await this.syncApi!.injectRoomEvents(this.room!, events); // Sliding Sync
291
+ }
286
292
  events.forEach((event) => {
287
293
  this.emit(ClientEvent.Event, event);
288
294
  logger.info(`Backfilled event ${event.getId()} ${event.getType()} ${event.getStateKey()}`);
@@ -466,7 +472,34 @@ export class RoomWidgetClient extends MatrixClient {
466
472
 
467
473
  // Only inject once we have update the txId
468
474
  await this.updateTxId(event);
469
- await this.syncApi!.injectRoomEvents(this.room!, [], [event]);
475
+
476
+ // The widget API does not tell us whether a state event came from `state_after` or not so we assume legacy behaviour for now.
477
+ if (this.syncApi instanceof SyncApi) {
478
+ // The code will want to be something like:
479
+ // ```
480
+ // if (!params.addToTimeline && !params.addToState) {
481
+ // // Passing undefined for `stateAfterEventList` makes `injectRoomEvents` run in "legacy mode"
482
+ // // -> state events part of the `timelineEventList` parameter will update the state.
483
+ // this.injectRoomEvents(this.room!, [], undefined, [event]);
484
+ // } else {
485
+ // this.injectRoomEvents(this.room!, undefined, params.addToState ? [event] : [], params.addToTimeline ? [event] : []);
486
+ // }
487
+ // ```
488
+
489
+ // Passing undefined for `stateAfterEventList` allows will make `injectRoomEvents` run in legacy mode
490
+ // -> state events in `timelineEventList` will update the state.
491
+ await this.syncApi.injectRoomEvents(this.room!, [], undefined, [event]);
492
+ } else {
493
+ // The code will want to be something like:
494
+ // ```
495
+ // if (!params.addToTimeline && !params.addToState) {
496
+ // this.injectRoomEvents(this.room!, [], [event]);
497
+ // } else {
498
+ // this.injectRoomEvents(this.room!, params.addToState ? [event] : [], params.addToTimeline ? [event] : []);
499
+ // }
500
+ // ```
501
+ await this.syncApi!.injectRoomEvents(this.room!, [], [event]); // Sliding Sync
502
+ }
470
503
  this.emit(ClientEvent.Event, event);
471
504
  this.setSyncState(SyncState.Syncing);
472
505
  logger.info(`Received event ${event.getId()} ${event.getType()} ${event.getStateKey()}`);
@@ -58,13 +58,13 @@ export interface IRoomTimelineData {
58
58
  }
59
59
 
60
60
  export interface IAddEventToTimelineOptions
61
- extends Pick<IAddEventOptions, "toStartOfTimeline" | "roomState" | "timelineWasEmpty"> {
61
+ extends Pick<IAddEventOptions, "toStartOfTimeline" | "roomState" | "timelineWasEmpty" | "addToState"> {
62
62
  /** Whether the sync response came from cache */
63
63
  fromCache?: boolean;
64
64
  }
65
65
 
66
66
  export interface IAddLiveEventOptions
67
- extends Pick<IAddEventToTimelineOptions, "fromCache" | "roomState" | "timelineWasEmpty"> {
67
+ extends Pick<IAddEventToTimelineOptions, "fromCache" | "roomState" | "timelineWasEmpty" | "addToState"> {
68
68
  /** Applies to events in the timeline only. If this is 'replace' then if a
69
69
  * duplicate is encountered, the event passed to this function will replace
70
70
  * the existing event in the timeline. If this is not specified, or is
@@ -391,6 +391,7 @@ export class EventTimelineSet extends TypedEventEmitter<EmittedEvents, EventTime
391
391
  public addEventsToTimeline(
392
392
  events: MatrixEvent[],
393
393
  toStartOfTimeline: boolean,
394
+ addToState: boolean,
394
395
  timeline: EventTimeline,
395
396
  paginationToken?: string | null,
396
397
  ): void {
@@ -495,6 +496,7 @@ export class EventTimelineSet extends TypedEventEmitter<EmittedEvents, EventTime
495
496
  // we don't know about this event yet. Just add it to the timeline.
496
497
  this.addEventToTimeline(event, timeline, {
497
498
  toStartOfTimeline,
499
+ addToState,
498
500
  });
499
501
  lastEventWasNew = true;
500
502
  didUpdate = true;
@@ -592,7 +594,7 @@ export class EventTimelineSet extends TypedEventEmitter<EmittedEvents, EventTime
592
594
  */
593
595
  public addLiveEvent(
594
596
  event: MatrixEvent,
595
- { duplicateStrategy, fromCache, roomState, timelineWasEmpty }: IAddLiveEventOptions = {},
597
+ { duplicateStrategy, fromCache, roomState, timelineWasEmpty, addToState }: IAddLiveEventOptions,
596
598
  ): void {
597
599
  if (this.filter) {
598
600
  const events = this.filter.filterRoomTimeline([event]);
@@ -630,6 +632,7 @@ export class EventTimelineSet extends TypedEventEmitter<EmittedEvents, EventTime
630
632
  fromCache,
631
633
  roomState,
632
634
  timelineWasEmpty,
635
+ addToState
633
636
  });
634
637
  }
635
638
 
@@ -649,40 +652,8 @@ export class EventTimelineSet extends TypedEventEmitter<EmittedEvents, EventTime
649
652
  public addEventToTimeline(
650
653
  event: MatrixEvent,
651
654
  timeline: EventTimeline,
652
- { toStartOfTimeline, fromCache, roomState, timelineWasEmpty }: IAddEventToTimelineOptions,
653
- ): void;
654
- /**
655
- * @deprecated In favor of the overload with `IAddEventToTimelineOptions`
656
- */
657
- public addEventToTimeline(
658
- event: MatrixEvent,
659
- timeline: EventTimeline,
660
- toStartOfTimeline: boolean,
661
- fromCache?: boolean,
662
- roomState?: RoomState,
663
- ): void;
664
- public addEventToTimeline(
665
- event: MatrixEvent,
666
- timeline: EventTimeline,
667
- toStartOfTimelineOrOpts: boolean | IAddEventToTimelineOptions,
668
- fromCache = false,
669
- roomState?: RoomState,
655
+ { toStartOfTimeline, fromCache = false, roomState, timelineWasEmpty, addToState }: IAddEventToTimelineOptions,
670
656
  ): void {
671
- let toStartOfTimeline = !!toStartOfTimelineOrOpts;
672
- let timelineWasEmpty: boolean | undefined;
673
- if (typeof toStartOfTimelineOrOpts === "object") {
674
- ({ toStartOfTimeline, fromCache = false, roomState, timelineWasEmpty } = toStartOfTimelineOrOpts);
675
- } else if (toStartOfTimelineOrOpts !== undefined) {
676
- // Deprecation warning
677
- // FIXME: Remove after 2023-06-01 (technical debt)
678
- logger.warn(
679
- "Overload deprecated: " +
680
- "`EventTimelineSet.addEventToTimeline(event, timeline, toStartOfTimeline, fromCache?, roomState?)` " +
681
- "is deprecated in favor of the overload with " +
682
- "`EventTimelineSet.addEventToTimeline(event, timeline, IAddEventToTimelineOptions)`",
683
- );
684
- }
685
-
686
657
  if (timeline.getTimelineSet() !== this) {
687
658
  throw new Error(`EventTimelineSet.addEventToTimeline: Timeline=${timeline.toString()} does not belong " +
688
659
  "in timelineSet(threadId=${this.thread?.id})`);
@@ -713,6 +684,7 @@ export class EventTimelineSet extends TypedEventEmitter<EmittedEvents, EventTime
713
684
  toStartOfTimeline,
714
685
  roomState,
715
686
  timelineWasEmpty,
687
+ addToState,
716
688
  });
717
689
  this._eventIdToTimeline.set(eventId, timeline);
718
690
 
@@ -741,7 +713,12 @@ export class EventTimelineSet extends TypedEventEmitter<EmittedEvents, EventTime
741
713
  * @remarks
742
714
  * Fires {@link RoomEvent.Timeline}
743
715
  */
744
- public insertEventIntoTimeline(event: MatrixEvent, timeline: EventTimeline, roomState: RoomState): void {
716
+ public insertEventIntoTimeline(
717
+ event: MatrixEvent,
718
+ timeline: EventTimeline,
719
+ roomState: RoomState,
720
+ addToState: boolean,
721
+ ): void {
745
722
  if (timeline.getTimelineSet() !== this) {
746
723
  throw new Error(`EventTimelineSet.insertEventIntoTimeline: Timeline=${timeline.toString()} does not belong " +
747
724
  "in timelineSet(threadId=${this.thread?.id})`);
@@ -777,6 +754,7 @@ export class EventTimelineSet extends TypedEventEmitter<EmittedEvents, EventTime
777
754
  fromCache: false,
778
755
  timelineWasEmpty: false,
779
756
  roomState,
757
+ addToState,
780
758
  });
781
759
  return;
782
760
  }
@@ -799,7 +777,7 @@ export class EventTimelineSet extends TypedEventEmitter<EmittedEvents, EventTime
799
777
  // If we got to the end of the loop, insertIndex points at the end of
800
778
  // the list.
801
779
 
802
- timeline.insertEvent(event, insertIndex, roomState);
780
+ timeline.insertEvent(event, insertIndex, roomState, addToState);
803
781
  this._eventIdToTimeline.set(eventId, timeline);
804
782
 
805
783
  const data: IRoomTimelineData = {
@@ -832,6 +810,7 @@ export class EventTimelineSet extends TypedEventEmitter<EmittedEvents, EventTime
832
810
  } else if (!this.filter || this.filter.filterRoomTimeline([localEvent]).length) {
833
811
  this.addEventToTimeline(localEvent, this.liveTimeline, {
834
812
  toStartOfTimeline: false,
813
+ addToState: false,
835
814
  });
836
815
  }
837
816
  }
@@ -35,6 +35,11 @@ export interface IAddEventOptions extends Pick<IMarkerFoundOptions, "timelineWas
35
35
  toStartOfTimeline: boolean;
36
36
  /** The state events to reconcile metadata from */
37
37
  roomState?: RoomState;
38
+ /** Whether to add timeline events to the state as was done in legacy sync v2.
39
+ * If true then timeline events will be added to the state.
40
+ * In sync v2 with org.matrix.msc4222.use_state_after and simplified sliding sync,
41
+ * all state arrives explicitly and timeline events should not be added. */
42
+ addToState: boolean;
38
43
  }
39
44
 
40
45
  export enum Direction {
@@ -127,7 +132,7 @@ export class EventTimeline {
127
132
  public constructor(private readonly eventTimelineSet: EventTimelineSet) {
128
133
  this.roomId = eventTimelineSet.room?.roomId ?? null;
129
134
  if (this.roomId) {
130
- this.startState = new RoomState(this.roomId, undefined, true);
135
+ this.startState = new RoomState(this.roomId);
131
136
  this.endState = new RoomState(this.roomId);
132
137
  }
133
138
 
@@ -362,7 +367,7 @@ export class EventTimeline {
362
367
  */
363
368
  public addEvent(
364
369
  event: MatrixEvent,
365
- { toStartOfTimeline, roomState, timelineWasEmpty }: IAddEventOptions = { toStartOfTimeline: false },
370
+ { toStartOfTimeline, roomState, timelineWasEmpty, addToState }: IAddEventOptions,
366
371
  ): void {
367
372
  if (!roomState) {
368
373
  roomState = toStartOfTimeline ? this.startState : this.endState;
@@ -374,7 +379,7 @@ export class EventTimeline {
374
379
  EventTimeline.setEventMetadata(event, roomState!, toStartOfTimeline);
375
380
 
376
381
  // modify state but only on unfiltered timelineSets
377
- if (event.isState() && timelineSet.room.getUnfilteredTimelineSet() === timelineSet) {
382
+ if (addToState && event.isState() && timelineSet.room.getUnfilteredTimelineSet() === timelineSet) {
378
383
  roomState?.setStateEvents([event], { timelineWasEmpty });
379
384
  // it is possible that the act of setting the state event means we
380
385
  // can set more metadata (specifically sender/target props), so try
@@ -417,14 +422,14 @@ export class EventTimeline {
417
422
  *
418
423
  * @internal
419
424
  */
420
- public insertEvent(event: MatrixEvent, insertIndex: number, roomState: RoomState): void {
425
+ public insertEvent(event: MatrixEvent, insertIndex: number, roomState: RoomState, addToState: boolean): void {
421
426
  const timelineSet = this.getTimelineSet();
422
427
 
423
428
  if (timelineSet.room) {
424
429
  EventTimeline.setEventMetadata(event, roomState, false);
425
430
 
426
431
  // modify state but only on unfiltered timelineSets
427
- if (event.isState() && timelineSet.room.getUnfilteredTimelineSet() === timelineSet) {
432
+ if (addToState && event.isState() && timelineSet.room.getUnfilteredTimelineSet() === timelineSet) {
428
433
  roomState.setStateEvents([event], {});
429
434
  // it is possible that the act of setting the state event means we
430
435
  // can set more metadata (specifically sender/target props), so try
@@ -965,7 +965,9 @@ export class MatrixEvent extends TypedEventEmitter<MatrixEventEmittedEvents, Mat
965
965
  const timeline = room.getLiveTimeline();
966
966
  // We use insertEventIntoTimeline to insert it in timestamp order,
967
967
  // because we don't know where it should go (until we have MSC4033).
968
- timeline.getTimelineSet().insertEventIntoTimeline(this, timeline, timeline.getState(EventTimeline.FORWARDS)!);
968
+ timeline
969
+ .getTimelineSet()
970
+ .insertEventIntoTimeline(this, timeline, timeline.getState(EventTimeline.FORWARDS)!, false);
969
971
  }
970
972
 
971
973
  /**
@@ -194,22 +194,11 @@ export class RoomState extends TypedEventEmitter<EmittedEvents, EventHandlerMap>
194
194
  * As the timeline might get reset while they are loading, this state needs to be inherited
195
195
  * and shared when the room state is cloned for the new timeline.
196
196
  * This should only be passed from clone.
197
- * @param isStartTimelineState - Optional. This state is marked as a start state.
198
- * This is used to skip state insertions that are
199
- * in the wrong order. The order is determined by the `replaces_state` id.
200
- *
201
- * Example:
202
- * A current state events `replaces_state` value is `1`.
203
- * Trying to insert a state event with `event_id` `1` in its place would fail if isStartTimelineState = false.
204
- *
205
- * A current state events `event_id` is `2`.
206
- * Trying to insert a state event where its `replaces_state` value is `2` would fail if isStartTimelineState = true.
207
197
  */
208
198
 
209
199
  public constructor(
210
200
  public readonly roomId: string,
211
201
  private oobMemberFlags = { status: OobStatus.NotStarted },
212
- public readonly isStartTimelineState = false,
213
202
  ) {
214
203
  super();
215
204
  this.updateModifiedTime();
@@ -420,7 +409,7 @@ export class RoomState extends TypedEventEmitter<EmittedEvents, EventHandlerMap>
420
409
  * Fires {@link RoomStateEvent.Events}
421
410
  * Fires {@link RoomStateEvent.Marker}
422
411
  */
423
- public setStateEvents(stateEvents: MatrixEvent[], options?: IMarkerFoundOptions): void {
412
+ public setStateEvents(stateEvents: MatrixEvent[], markerFoundOptions?: IMarkerFoundOptions): void {
424
413
  this.updateModifiedTime();
425
414
 
426
415
  // update the core event dict
@@ -432,22 +421,6 @@ export class RoomState extends TypedEventEmitter<EmittedEvents, EventHandlerMap>
432
421
  }
433
422
 
434
423
  const lastStateEvent = this.getStateEventMatching(event);
435
-
436
- // Safety measure to not update the room (and emit the update) with older state.
437
- // The sync loop really should not send old events but it does very regularly.
438
- // Logging on return in those two conditions results in a large amount of logging. (on startup and when running element)
439
- const lastReplaceId = lastStateEvent?.event.unsigned?.replaces_state;
440
- const lastId = lastStateEvent?.event.event_id;
441
- const newReplaceId = event.event.unsigned?.replaces_state;
442
- const newId = event.event.event_id;
443
- if (this.isStartTimelineState) {
444
- // Add an event to the start of the timeline. Its replace id should not be the same as the one of the current/last start state event.
445
- if (newReplaceId && lastId && newReplaceId === lastId) return;
446
- } else {
447
- // Add an event to the end of the timeline. It should not be the same as the one replaced by the current/last end state event.
448
- if (lastReplaceId && newId && lastReplaceId === newId) return;
449
- }
450
-
451
424
  this.setStateEvent(event);
452
425
  if (event.getType() === EventType.RoomMember) {
453
426
  this.updateDisplayNameCache(event.getStateKey()!, event.getContent().displayname ?? "");
@@ -504,7 +477,7 @@ export class RoomState extends TypedEventEmitter<EmittedEvents, EventHandlerMap>
504
477
  // assume all our sentinels are now out-of-date
505
478
  this.sentinels = {};
506
479
  } else if (UNSTABLE_MSC2716_MARKER.matches(event.getType())) {
507
- this.emit(RoomStateEvent.Marker, event, options);
480
+ this.emit(RoomStateEvent.Marker, event, markerFoundOptions);
508
481
  }
509
482
  });
510
483
 
@@ -1692,10 +1692,11 @@ export class Room extends ReadReceipt<RoomEmittedEvents, RoomEventHandlerMap> {
1692
1692
  public addEventsToTimeline(
1693
1693
  events: MatrixEvent[],
1694
1694
  toStartOfTimeline: boolean,
1695
+ addToState: boolean,
1695
1696
  timeline: EventTimeline,
1696
1697
  paginationToken?: string,
1697
1698
  ): void {
1698
- timeline.getTimelineSet().addEventsToTimeline(events, toStartOfTimeline, timeline, paginationToken);
1699
+ timeline.getTimelineSet().addEventsToTimeline(events, toStartOfTimeline, addToState, timeline, paginationToken);
1699
1700
  }
1700
1701
 
1701
1702
  /**
@@ -1860,7 +1861,7 @@ export class Room extends ReadReceipt<RoomEmittedEvents, RoomEventHandlerMap> {
1860
1861
  // see https://github.com/vector-im/vector-web/issues/2109
1861
1862
 
1862
1863
  unfilteredLiveTimeline.getEvents().forEach(function (event) {
1863
- timelineSet.addLiveEvent(event);
1864
+ timelineSet.addLiveEvent(event, { addToState: false }); // Filtered timeline sets should not track state
1864
1865
  });
1865
1866
 
1866
1867
  // find the earliest unfiltered timeline
@@ -1947,6 +1948,7 @@ export class Room extends ReadReceipt<RoomEmittedEvents, RoomEventHandlerMap> {
1947
1948
  if (filterType !== ThreadFilterType.My || currentUserParticipated) {
1948
1949
  timelineSet.getLiveTimeline().addEvent(thread.rootEvent!, {
1949
1950
  toStartOfTimeline: false,
1951
+ addToState: false,
1950
1952
  });
1951
1953
  }
1952
1954
  });
@@ -2020,6 +2022,7 @@ export class Room extends ReadReceipt<RoomEmittedEvents, RoomEventHandlerMap> {
2020
2022
  const opts = {
2021
2023
  duplicateStrategy: DuplicateStrategy.Ignore,
2022
2024
  fromCache: false,
2025
+ addToState: false,
2023
2026
  roomState,
2024
2027
  };
2025
2028
  this.threadsTimelineSets[0]?.addLiveEvent(rootEvent, opts);
@@ -2128,6 +2131,7 @@ export class Room extends ReadReceipt<RoomEmittedEvents, RoomEventHandlerMap> {
2128
2131
  duplicateStrategy: DuplicateStrategy.Replace,
2129
2132
  fromCache: false,
2130
2133
  roomState,
2134
+ addToState: false,
2131
2135
  });
2132
2136
  }
2133
2137
  }
@@ -2319,9 +2323,13 @@ export class Room extends ReadReceipt<RoomEmittedEvents, RoomEventHandlerMap> {
2319
2323
  duplicateStrategy: DuplicateStrategy.Replace,
2320
2324
  fromCache: false,
2321
2325
  roomState: this.currentState,
2326
+ addToState: false,
2322
2327
  });
2323
2328
  } else {
2324
- timelineSet.addEventToTimeline(thread.rootEvent, timelineSet.getLiveTimeline(), { toStartOfTimeline });
2329
+ timelineSet.addEventToTimeline(thread.rootEvent, timelineSet.getLiveTimeline(), {
2330
+ toStartOfTimeline,
2331
+ addToState: false,
2332
+ });
2325
2333
  }
2326
2334
  }
2327
2335
  };
@@ -2478,7 +2486,7 @@ export class Room extends ReadReceipt<RoomEmittedEvents, RoomEventHandlerMap> {
2478
2486
  * Fires {@link RoomEvent.Timeline}
2479
2487
  */
2480
2488
  private addLiveEvent(event: MatrixEvent, addLiveEventOptions: IAddLiveEventOptions): void {
2481
- const { duplicateStrategy, timelineWasEmpty, fromCache } = addLiveEventOptions;
2489
+ const { duplicateStrategy, timelineWasEmpty, fromCache, addToState } = addLiveEventOptions;
2482
2490
 
2483
2491
  // add to our timeline sets
2484
2492
  for (const timelineSet of this.timelineSets) {
@@ -2486,6 +2494,7 @@ export class Room extends ReadReceipt<RoomEmittedEvents, RoomEventHandlerMap> {
2486
2494
  duplicateStrategy,
2487
2495
  fromCache,
2488
2496
  timelineWasEmpty,
2497
+ addToState,
2489
2498
  });
2490
2499
  }
2491
2500
 
@@ -2569,11 +2578,13 @@ export class Room extends ReadReceipt<RoomEmittedEvents, RoomEventHandlerMap> {
2569
2578
  if (timelineSet.getFilter()!.filterRoomTimeline([event]).length) {
2570
2579
  timelineSet.addEventToTimeline(event, timelineSet.getLiveTimeline(), {
2571
2580
  toStartOfTimeline: false,
2581
+ addToState: false, // We don't support localEcho of state events yet
2572
2582
  });
2573
2583
  }
2574
2584
  } else {
2575
2585
  timelineSet.addEventToTimeline(event, timelineSet.getLiveTimeline(), {
2576
2586
  toStartOfTimeline: false,
2587
+ addToState: false, // We don't support localEcho of state events yet
2577
2588
  });
2578
2589
  }
2579
2590
  }
@@ -2824,8 +2835,8 @@ export class Room extends ReadReceipt<RoomEmittedEvents, RoomEventHandlerMap> {
2824
2835
  * @param addLiveEventOptions - addLiveEvent options
2825
2836
  * @throws If `duplicateStrategy` is not falsey, 'replace' or 'ignore'.
2826
2837
  */
2827
- public async addLiveEvents(events: MatrixEvent[], addLiveEventOptions?: IAddLiveEventOptions): Promise<void> {
2828
- const { duplicateStrategy, fromCache, timelineWasEmpty = false } = addLiveEventOptions ?? {};
2838
+ public async addLiveEvents(events: MatrixEvent[], addLiveEventOptions: IAddLiveEventOptions): Promise<void> {
2839
+ const { duplicateStrategy, fromCache, timelineWasEmpty = false, addToState } = addLiveEventOptions;
2829
2840
  if (duplicateStrategy && ["replace", "ignore"].indexOf(duplicateStrategy) === -1) {
2830
2841
  throw new Error("duplicateStrategy MUST be either 'replace' or 'ignore'");
2831
2842
  }
@@ -2840,6 +2851,7 @@ export class Room extends ReadReceipt<RoomEmittedEvents, RoomEventHandlerMap> {
2840
2851
  duplicateStrategy,
2841
2852
  fromCache,
2842
2853
  timelineWasEmpty,
2854
+ addToState,
2843
2855
  };
2844
2856
 
2845
2857
  // List of extra events to check for being parents of any relations encountered
@@ -208,6 +208,7 @@ export class Thread extends ReadReceipt<ThreadEmittedEvents, ThreadEventHandlerM
208
208
 
209
209
  public static setServerSideSupport(status: FeatureSupport): void {
210
210
  Thread.hasServerSideSupport = status;
211
+ // XXX: This global latching behaviour is really unexpected and means that you can't undo when moving to a server without support
211
212
  if (status !== FeatureSupport.Stable) {
212
213
  FILTER_RELATED_BY_SENDERS.setPreferUnstable(true);
213
214
  FILTER_RELATED_BY_REL_TYPES.setPreferUnstable(true);
@@ -317,6 +318,7 @@ export class Thread extends ReadReceipt<ThreadEmittedEvents, ThreadEventHandlerM
317
318
  toStartOfTimeline,
318
319
  fromCache: false,
319
320
  roomState: this.roomState,
321
+ addToState: false,
320
322
  });
321
323
  }
322
324
  }
@@ -343,7 +345,7 @@ export class Thread extends ReadReceipt<ThreadEmittedEvents, ThreadEventHandlerM
343
345
  if (this.findEventById(eventId)) {
344
346
  return;
345
347
  }
346
- this.timelineSet.insertEventIntoTimeline(event, this.liveTimeline, this.roomState);
348
+ this.timelineSet.insertEventIntoTimeline(event, this.liveTimeline, this.roomState, false);
347
349
  }
348
350
 
349
351
  public addEvents(events: MatrixEvent[], toStartOfTimeline: boolean): void {
@@ -617,7 +619,7 @@ export class Thread extends ReadReceipt<ThreadEmittedEvents, ThreadEventHandlerM
617
619
  // if the thread has regular events, this will just load the last reply.
618
620
  // if the thread is newly created, this will load the root event.
619
621
  if (this.replyCount === 0 && this.rootEvent) {
620
- this.timelineSet.addEventsToTimeline([this.rootEvent], true, this.liveTimeline, null);
622
+ this.timelineSet.addEventsToTimeline([this.rootEvent], true, false, this.liveTimeline, null);
621
623
  this.liveTimeline.setPaginationToken(null, Direction.Backward);
622
624
  } else {
623
625
  this.initalEventFetchProm = this.client.paginateEventTimeline(this.liveTimeline, {
@@ -550,7 +550,7 @@ export class SlidingSyncSdk {
550
550
  timelineEvents = newEvents;
551
551
  if (oldEvents.length > 0) {
552
552
  // old events are scrollback, insert them now
553
- room.addEventsToTimeline(oldEvents, true, room.getLiveTimeline(), roomData.prev_batch);
553
+ room.addEventsToTimeline(oldEvents, true, false, room.getLiveTimeline(), roomData.prev_batch);
554
554
  }
555
555
  }
556
556
 
@@ -684,7 +684,7 @@ export class SlidingSyncSdk {
684
684
  /**
685
685
  * Injects events into a room's model.
686
686
  * @param stateEventList - A list of state events. This is the state
687
- * at the *START* of the timeline list if it is supplied.
687
+ * at the *END* of the timeline list if it is supplied.
688
688
  * @param timelineEventList - A list of timeline events. Lower index
689
689
  * is earlier in time. Higher index is later.
690
690
  * @param numLive - the number of events in timelineEventList which just happened,
@@ -693,13 +693,9 @@ export class SlidingSyncSdk {
693
693
  public async injectRoomEvents(
694
694
  room: Room,
695
695
  stateEventList: MatrixEvent[],
696
- timelineEventList?: MatrixEvent[],
697
- numLive?: number,
696
+ timelineEventList: MatrixEvent[] = [],
697
+ numLive: number = 0,
698
698
  ): Promise<void> {
699
- timelineEventList = timelineEventList || [];
700
- stateEventList = stateEventList || [];
701
- numLive = numLive || 0;
702
-
703
699
  // If there are no events in the timeline yet, initialise it with
704
700
  // the given state events
705
701
  const liveTimeline = room.getLiveTimeline();
@@ -750,16 +746,17 @@ export class SlidingSyncSdk {
750
746
  timelineEventList = timelineEventList.slice(0, -1 * liveTimelineEvents.length);
751
747
  }
752
748
 
753
- // execute the timeline events. This will continue to diverge the current state
754
- // if the timeline has any state events in it.
749
+ // Execute the timeline events.
755
750
  // This also needs to be done before running push rules on the events as they need
756
751
  // to be decorated with sender etc.
757
752
  await room.addLiveEvents(timelineEventList, {
758
753
  fromCache: true,
754
+ addToState: false,
759
755
  });
760
756
  if (liveTimelineEvents.length > 0) {
761
757
  await room.addLiveEvents(liveTimelineEvents, {
762
758
  fromCache: false,
759
+ addToState: false,
763
760
  });
764
761
  }
765
762
 
@@ -896,7 +893,7 @@ export class SlidingSyncSdk {
896
893
  return a.getTs() - b.getTs();
897
894
  });
898
895
  this.notifEvents.forEach((event) => {
899
- this.client.getNotifTimelineSet()?.addLiveEvent(event);
896
+ this.client.getNotifTimelineSet()?.addLiveEvent(event, { addToState: false });
900
897
  });
901
898
  this.notifEvents = [];
902
899
  }