diff --git a/src/MatrixClient.ts b/src/MatrixClient.ts index 70c577ba..2621ce48 100644 --- a/src/MatrixClient.ts +++ b/src/MatrixClient.ts @@ -43,6 +43,7 @@ import { RustSdkCryptoStorageProvider } from "./storage/RustSdkCryptoStorageProv import { DMs } from "./DMs"; import { ServerVersions } from "./models/ServerVersions"; import { RoomCreateOptions } from "./models/CreateRoom"; +import { RoomMessagesResponse } from "./models/RoomMessagesResponse"; const SYNC_BACKOFF_MIN_MS = 5000; const SYNC_BACKOFF_MAX_MS = 15000; @@ -897,6 +898,34 @@ export class MatrixClient extends EventEmitter { } } + /** + * This returns a list of message and state events for a room. + * + * It uses pagination query parameters to paginate history in the room. + * + * @param roomId the room ID to get the event in + * @param dir The direction to return events from. + * If this is set to `f`, events will be returned in chronological order starting at `from`. + * If it is set to `b`, events will be returned in reverse chronolgical order, again starting at `from`. + * @param from The token to start returning events from. + * This token can be obtained from a prev_batch or next_batch token returned by the /sync endpoint, + * or from an end token returned by a previous call to this function. + * @param filter A JSON RoomEventFilter to filter returned events with. + * @param limit The maximum number of events to return. Default: 10. + * @param to The token to stop returning events at. + * This token can be obtained from a `prev_batch` or `next_batch` token returned by the /sync endpoint, + * or from an end token returned by a previous call to this function. + */ + public async getRoomMessages(roomId: string, dir: 'f'|'b', from: string, opts: { + filter?: string; + limit?: number; + to?: string; + }): Promise { + return this.doRequest("GET", `/_matrix/client/v3/rooms/${encodeURIComponent(roomId)}/messages`, { + dir, from, ...opts, + }); + } + /** * Gets an event for a room. If the event is encrypted, and the client supports encryption, * and the room is encrypted, then this will return a decrypted event. diff --git a/src/models/RoomMessagesResponse.ts b/src/models/RoomMessagesResponse.ts new file mode 100644 index 00000000..10ecd3b2 --- /dev/null +++ b/src/models/RoomMessagesResponse.ts @@ -0,0 +1,12 @@ +import { RoomEventData, RoomStateEventData } from "./events/RoomEvent"; + +/** + * The options available when creating a room. + * @category Models + */ +export interface RoomMessagesResponse { + start: string; + chunk: RoomEventData[]; + end?: string; + state: RoomStateEventData[]; +} diff --git a/src/models/events/RoomEvent.ts b/src/models/events/RoomEvent.ts index 3ccb65fe..4d87508d 100644 --- a/src/models/events/RoomEvent.ts +++ b/src/models/events/RoomEvent.ts @@ -17,6 +17,48 @@ export interface TypicalUnsigned { [prop: string]: any; } +export interface RoomEventData { + /** + * The fields in this object will vary depending on the type of event. + */ + content: T; + /** + * The globally unique event identifier. + */ + event_id: string; + /** + * Timestamp in milliseconds on originating homeserver when this event was sent. + */ + origin_server_ts: number; + /** + * The ID of the room associated with this event. Will not be present on events that arrive through /sync, despite being required everywhere else. + */ + room_id: string; + /** + * Contains the fully-qualified ID of the user who sent this event. + */ + sender: string; + /** + * The type of event. This SHOULD be namespaced similar to Java package naming conventions e.g. `com.example.subdomain.event.type` + */ + type: string; + /** + * Contains optional extra information about the event. + */ + unsinged: TypicalUnsigned; +} + +export interface RoomStateEventData extends RoomEventData { + /** + * A unique key which defines the overwriting semantics for this piece of room state. + */ + state_key: string; + /** + * The previous content for this event. If there is no previous content, this key will be missing. + */ + prev_content?: P; +} + /** * Empty room event content. * @category Matrix event contents diff --git a/test/MatrixClientTest.ts b/test/MatrixClientTest.ts index fd07051c..d179fa4b 100644 --- a/test/MatrixClientTest.ts +++ b/test/MatrixClientTest.ts @@ -2268,6 +2268,48 @@ describe('MatrixClient', () => { }); }); + describe('getRoomMessages', () => { + it('should call the right endpoint', async () => { + const { client, http, hsUrl } = createTestClient(); + + const roomId = "!abc123:example.org"; + + const opts = { + filter: 'foo-bar', + limit: 5, + to: 'my-to-token', + }; + + const from = 'my-from-token'; + const dir = 'f'; + + const response = { + chunk: [ + { a_chunk: "foo" }, + ], + start: 'new-from', + end: 'new-to', + state: [ + { state_chunk: 'bar', state_key: '' }, + ], + }; + + // noinspection TypeScriptValidateJSTypes + http.when("GET", `/_matrix/client/v3/rooms/${encodeURIComponent(roomId)}/messages`).respond(200, (path, _data, req) => { + expect(path).toEqual(`${hsUrl}/_matrix/client/v3/rooms/${encodeURIComponent(roomId)}/messages`); + expect(req.queryParams['dir']).toEqual(dir); + expect(req.queryParams['from']).toEqual(from); + expect(req.queryParams['filter']).toEqual(opts.filter); + expect(req.queryParams['limit']).toEqual(opts.limit); + expect(req.queryParams['to']).toEqual(opts.to); + return response; + }); + + const [result] = await Promise.all([client.getRoomMessages(roomId, dir, from, opts), http.flushAllExpected()]); + expect(result).toMatchObject(response); + }); + }); + describe('getEvent', () => { it('should call the right endpoint', async () => { const { client, http, hsUrl } = createTestClient();